| // Copyright 2017 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef CONTENT_BROWSER_INDEXED_DB_INSTANCE_LEVELDB_TOMBSTONE_SWEEPER_H_ | 
 | #define CONTENT_BROWSER_INDEXED_DB_INSTANCE_LEVELDB_TOMBSTONE_SWEEPER_H_ | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <vector> | 
 |  | 
 | #include "base/feature_list.h" | 
 | #include "base/functional/callback.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 
 | #include "content/browser/indexed_db/instance/backing_store_pre_close_task_queue.h" | 
 | #include "content/browser/indexed_db/status.h" | 
 | #include "content/common/content_export.h" | 
 | #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" | 
 |  | 
 | namespace blink { | 
 | struct IndexedDBDatabaseMetadata; | 
 | struct IndexedDBIndexMetadata; | 
 | struct IndexedDBObjectStoreMetadata; | 
 | }  // namespace blink | 
 |  | 
 | namespace leveldb { | 
 | class DB; | 
 | class Iterator; | 
 | }  // namespace leveldb | 
 |  | 
 | namespace content::indexed_db { | 
 | class BackingStore; | 
 |  | 
 | namespace level_db { | 
 |  | 
 | // Facilitates iterating a whole container with an abnormal starting position. | 
 | // If the starting position is not 0, then the iteration will wrap to the | 
 | // beginning of the container until the starting position is reached again. | 
 | template <typename T> | 
 | class WrappingIterator { | 
 |  public: | 
 |   WrappingIterator(); | 
 |   WrappingIterator(const T* container, size_t start_position); | 
 |   ~WrappingIterator(); | 
 |   WrappingIterator& operator=(const WrappingIterator& other) = default; | 
 |  | 
 |   void Next(); | 
 |   bool IsValid() const { return valid_; } | 
 |   const typename T::value_type& Value() const; | 
 |  | 
 |  private: | 
 |   bool valid_ = false; | 
 |   size_t iterations_done_ = 0; | 
 |   typename T::const_iterator inner_; | 
 |   raw_ptr<const T> container_ = nullptr; | 
 | }; | 
 |  | 
 | // Sweeps the IndexedDB leveldb database looking for index tombstones. These | 
 | // occur when the indexed fields of rows are modified, and stay around if script | 
 | // doesn't do a cursor iteration of the database. | 
 | // | 
 | // Owned by the BackingStore. | 
 | // | 
 | // TODO(dmurph) Describe this class in a README.md file. | 
 | // See bit.ly/idb-tombstone-sweeper for more information. | 
 | class CONTENT_EXPORT LevelDbTombstoneSweeper | 
 |     : public BackingStorePreCloseTaskQueue::PreCloseTask { | 
 |  public: | 
 |   using MetadataVector = | 
 |       std::vector<std::unique_ptr<blink::IndexedDBDatabaseMetadata>>; | 
 |  | 
 |   // The |database| must outlive this instance. | 
 |   explicit LevelDbTombstoneSweeper(leveldb::DB* database); | 
 |  | 
 |   LevelDbTombstoneSweeper(int round_iterations, | 
 |                           int max_iterations, | 
 |                           leveldb::DB* database); | 
 |  | 
 |   LevelDbTombstoneSweeper(const LevelDbTombstoneSweeper&) = delete; | 
 |   LevelDbTombstoneSweeper& operator=(const LevelDbTombstoneSweeper&) = delete; | 
 |  | 
 |   ~LevelDbTombstoneSweeper() override; | 
 |  | 
 |   bool RequiresMetadata() const override; | 
 |  | 
 |   void SetMetadata(const MetadataVector* metadata) override; | 
 |  | 
 |   bool RunRound() override; | 
 |  | 
 |  private: | 
 |   using ObjectStoreMetadataMap = | 
 |       std::map<int64_t, blink::IndexedDBObjectStoreMetadata>; | 
 |   using IndexMetadataMap = std::map<int64_t, blink::IndexedDBIndexMetadata>; | 
 |  | 
 |   friend class LevelDbTombstoneSweeperTest; | 
 |  | 
 |   enum class SweepStatus { SWEEPING, DONE_ERROR, DONE }; | 
 |  | 
 |   // Contains the current sweeping state and position for the sweeper. | 
 |   struct SweepState { | 
 |     SweepState(); | 
 |     ~SweepState(); | 
 |  | 
 |     // Stores the random starting database seed. Not bounded. | 
 |     size_t start_database_seed = 0; | 
 |     std::optional<WrappingIterator<MetadataVector>> database_it; | 
 |  | 
 |     // Stores the random starting object store seed. Not bounded. | 
 |     size_t start_object_store_seed = 0; | 
 |     std::optional<WrappingIterator<ObjectStoreMetadataMap>> object_store_it; | 
 |  | 
 |     // Stores the random starting object store seed. Not bounded. | 
 |     size_t start_index_seed = 0; | 
 |     std::optional<WrappingIterator<IndexMetadataMap>> index_it; | 
 |     std::optional<IndexDataKey> index_it_key; | 
 |   }; | 
 |  | 
 |   void SetStartSeedsForTesting(size_t database_seed, | 
 |                                size_t object_store_seed, | 
 |                                size_t index_seed) { | 
 |     sweep_state_.start_database_seed = database_seed; | 
 |     sweep_state_.start_object_store_seed = object_store_seed; | 
 |     sweep_state_.start_index_seed = index_seed; | 
 |   } | 
 |  | 
 |   Status FlushDeletions(); | 
 |  | 
 |   bool ShouldContinueIteration(const leveldb::Iterator& iterator, | 
 |                                SweepStatus* sweep_status, | 
 |                                Status* leveldb_status, | 
 |                                int* round_iters); | 
 |  | 
 |   SweepStatus DoSweep(Status* status); | 
 |  | 
 |   // Returns true if sweeper can continue iterating. | 
 |   bool IterateIndex(int64_t database_id, | 
 |                     int64_t object_store_id, | 
 |                     const blink::IndexedDBIndexMetadata& index, | 
 |                     SweepStatus* sweep_status, | 
 |                     Status* leveldb_status, | 
 |                     int* round_iterations); | 
 |  | 
 |   int num_iterations_ = 0; | 
 |  | 
 |   // Sum of tombstones across rounds. | 
 |   long tombstones_found_ = 0; | 
 |   const int max_round_iterations_; | 
 |   const int max_iterations_; | 
 |  | 
 |   bool has_writes_ = false; | 
 |   leveldb::WriteBatch round_deletion_batch_; | 
 |  | 
 |   raw_ptr<const std::vector<std::unique_ptr<blink::IndexedDBDatabaseMetadata>>> | 
 |       database_metadata_ = nullptr; | 
 |  | 
 |   SweepState sweep_state_; | 
 |  | 
 |   base::WeakPtrFactory<LevelDbTombstoneSweeper> ptr_factory_{this}; | 
 | }; | 
 |  | 
 | }  // namespace level_db | 
 | }  // namespace content::indexed_db | 
 |  | 
 | #endif  // CONTENT_BROWSER_INDEXED_DB_INSTANCE_LEVELDB_TOMBSTONE_SWEEPER_H_ |