blob: 79a945d9a3d3e6417b154cc6393a20120963169b [file] [log] [blame]
// Copyright 2013 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_BACKING_STORE_H_
#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_LEVELDB_BACKING_STORE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/dcheck_is_on.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/services/storage/indexed_db/locks/partitioned_lock.h"
#include "components/services/storage/privileged/mojom/indexed_db_control_test.mojom.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "content/browser/indexed_db/indexed_db_external_object.h"
#include "content/browser/indexed_db/indexed_db_external_object_storage.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/instance/backing_store.h"
#include "content/browser/indexed_db/instance/backing_store_pre_close_task_queue.h"
#include "content/browser/indexed_db/instance/leveldb/cleanup_scheduler.h"
#include "content/browser/indexed_db/instance/leveldb/indexed_db_leveldb_operations.h"
#include "content/browser/indexed_db/status.h"
#include "content/common/content_export.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
namespace base {
class WaitableEvent;
} // namespace base
namespace blink {
class IndexedDBKeyRange;
struct IndexedDBDatabaseMetadata;
} // namespace blink
namespace content::indexed_db {
class ActiveBlobRegistry;
class BucketContext;
class LevelDBWriteBatch;
class PartitionedLockManager;
class TransactionalLevelDBDatabase;
class TransactionalLevelDBIterator;
class TransactionalLevelDBTransaction;
struct IndexedDBDataLossInfo;
struct IndexedDBValue;
namespace level_db {
class AutoDidCommitTransaction;
class CONTENT_EXPORT BackingStore : public indexed_db::BackingStore,
public LevelDBCleanupScheduler::Delegate {
public:
// This struct contains extra metadata only relevant to this implementation of
// the backing store.
struct CONTENT_EXPORT DatabaseMetadata
: public blink::IndexedDBDatabaseMetadata {
public:
explicit DatabaseMetadata(const std::u16string& name);
DatabaseMetadata(DatabaseMetadata&& metadata);
DatabaseMetadata(const DatabaseMetadata& metadata);
DatabaseMetadata& operator=(const DatabaseMetadata& metadata);
DatabaseMetadata();
~DatabaseMetadata() override;
// Uniquely identifies this database within the backing store. See
// `GetNewDatabaseId()`. Null indicates that this object does not (yet)
// represent a valid database.
std::optional<int64_t> id;
};
class CONTENT_EXPORT Database : public indexed_db::BackingStore::Database {
public:
Database(BackingStore& backing_store,
BackingStore::DatabaseMetadata metadata);
~Database() override;
// indexed_db::BackingStore::Database:
const blink::IndexedDBDatabaseMetadata& GetMetadata() override;
std::string GetObjectStoreLockIdKey(int64_t object_store_id) const override;
std::unique_ptr<Transaction> CreateTransaction(
blink::mojom::IDBTransactionDurability durability,
blink::mojom::IDBTransactionMode mode) override;
Status DeleteDatabase(std::vector<PartitionedLock> locks,
base::OnceClosure on_complete) override;
DatabaseMetadata& metadata() { return metadata_; }
base::WeakPtr<BackingStore> backing_store() { return backing_store_; }
private:
base::WeakPtr<BackingStore> backing_store_;
DatabaseMetadata metadata_;
base::WeakPtrFactory<Database> weak_factory_{this};
};
class Cursor;
// This class could be moved to the implementation file, but it's left here to
// avoid needless git churn.
class CONTENT_EXPORT Transaction
: public indexed_db::BackingStore::Transaction {
public:
struct BlobWriteState {
BlobWriteState();
explicit BlobWriteState(int calls_left, BlobWriteCallback on_complete);
~BlobWriteState();
int calls_left = 0;
BlobWriteCallback on_complete;
};
Transaction(base::WeakPtr<Database> database,
blink::mojom::IDBTransactionDurability durability,
blink::mojom::IDBTransactionMode mode);
Transaction(const Transaction&) = delete;
Transaction& operator=(const Transaction&) = delete;
~Transaction() override;
Status Begin(std::vector<PartitionedLock> locks) override;
// The `serialize_fsa_handle` callback is not used.
Status CommitPhaseOne(BlobWriteCallback callback,
SerializeFsaCallback serialize_fsa_handle) override;
Status CommitPhaseTwo() override;
void Rollback() override;
Status SetDatabaseVersion(int64_t version) override;
Status CreateObjectStore(int64_t object_store_id,
const std::u16string& name,
blink::IndexedDBKeyPath key_path,
bool auto_increment) override;
Status DeleteObjectStore(int64_t object_store_id) override;
Status RenameObjectStore(int64_t object_store_id,
const std::u16string& new_name) override;
// Creates a new index metadata and writes it to the transaction.
Status CreateIndex(int64_t object_store_id,
blink::IndexedDBIndexMetadata index) override;
// Deletes the index metadata on the transaction (but not any index
// entries).
Status DeleteIndex(int64_t object_store_id, int64_t index_id) override;
// Renames the given index and writes it to the transaction.
Status RenameIndex(int64_t object_store_id,
int64_t index_id,
const std::u16string& new_name) override;
StatusOr<IndexedDBValue> GetRecord(int64_t object_store_id,
const blink::IndexedDBKey& key) override;
StatusOr<RecordIdentifier> PutRecord(int64_t object_store_id,
const blink::IndexedDBKey& key,
IndexedDBValue value) override;
Status ClearObjectStore(int64_t object_store_id) override;
Status DeleteRange(int64_t object_store_id,
const blink::IndexedDBKeyRange&) override;
StatusOr<int64_t> GetKeyGeneratorCurrentNumber(
int64_t object_store_id) override;
Status MaybeUpdateKeyGeneratorCurrentNumber(int64_t object_store_id,
int64_t new_number,
bool was_generated) override;
StatusOr<std::optional<RecordIdentifier>> KeyExistsInObjectStore(
int64_t object_store_id,
const blink::IndexedDBKey& key) override;
Status PutIndexDataForRecord(int64_t object_store_id,
int64_t index_id,
const blink::IndexedDBKey& key,
const RecordIdentifier& record) override;
StatusOr<blink::IndexedDBKey> GetFirstPrimaryKeyForIndexKey(
int64_t object_store_id,
int64_t index_id,
const blink::IndexedDBKey& key) override;
StatusOr<uint32_t> GetObjectStoreKeyCount(
int64_t object_store_id,
blink::IndexedDBKeyRange key_range) override;
StatusOr<uint32_t> GetIndexKeyCount(
int64_t object_store_id,
int64_t index_id,
blink::IndexedDBKeyRange key_range) override;
StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>>
OpenObjectStoreKeyCursor(int64_t object_store_id,
const blink::IndexedDBKeyRange& key_range,
blink::mojom::IDBCursorDirection) override;
StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>>
OpenObjectStoreCursor(int64_t object_store_id,
const blink::IndexedDBKeyRange& key_range,
blink::mojom::IDBCursorDirection) override;
StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>>
OpenIndexKeyCursor(int64_t object_store_id,
int64_t index_id,
const blink::IndexedDBKeyRange& key_range,
blink::mojom::IDBCursorDirection) override;
StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>> OpenIndexCursor(
int64_t object_store_id,
int64_t index_id,
const blink::IndexedDBKeyRange& key_range,
blink::mojom::IDBCursorDirection) override;
// `deserialize_fsa_handle` is not used in this implementation.
blink::mojom::IDBValuePtr BuildMojoValue(
IndexedDBValue value,
DeserializeFsaCallback deserialize_fsa_handle) override;
Status PutExternalObjectsIfNeeded(const std::string& object_store_data_key,
std::vector<IndexedDBExternalObject>*);
void PutExternalObjects(const std::string& object_store_data_key,
std::vector<IndexedDBExternalObject>*);
TransactionalLevelDBTransaction* transaction() {
return transaction_.get();
}
void SetTombstoneThresholdExceeded(bool tombstone_threshold_exceeded) {
tombstone_threshold_exceeded_ = tombstone_threshold_exceeded;
}
Status GetExternalObjectsForRecord(const std::string& object_store_data_key,
IndexedDBValue* value);
base::WeakPtr<Transaction> AsWeakPtr();
blink::mojom::IDBTransactionDurability durability() const {
return durability_;
}
blink::mojom::IDBTransactionMode mode() const { return mode_; }
private:
int64_t database_id() const { return *database_->metadata().id; }
Status FindKeyInIndex(int64_t object_store_id,
int64_t index_id,
const blink::IndexedDBKey& key,
std::string* found_encoded_primary_key,
bool* found);
// Called by CommitPhaseOne: Identifies the blob entries to write and adds
// them to the recovery blob journal directly (i.e. not as part of the
// transaction). Populates blobs_to_write_.
Status HandleBlobPreTransaction();
// Called by CommitPhaseOne: Populates blob_files_to_remove_ by
// determining which blobs are deleted as part of the transaction, and
// adds blob entry cleanup operations to the transaction. Returns true on
// success, false on failure.
bool CollectBlobFilesToRemove();
// Called by CommitPhaseOne: Kicks off the asynchronous writes of blobs
// identified in HandleBlobPreTransaction. The callback will be called
// eventually on success or failure.
Status WriteNewBlobs(BlobWriteCallback callback);
// Called by CommitPhaseTwo: Partition blob references in blobs_to_remove_
// into live (active references) and dead (no references).
void PartitionBlobsToRemove(BlobJournalType* dead_blobs,
BlobJournalType* live_blobs) const;
// Prepares a cursor and returns it if successful, an error Status if
// there's an error, or null if the cursor is empty.
StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>> PrepareCursor(
std::unique_ptr<Cursor> cursor);
// This does NOT mean that this class can outlive the BackingStore.
// This is only to protect against security issues before this class is
// refactored away and this isn't necessary.
// https://crbug.com/1012918
base::WeakPtr<BackingStore> backing_store_;
base::WeakPtr<Database> database_;
scoped_refptr<TransactionalLevelDBTransaction> transaction_;
std::map<std::string, std::unique_ptr<IndexedDBExternalObjectChangeRecord>>
external_object_change_map_;
std::map<std::string, std::unique_ptr<IndexedDBExternalObjectChangeRecord>>
in_memory_external_object_map_;
// List of blob files being newly written as part of this transaction.
// These will be added to the recovery blob journal prior to commit, then
// removed after a successful commit.
BlobJournalType blobs_to_write_;
// List of blob files being deleted as part of this transaction. These will
// be added to either the recovery or live blob journal as appropriate
// following a successful commit.
BlobJournalType blobs_to_remove_;
// Populated when blobs are being written to disk. This is saved here (as
// opposed to being ephemeral and owned by the WriteBlobToFile callbacks)
// because the transaction needs to be able to cancel this operation in
// Rollback().
std::optional<BlobWriteState> write_state_;
// Set to true between CommitPhaseOne and CommitPhaseTwo/Rollback, to
// indicate that the committing_transaction_count_ on the backing store
// has been bumped, and journal cleaning should be deferred.
bool committing_ = false;
// This flag is passed to LevelDBScopes as `sync_on_commit`, converted
// via ShouldSyncOnCommit.
const blink::mojom::IDBTransactionDurability durability_;
const blink::mojom::IDBTransactionMode mode_;
// This flag is set when tombstones encountered during a read-only
// cursor operation exceed `kCursorTombstoneThreshold`.
bool tombstone_threshold_exceeded_ = false;
std::optional<DatabaseMetadata> metadata_before_transaction_;
base::WeakPtrFactory<Transaction> weak_ptr_factory_{this};
};
// This class could be moved to the implementation file, but it's left here to
// avoid needless git churn.
class Cursor : public indexed_db::BackingStore::Cursor {
public:
enum IteratorState { READY = 0, SEEK };
struct CursorOptions {
CursorOptions();
CursorOptions(const CursorOptions& other);
~CursorOptions();
int64_t database_id;
int64_t object_store_id;
int64_t index_id;
std::string low_key;
bool low_open;
std::string high_key;
bool high_open;
bool forward;
bool unique;
blink::mojom::IDBTransactionMode mode =
blink::mojom::IDBTransactionMode::ReadWrite;
};
Cursor(const Cursor&) = delete;
Cursor& operator=(const Cursor&) = delete;
~Cursor() override;
// indexed_db::BackingStore::Cursor:
const blink::IndexedDBKey& GetKey() const override;
const blink::IndexedDBKey& GetPrimaryKey() const override;
blink::IndexedDBKey TakeKey() && override;
StatusOr<bool> Continue() override;
StatusOr<bool> Continue(const blink::IndexedDBKey& key,
const blink::IndexedDBKey& primary_key) override;
StatusOr<bool> Advance(uint32_t count) override;
void SavePosition() override;
bool TryResetToLastSavedPosition() override;
StatusOr<bool> Continue(const blink::IndexedDBKey& key,
const blink::IndexedDBKey& primary_key,
IteratorState state);
StatusOr<bool> FirstSeek();
protected:
Cursor(base::WeakPtr<Transaction> transaction,
int64_t database_id,
const CursorOptions& cursor_options);
// May return nullptr.
static std::unique_ptr<TransactionalLevelDBIterator> CloneIterator(
const Cursor* other);
virtual bool LoadCurrentRow(Status* s) = 0;
virtual std::string EncodeKey(const blink::IndexedDBKey& key) = 0;
virtual std::string EncodeKey(const blink::IndexedDBKey& key,
const blink::IndexedDBKey& primary_key) = 0;
bool IsPastBounds() const;
bool HaveEnteredRange() const;
// If the version numbers don't match or if the value is missing, that
// means this is an obsolete index entry (a 'tombstone') that can be
// cleaned up. This removal can only happen in non-read-only transactions.
void RemoveTombstoneOrIncrementCount(Status* s);
// This does NOT mean that this class can outlive the Transaction.
// This is only to protect against security issues before this class is
// refactored away and this isn't necessary.
// https://crbug.com/1012918
const base::WeakPtr<Transaction> transaction_;
const int64_t database_id_;
const CursorOptions cursor_options_;
std::unique_ptr<TransactionalLevelDBIterator> iterator_;
blink::IndexedDBKey current_key_;
private:
enum class ContinueResult { DONE, OUT_OF_BOUNDS };
// For cursors with direction Next or NextNoDuplicate.
StatusOr<ContinueResult> ContinueNext(
const blink::IndexedDBKey& key,
const blink::IndexedDBKey& primary_key,
IteratorState state);
// For cursors with direction Prev or PrevNoDuplicate. The PrevNoDuplicate
// case has additional complexity of not being symmetric with
// NextNoDuplicate.
StatusOr<ContinueResult> ContinuePrevious(
const blink::IndexedDBKey& key,
const blink::IndexedDBKey& primary_key,
IteratorState state);
int tombstones_count_ = 0;
// `iterator_` and `current_key_` are saved when `SavePosition()` is called.
std::optional<std::tuple<std::unique_ptr<TransactionalLevelDBIterator>,
blink::IndexedDBKey>>
saved_members_;
base::WeakPtrFactory<Cursor> weak_factory_{this};
};
using BlobFilesCleanedCallback = base::RepeatingClosure;
using ReportOutstandingBlobsCallback =
base::RepeatingCallback<void(/*outstanding_blobs=*/bool)>;
enum class Mode { kInMemory, kOnDisk };
// Schedule an immediate blob journal cleanup if we reach this number of
// requests.
static constexpr const int kMaxJournalCleanRequests = 50;
// Wait for a maximum of 5 seconds from the first call to the timer since the
// last journal cleaning.
static constexpr const base::TimeDelta kMaxJournalCleaningWindowTime =
base::Seconds(5);
// Default to a 2 second timer delay before we clean up blobs.
static constexpr const base::TimeDelta kInitialJournalCleaningWindowTime =
base::Seconds(2);
BackingStore(Mode backing_store_mode,
const storage::BucketLocator& bucket_locator,
const base::FilePath& blob_path,
std::unique_ptr<TransactionalLevelDBDatabase> db,
BlobFilesCleanedCallback blob_files_cleaned,
ReportOutstandingBlobsCallback report_outstanding_blobs);
BackingStore(const BackingStore&) = delete;
BackingStore& operator=(const BackingStore&) = delete;
~BackingStore() override;
// Initializes the backing store. This must be called before doing any
// operations or method calls on this object.
Status Initialize(bool clean_active_blob_journal);
const storage::BucketLocator& bucket_locator() const {
return bucket_locator_;
}
ActiveBlobRegistry* active_blob_registry() {
return active_blob_registry_.get();
}
void OnTransactionComplete(bool tombstone_threshold_exceeded);
static void HandleCorruption(const base::FilePath& path_base,
const storage::BucketLocator& bucket_locator,
const std::string& message);
// BackingStore:
bool CanOpportunisticallyClose() const override;
void TearDown(base::WaitableEvent* signal_on_destruction) override;
void InvalidateBlobReferences() override;
void StartPreCloseTasks(base::OnceClosure on_done) override;
void StopPreCloseTasks() override;
StatusOr<std::unique_ptr<indexed_db::BackingStore::Database>>
CreateOrOpenDatabase(const std::u16string& name) override;
uintptr_t GetIdentifierForMemoryDump() override;
void FlushForTesting() override;
StatusOr<bool> DatabaseExists(std::u16string_view database_name) override;
StatusOr<std::vector<blink::mojom::IDBNameAndVersionPtr>>
GetDatabaseNamesAndVersions() override;
base::FilePath GetBlobFileName(int64_t database_id, int64_t key) const;
TransactionalLevelDBDatabase* db() { return db_.get(); }
const std::string& origin_identifier() { return origin_identifier_; }
int64_t GetInMemorySize() const override;
#if DCHECK_IS_ON()
int NumBlobFilesDeletedForTesting() { return num_blob_files_deleted_; }
#endif
int NumAggregatedJournalCleaningRequestsForTesting() const {
return num_aggregated_journal_cleaning_requests_;
}
void SetNumAggregatedJournalCleaningRequestsForTesting(int num_requests) {
num_aggregated_journal_cleaning_requests_ = num_requests;
}
void SetExecuteJournalCleaningOnNoTransactionsForTesting() {
execute_journal_cleaning_on_no_txns_ = true;
}
const LevelDBCleanupScheduler& GetLevelDBCleanupSchedulerForTesting() const {
return level_db_cleanup_scheduler_;
}
bool in_memory() const { return backing_store_mode_ == Mode::kInMemory; }
base::WeakPtr<BackingStore> AsWeakPtr() { return weak_factory_.GetWeakPtr(); }
static bool ShouldSyncOnCommit(
blink::mojom::IDBTransactionDurability durability);
// Create and initialize a BackingStore; verify and report its status.
static std::tuple<std::unique_ptr<indexed_db::BackingStore>,
Status,
IndexedDBDataLossInfo,
bool /* is_disk_full */>
OpenAndVerify(BucketContext& bucket_context,
base::FilePath data_directory,
base::FilePath database_path,
base::FilePath blob_path,
PartitionedLockManager* lock_manager,
bool is_first_attempt,
bool create_if_missing);
private:
FRIEND_TEST_ALL_PREFIXES(LevelDbBackingStoreTestWithExternalObjects,
ActiveBlobJournal);
FRIEND_TEST_ALL_PREFIXES(LevelDbBackingStoreTest, CompactionTaskTiming);
FRIEND_TEST_ALL_PREFIXES(LevelDbBackingStoreTest, TombstoneSweeperTiming);
friend class AutoDidCommitTransaction;
friend class indexed_db::BucketContext;
static std::tuple<std::unique_ptr<BackingStore>,
Status,
IndexedDBDataLossInfo,
bool /* is_disk_full */>
DoOpenAndVerify(BucketContext& bucket_context,
base::FilePath data_directory,
base::FilePath database_path,
base::FilePath blob_path,
PartitionedLockManager* lock_manager,
bool is_first_attempt,
bool create_if_missing);
// Fills in metadata for the database specified by `metadata->name` by reading
// from disk. If no database is found, `metadata->id` will remain null.
Status ReadMetadataForDatabaseName(DatabaseMetadata& metadata);
StatusOr<std::vector<std::u16string>> GetDatabaseNames();
// LevelDBCleanupScheduler::Delegate:
// This function updates the next run timestamp for the
// tombstone sweeper in the database metadata.
// Virtual for testing.
// Returns if the update was successful.
bool UpdateEarliestSweepTime() override;
// This function updates the next run timestamp for the
// level db compaction in the database metadata.
// Virtual for testing.
// Returns if the update was successful.
bool UpdateEarliestCompactionTime() override;
// TODO(dmurph): Move this completely to IndexedDBMetadataFactory.
Status GetCompleteMetadata(
std::vector<std::unique_ptr<blink::IndexedDBDatabaseMetadata>>* output)
override;
// A helper function for V4 schema migration.
// It iterates through all blob files. It will add to the db entry both the
// size and modified date for the blob based on the written file. If any blob
// file in the db is missing on disk, it will return an inconsistency status.
Status UpgradeBlobEntriesToV4(
LevelDBWriteBatch* write_batch,
std::vector<base::FilePath>* empty_blobs_to_delete);
// A helper function for V5 schema miration.
// Iterates through all blob files on disk and validates they exist,
// returning an internal inconsistency corruption error if any are missing.
Status ValidateBlobFiles();
// Remove the referenced file on disk.
bool RemoveBlobFile(int64_t database_id, int64_t key) const;
// Schedule a call to CleanRecoveryJournalIgnoreReturn() via
// an owned timer. If this object is destroyed, the timer
// will automatically be cancelled.
void StartJournalCleaningTimer();
// Attempt to clean the recovery journal. This will remove
// any referenced files and delete the journal entry. If any
// transaction is currently committing this will be deferred
// via StartJournalCleaningTimer().
void CleanRecoveryJournalIgnoreReturn();
Status MigrateToV4(LevelDBWriteBatch* write_batch);
Status MigrateToV5(LevelDBWriteBatch* write_batch);
// Used by ActiveBlobRegistry::MarkBlobInactive.
void ReportBlobUnused(int64_t database_id, int64_t blob_number);
// Remove the blob directory for the specified database and all contained
// blob files.
bool RemoveBlobDirectory(int64_t database_id) const;
// Synchronously read the key-specified blob journal entry from the backing
// store, delete all referenced blob files, and erase the journal entry.
// This must not be used while temporary entries are present e.g. during
// a two-stage transaction commit with blobs.
Status CleanUpBlobJournal(const std::string& level_db_key) const;
// Synchronously delete the files and/or directories on disk referenced by
// the blob journal.
Status CleanUpBlobJournalEntries(const BlobJournalType& journal) const;
void WillCommitTransaction();
// Can run a journal cleaning job if one is pending.
void DidCommitTransaction();
// Returns whether tombstone sweeping or compaction should occur now, checking
// and updating timing information as needed for throttling.
bool ShouldRunTombstoneSweeper();
bool ShouldRunCompaction();
// Returns true if a blob cleanup job is pending on journal_cleaning_timer_.
bool IsBlobCleanupPending();
// Stops the journal_cleaning_timer_ and runs its pending task.
void ForceRunBlobCleanup();
// Owns `this`. Should be initialized shortly after construction.
raw_ptr<BucketContext> bucket_context_ = nullptr;
const Mode backing_store_mode_;
const storage::BucketLocator bucket_locator_;
const base::FilePath blob_path_;
// The origin identifier is a key prefix, unique to the storage key's origin,
// used in the leveldb backing store to partition data by origin. It is a
// normalized version of the origin URL with a versioning suffix appended,
// e.g. "http_localhost_81@1." Since only one storage key is stored per
// backing store this is redundant but necessary for backwards compatibility.
const std::string origin_identifier_;
std::map<std::string, std::unique_ptr<IndexedDBExternalObjectChangeRecord>>
in_memory_external_object_map_;
bool execute_journal_cleaning_on_no_txns_ = false;
int num_aggregated_journal_cleaning_requests_ = 0;
base::OneShotTimer journal_cleaning_timer_;
base::TimeTicks journal_cleaning_timer_window_start_;
#if DCHECK_IS_ON()
mutable int num_blob_files_deleted_ = 0;
#endif
const std::unique_ptr<TransactionalLevelDBDatabase> db_;
const BlobFilesCleanedCallback blob_files_cleaned_;
// Whenever blobs are registered in active_blob_registry_,
// indexed_db_factory_ will hold a reference to this backing store.
std::unique_ptr<ActiveBlobRegistry> active_blob_registry_;
// Ensures tombstones are removed periodically during an active session.
LevelDBCleanupScheduler level_db_cleanup_scheduler_;
// Incremented whenever a transaction starts committing, decremented when
// complete. While > 0, temporary journal entries may exist so out-of-band
// journal cleaning must be deferred.
size_t committing_transaction_count_ = 0;
#if DCHECK_IS_ON()
bool initialized_ = false;
#endif
std::unique_ptr<BackingStorePreCloseTaskQueue> pre_close_task_queue_;
base::WeakPtrFactory<BackingStore> weak_factory_{this};
};
void BindMockFailureSingletonForTesting(
mojo::PendingReceiver<storage::mojom::MockFailureInjector> receiver);
} // namespace level_db
} // namespace content::indexed_db
#endif // CONTENT_BROWSER_INDEXED_DB_INSTANCE_LEVELDB_BACKING_STORE_H_