#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include <algorithm>
#include <optional>
#include <string_view>
#include <tuple>
#include <utility>
#include "base/dcheck_is_on.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/thread_annotations.h"
#include "base/trace_event/base_tracing.h"
#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
#include "components/services/storage/indexed_db/scopes/leveldb_scope.h"
#include "components/services/storage/indexed_db/scopes/leveldb_scopes.h"
#include "components/services/storage/indexed_db/scopes/varint_coding.h"
#include "components/services/storage/indexed_db/transactional_leveldb/leveldb_write_batch.h"
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.h"
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_factory.h"
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h"
#include "components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "components/services/storage/public/mojom/file_system_access_context.mojom.h"
#include "content/browser/indexed_db/file_path_util.h"
#include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
#include "content/browser/indexed_db/indexed_db_bucket_context.h"
#include "content/browser/indexed_db/indexed_db_data_format_version.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
#include "content/browser/indexed_db/indexed_db_external_object.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/indexed_db_leveldb_operations.h"
#include "content/browser/indexed_db/indexed_db_reporting.h"
#include "content/browser/indexed_db/indexed_db_value.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/file_system/file_stream_writer.h"
#include "storage/browser/file_system/file_writer_delegate.h"
#include "storage/browser/file_system/local_file_stream_writer.h"
#include "storage/common/database/database_identifier.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "third_party/blink/public/common/blob/blob_utils.h"
#include "third_party/blink/public/common/indexeddb/indexeddb_key_range.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/leveldatabase/env_chromium.h"
IndexedDBDatabaseMetadata;
IndexedDBKey;
IndexedDBKeyRange;
Status;
namespace content {
CheckIndexAndMetaDataKey;
CheckObjectStoreAndMetaDataType;
FindGreatestKeyLessThanOrEqual;
GetInt;
GetString;
GetVarInt;
InternalInconsistencyStatus;
InvalidDBKeyStatus;
IOErrorStatus;
PutBool;
PutIDBKeyPath;
PutInt;
PutString;
PutVarInt;
ReportOpenStatus;
class AutoDidCommitTransaction { … };
namespace {
std::string ComputeOriginIdentifier(
const storage::BucketLocator& bucket_locator) { … }
leveldb::Status GetDBSizeFromEnv(leveldb::Env* env,
const std::string& path,
int64_t* total_size_out) { … }
template <typename TransactionType>
Status GetBlobJournal(std::string_view key,
TransactionType* transaction,
BlobJournalType* journal) { … }
template <typename TransactionType>
Status GetRecoveryBlobJournal(TransactionType* transaction,
BlobJournalType* journal) { … }
template <typename TransactionType>
Status GetActiveBlobJournal(TransactionType* transaction,
BlobJournalType* journal) { … }
template <typename TransactionType>
void ClearBlobJournal(TransactionType* transaction, const std::string& key) { … }
template <typename TransactionType>
leveldb::Status UpdateBlobJournal(TransactionType* transaction,
const std::string& key,
const BlobJournalType& journal) { … }
template <typename TransactionType>
leveldb::Status UpdateRecoveryBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) { … }
template <typename TransactionType>
leveldb::Status UpdateActiveBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) { … }
template <typename TransactionType>
Status AppendBlobsToBlobJournal(TransactionType* transaction,
const std::string& key,
const BlobJournalType& journal) { … }
template <typename TransactionType>
Status AppendBlobsToRecoveryBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) { … }
template <typename TransactionType>
Status AppendBlobsToActiveBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) { … }
Status MergeDatabaseIntoBlobJournal(
TransactionalLevelDBTransaction* transaction,
const std::string& key,
int64_t database_id) { … }
Status MergeDatabaseIntoRecoveryBlobJournal(
TransactionalLevelDBTransaction* leveldb_transaction,
int64_t database_id) { … }
Status MergeDatabaseIntoActiveBlobJournal(
TransactionalLevelDBTransaction* leveldb_transaction,
int64_t database_id) { … }
std::string EncodeExternalObjects(
const std::vector<IndexedDBExternalObject>& external_objects) { … }
bool DecodeV3ExternalObjects(std::string_view data,
std::vector<IndexedDBExternalObject>* output) { … }
bool DecodeExternalObjects(const std::string& data,
std::vector<IndexedDBExternalObject>* output) { … }
Status DeleteBlobsInRange(IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
const std::string& start_key,
const std::string& end_key,
bool upper_open) { … }
Status DeleteBlobsInObjectStore(IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id) { … }
bool ObjectStoreCursorOptions(
TransactionalLevelDBTransaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
IndexedDBBackingStore::Cursor::CursorOptions* cursor_options,
Status* status) { … }
bool IndexCursorOptions(
TransactionalLevelDBTransaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
IndexedDBBackingStore::Cursor::CursorOptions* cursor_options,
Status* status) { … }
Status ReadIndexes(TransactionalLevelDBDatabase* db,
int64_t database_id,
int64_t object_store_id,
std::map<int64_t, blink::IndexedDBIndexMetadata>* indexes) { … }
Status ReadObjectStores(
TransactionalLevelDBDatabase* db,
int64_t database_id,
std::map<int64_t, blink::IndexedDBObjectStoreMetadata>* object_stores) { … }
Status FindDatabaseId(TransactionalLevelDBDatabase* db,
const std::string& origin_identifier,
const std::u16string& name,
int64_t* id,
bool* found) { … }
}
IndexedDBBackingStore::IndexedDBBackingStore(
Mode backing_store_mode,
const storage::BucketLocator& bucket_locator,
const base::FilePath& blob_path,
TransactionalLevelDBFactory& transactional_leveldb_factory,
std::unique_ptr<TransactionalLevelDBDatabase> db,
BlobFilesCleanedCallback blob_files_cleaned,
ReportOutstandingBlobsCallback report_outstanding_blobs,
scoped_refptr<base::SequencedTaskRunner> idb_task_runner)
: … { … }
IndexedDBBackingStore::~IndexedDBBackingStore() { … }
IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
std::string primary_key,
int64_t version)
: … { … }
IndexedDBBackingStore::RecordIdentifier::RecordIdentifier() = default;
IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() { … }
void IndexedDBBackingStore::RecordIdentifier::Reset(std::string primary_key,
int64_t version) { … }
constexpr const int IndexedDBBackingStore::kMaxJournalCleanRequests;
constexpr const base::TimeDelta
IndexedDBBackingStore::kMaxJournalCleaningWindowTime;
constexpr const base::TimeDelta
IndexedDBBackingStore::kInitialJournalCleaningWindowTime;
leveldb::Status IndexedDBBackingStore::Initialize(bool clean_active_journal) { … }
void IndexedDBBackingStore::TearDown(
base::WaitableEvent* signal_on_destruction) { … }
Status IndexedDBBackingStore::AnyDatabaseContainsBlobs(bool* blobs_exist) { … }
Status IndexedDBBackingStore::UpgradeBlobEntriesToV4(
LevelDBWriteBatch* write_batch,
std::vector<base::FilePath>* empty_blobs_to_delete) { … }
Status IndexedDBBackingStore::ValidateBlobFiles() { … }
std::unique_ptr<IndexedDBBackingStore::Transaction>
IndexedDBBackingStore::CreateTransaction(
blink::mojom::IDBTransactionDurability durability,
blink::mojom::IDBTransactionMode mode) { … }
bool IndexedDBBackingStore::ShouldSyncOnCommit(
blink::mojom::IDBTransactionDurability durability) { … }
leveldb::Status IndexedDBBackingStore::GetCompleteMetadata(
std::vector<IndexedDBDatabaseMetadata>* output) { … }
bool IndexedDBBackingStore::RecordCorruptionInfo(
const base::FilePath& path_base,
const storage::BucketLocator& bucket_locator,
const std::string& message) { … }
Status IndexedDBBackingStore::CreateDatabase(
blink::IndexedDBDatabaseMetadata& metadata) { … }
Status IndexedDBBackingStore::DeleteDatabase(
const std::u16string& name,
TransactionalLevelDBTransaction* transaction) { … }
leveldb::Status IndexedDBBackingStore::SetDatabaseVersion(
Transaction* transaction,
int64_t row_id,
int64_t version,
blink::IndexedDBDatabaseMetadata* metadata) { … }
leveldb::Status IndexedDBBackingStore::CreateObjectStore(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
std::u16string name,
blink::IndexedDBKeyPath key_path,
bool auto_increment,
blink::IndexedDBObjectStoreMetadata* metadata) { … }
Status IndexedDBBackingStore::DeleteObjectStore(
Transaction* transaction,
int64_t database_id,
const blink::IndexedDBObjectStoreMetadata& object_store) { … }
Status IndexedDBBackingStore::RenameObjectStore(
Transaction* transaction,
int64_t database_id,
std::u16string new_name,
std::u16string* old_name,
blink::IndexedDBObjectStoreMetadata* metadata) { … }
Status IndexedDBBackingStore::CreateIndex(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
std::u16string name,
blink::IndexedDBKeyPath key_path,
bool is_unique,
bool is_multi_entry,
blink::IndexedDBIndexMetadata* metadata) { … }
Status IndexedDBBackingStore::DeleteIndex(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const blink::IndexedDBIndexMetadata& metadata) { … }
Status IndexedDBBackingStore::RenameIndex(
Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
std::u16string new_name,
std::u16string* old_name,
blink::IndexedDBIndexMetadata* metadata) { … }
void IndexedDBBackingStore::Compact() { … }
Status IndexedDBBackingStore::GetRecord(Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKey& key,
IndexedDBValue* record) { … }
int64_t IndexedDBBackingStore::GetInMemorySize() const { … }
Status IndexedDBBackingStore::PutRecord(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKey& key,
IndexedDBValue* value,
RecordIdentifier* record_identifier) { … }
Status IndexedDBBackingStore::ClearObjectStore(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id) { … }
Status IndexedDBBackingStore::DeleteRecord(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const RecordIdentifier& record_identifier) { … }
Status IndexedDBBackingStore::DeleteRange(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKeyRange& key_range) { … }
Status IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t* key_generator_current_number) { … }
Status IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t new_number,
bool check_current) { … }
Status IndexedDBBackingStore::KeyExistsInObjectStore(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKey& key,
RecordIdentifier* found_record_identifier,
bool* found) { … }
void IndexedDBBackingStore::ReportBlobUnused(int64_t database_id,
int64_t blob_number) { … }
void IndexedDBBackingStore::StartJournalCleaningTimer() { … }
base::FilePath IndexedDBBackingStore::GetBlobFileName(
int64_t database_id,
int64_t blob_number) const { … }
bool IndexedDBBackingStore::RemoveBlobFile(int64_t database_id,
int64_t blob_number) const { … }
bool IndexedDBBackingStore::RemoveBlobDirectory(int64_t database_id) const { … }
Status IndexedDBBackingStore::CleanUpBlobJournal(
const std::string& level_db_key) const { … }
Status IndexedDBBackingStore::CleanUpBlobJournalEntries(
const BlobJournalType& journal) const { … }
void IndexedDBBackingStore::WillCommitTransaction() { … }
void IndexedDBBackingStore::DidCommitTransaction() { … }
Status IndexedDBBackingStore::Transaction::GetExternalObjectsForRecord(
int64_t database_id,
const std::string& object_store_data_key,
IndexedDBValue* value) { … }
base::WeakPtr<IndexedDBBackingStore::Transaction>
IndexedDBBackingStore::Transaction::AsWeakPtr() { … }
void IndexedDBBackingStore::CleanRecoveryJournalIgnoreReturn() { … }
Status IndexedDBBackingStore::ClearIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id) { … }
Status IndexedDBBackingStore::PutIndexDataForRecord(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKey& key,
const RecordIdentifier& record_identifier) { … }
Status IndexedDBBackingStore::FindKeyInIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKey& key,
std::string* found_encoded_primary_key,
bool* found) { … }
Status IndexedDBBackingStore::GetPrimaryKeyViaIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKey& key,
std::unique_ptr<IndexedDBKey>* primary_key) { … }
Status IndexedDBBackingStore::KeyExistsInIndex(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKey& index_key,
std::unique_ptr<IndexedDBKey>* found_primary_key,
bool* exists) { … }
Status IndexedDBBackingStore::GetDatabaseNames(
std::vector<std::u16string>* names) { … }
Status IndexedDBBackingStore::GetDatabaseNamesAndVersions(
std::vector<blink::mojom::IDBNameAndVersionPtr>* names_and_versions) { … }
leveldb::Status IndexedDBBackingStore::ReadMetadataForDatabaseName(
const std::u16string& name,
blink::IndexedDBDatabaseMetadata* metadata,
bool* found) { … }
IndexedDBBackingStore::Cursor::Cursor(
const IndexedDBBackingStore::Cursor* other,
std::unique_ptr<TransactionalLevelDBIterator> iterator)
: … { … }
IndexedDBBackingStore::Cursor::Cursor(base::WeakPtr<Transaction> transaction,
int64_t database_id,
const CursorOptions& cursor_options)
: … { … }
IndexedDBBackingStore::Cursor::~Cursor() { … }
std::unique_ptr<TransactionalLevelDBIterator>
IndexedDBBackingStore::Cursor::CloneIterator(
const IndexedDBBackingStore::Cursor* other) { … }
bool IndexedDBBackingStore::Cursor::FirstSeek(Status* s) { … }
bool IndexedDBBackingStore::Cursor::Advance(uint32_t count, Status* s) { … }
bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
const IndexedDBKey* primary_key,
IteratorState next_state,
Status* s) { … }
IndexedDBBackingStore::Cursor::ContinueResult
IndexedDBBackingStore::Cursor::ContinueNext(const IndexedDBKey* key,
const IndexedDBKey* primary_key,
IteratorState next_state,
Status* s) { … }
IndexedDBBackingStore::Cursor::ContinueResult
IndexedDBBackingStore::Cursor::ContinuePrevious(const IndexedDBKey* key,
const IndexedDBKey* primary_key,
IteratorState next_state,
Status* s) { … }
bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { … }
bool IndexedDBBackingStore::Cursor::IsPastBounds() const { … }
const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const { … }
class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { … };
IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() = default;
IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions(
const CursorOptions& other) = default;
IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() = default;
const IndexedDBBackingStore::RecordIdentifier&
IndexedDBBackingStore::Cursor::record_identifier() const { … }
bool ObjectStoreKeyCursorImpl::LoadCurrentRow(Status* s) { … }
class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { … };
bool ObjectStoreCursorImpl::LoadCurrentRow(Status* s) { … }
class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { … };
bool IndexKeyCursorImpl::LoadCurrentRow(Status* s) { … }
class IndexCursorImpl : public IndexedDBBackingStore::Cursor { … };
bool IndexCursorImpl::LoadCurrentRow(Status* s) { … }
std::unique_ptr<IndexedDBBackingStore::Cursor>
IndexedDBBackingStore::OpenObjectStoreCursor(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
Status* s) { … }
std::unique_ptr<IndexedDBBackingStore::Cursor>
IndexedDBBackingStore::OpenObjectStoreKeyCursor(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
Status* s) { … }
std::unique_ptr<IndexedDBBackingStore::Cursor>
IndexedDBBackingStore::OpenIndexKeyCursor(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
Status* s) { … }
std::unique_ptr<IndexedDBBackingStore::Cursor>
IndexedDBBackingStore::OpenIndexCursor(
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKeyRange& range,
blink::mojom::IDBCursorDirection direction,
Status* s) { … }
bool IndexedDBBackingStore::IsBlobCleanupPending() { … }
void IndexedDBBackingStore::ForceRunBlobCleanup() { … }
IndexedDBBackingStore::Transaction::BlobWriteState::BlobWriteState() = default;
IndexedDBBackingStore::Transaction::BlobWriteState::BlobWriteState(
int calls_left,
BlobWriteCallback on_complete)
: … { … }
IndexedDBBackingStore::Transaction::BlobWriteState::~BlobWriteState() = default;
IndexedDBBackingStore::Transaction::Transaction(
base::WeakPtr<IndexedDBBackingStore> backing_store,
blink::mojom::IDBTransactionDurability durability,
blink::mojom::IDBTransactionMode mode)
: … { … }
IndexedDBBackingStore::Transaction::~Transaction() { … }
void IndexedDBBackingStore::Transaction::Begin(
std::vector<PartitionedLock> locks) { … }
Status IndexedDBBackingStore::MigrateToV4(LevelDBWriteBatch* write_batch) { … }
Status IndexedDBBackingStore::MigrateToV5(LevelDBWriteBatch* write_batch) { … }
Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction() { … }
bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { … }
void IndexedDBBackingStore::Transaction::PartitionBlobsToRemove(
BlobJournalType* inactive_blobs,
BlobJournalType* active_blobs) const { … }
Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
BlobWriteCallback callback) { … }
Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() { … }
leveldb::Status IndexedDBBackingStore::Transaction::WriteNewBlobs(
BlobWriteCallback callback) { … }
void IndexedDBBackingStore::Transaction::Reset() { … }
void IndexedDBBackingStore::Transaction::Rollback() { … }
uint64_t IndexedDBBackingStore::Transaction::GetTransactionSize() { … }
Status IndexedDBBackingStore::Transaction::PutExternalObjectsIfNeeded(
int64_t database_id,
const std::string& object_store_data_key,
std::vector<IndexedDBExternalObject>* external_objects) { … }
void IndexedDBBackingStore::Transaction::PutExternalObjects(
int64_t database_id,
const std::string& object_store_data_key,
std::vector<IndexedDBExternalObject>* external_objects) { … }
}