blob: ac7b7be37a96b75d7adbbe35506918a58222ca45 [file] [log] [blame]
// 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_