Commit 190c0e45 authored by Daniel Murphy's avatar Daniel Murphy Committed by Commit Bot

[IndexedDB] Renamings and cleanups in Blob integration

This change does some renamings to match the terminology outlined here:
https://chromium.googlesource.com/chromium/src/+/master/content/browser/indexed_db/docs/README.md

It also adds more comments to the IndexedDBActiveBlobRegistry, and
splits up the method MarkDeletedCheckIfUsed into:
* MarkDatabaseDeletedAndCheckIfReferenced
* MarkBlobInfoDeletedAndCheckIfReferenced
and changes the following methods to be more accurate:
* AddBlobRef -> MarkBlobActive
* RemoveBlobRef -> MarkBlobInactive

Future CLs will continue renaming parts of the system to match the new
README.

Work planning doc:
https://docs.google.com/document/d/18suNOOzuEJbqgRJF0MB2VqdTyYqS4cvI2PGaCpyPXSw/edit?pli=1#heading=h.wwk24xdiduw5

R=enne@chromium.org

Bug: 1027737, 1024966
Change-Id: I3f569bad802e64eee2ccf55cacafbb170f099d14
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1912828
Commit-Queue: Daniel Murphy <dmurph@chromium.org>
Auto-Submit: Daniel Murphy <dmurph@chromium.org>
Reviewed-by: default avatarenne <enne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718876}
parent 4de1c6cf
......@@ -23,92 +23,102 @@ IndexedDBActiveBlobRegistry::IndexedDBActiveBlobRegistry(
IndexedDBActiveBlobRegistry::~IndexedDBActiveBlobRegistry() {}
bool IndexedDBActiveBlobRegistry::MarkDeletedCheckIfUsed(int64_t database_id,
int64_t blob_key) {
bool IndexedDBActiveBlobRegistry::MarkDatabaseDeletedAndCheckIfReferenced(
int64_t database_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
const auto& db_pair = use_tracker_.find(database_id);
if (db_pair == use_tracker_.end())
const auto& db_pair = blob_reference_tracker_.find(database_id);
if (db_pair == blob_reference_tracker_.end())
return false;
if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
deleted_dbs_.insert(database_id);
return true;
}
}
bool IndexedDBActiveBlobRegistry::MarkBlobInfoDeletedAndCheckIfReferenced(
int64_t database_id,
int64_t blob_number) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(blob_number, DatabaseMetaDataKey::kAllBlobsKey);
DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
const auto& db_pair = blob_reference_tracker_.find(database_id);
if (db_pair == blob_reference_tracker_.end())
return false;
SingleDBMap& single_db = db_pair->second;
auto iter = single_db.find(blob_key);
auto iter = single_db.find(blob_number);
if (iter == single_db.end())
return false;
iter->second = BlobState::kDeleted;
iter->second = BlobState::kUnlinked;
return true;
}
IndexedDBBlobInfo::ReleaseCallback
IndexedDBActiveBlobRegistry::GetFinalReleaseCallback(int64_t database_id,
int64_t blob_key) {
int64_t blob_number) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return base::BindRepeating(
&IndexedDBActiveBlobRegistry::ReleaseBlobRefThreadSafe,
&IndexedDBActiveBlobRegistry::MarkBlobInactiveThreadSafe,
base::SequencedTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr(),
database_id, blob_key);
database_id, blob_number);
}
base::RepeatingClosure IndexedDBActiveBlobRegistry::GetAddBlobRefCallback(
base::RepeatingClosure IndexedDBActiveBlobRegistry::GetMarkBlobActiveCallback(
int64_t database_id,
int64_t blob_key) {
int64_t blob_number) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return base::BindRepeating(&IndexedDBActiveBlobRegistry::AddBlobRef,
weak_factory_.GetWeakPtr(), database_id, blob_key);
return base::BindRepeating(&IndexedDBActiveBlobRegistry::MarkBlobActive,
weak_factory_.GetWeakPtr(), database_id,
blob_number);
}
void IndexedDBActiveBlobRegistry::ForceShutdown() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
weak_factory_.InvalidateWeakPtrs();
use_tracker_.clear();
blob_reference_tracker_.clear();
report_outstanding_blobs_.Reset();
report_unused_blob_.Reset();
}
void IndexedDBActiveBlobRegistry::AddBlobRef(int64_t database_id,
int64_t blob_key) {
void IndexedDBActiveBlobRegistry::MarkBlobActive(int64_t database_id,
int64_t blob_number) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(report_outstanding_blobs_);
DCHECK(report_unused_blob_);
DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_number));
DCHECK(!base::Contains(deleted_dbs_, database_id));
bool outstanding_blobs_in_backing_store = !use_tracker_.empty();
SingleDBMap& blobs_in_db = use_tracker_[database_id];
auto iter = blobs_in_db.find(blob_key);
bool outstanding_blobs_in_backing_store = !blob_reference_tracker_.empty();
SingleDBMap& blobs_in_db = blob_reference_tracker_[database_id];
auto iter = blobs_in_db.find(blob_number);
if (iter == blobs_in_db.end()) {
blobs_in_db[blob_key] = BlobState::kAlive;
blobs_in_db[blob_number] = BlobState::kLinked;
if (!outstanding_blobs_in_backing_store)
report_outstanding_blobs_.Run(true);
} else {
DCHECK(outstanding_blobs_in_backing_store);
// You can't add a reference once it's been deleted.
DCHECK(iter->second == BlobState::kAlive);
DCHECK(iter->second == BlobState::kLinked);
}
}
void IndexedDBActiveBlobRegistry::ReleaseBlobRef(int64_t database_id,
int64_t blob_key) {
void IndexedDBActiveBlobRegistry::MarkBlobInactive(int64_t database_id,
int64_t blob_number) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(report_outstanding_blobs_);
DCHECK(report_unused_blob_);
DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
const auto& db_pair = use_tracker_.find(database_id);
if (db_pair == use_tracker_.end()) {
DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_number));
const auto& db_pair = blob_reference_tracker_.find(database_id);
if (db_pair == blob_reference_tracker_.end()) {
NOTREACHED();
return;
}
SingleDBMap& blobs_in_db = db_pair->second;
auto blob_in_db_it = blobs_in_db.find(blob_key);
auto blob_in_db_it = blobs_in_db.find(blob_number);
if (blob_in_db_it == blobs_in_db.end()) {
NOTREACHED();
return;
......@@ -119,31 +129,31 @@ void IndexedDBActiveBlobRegistry::ReleaseBlobRef(int64_t database_id,
// Don't bother deleting the file if we're going to delete its whole
// database directory soon.
delete_blob_in_backend =
blob_in_db_it->second == BlobState::kDeleted && !db_marked_for_deletion;
blob_in_db_it->second == BlobState::kUnlinked && !db_marked_for_deletion;
blobs_in_db.erase(blob_in_db_it);
if (blobs_in_db.empty()) {
use_tracker_.erase(db_pair);
blob_reference_tracker_.erase(db_pair);
if (db_marked_for_deletion) {
delete_blob_in_backend = true;
blob_key = DatabaseMetaDataKey::kAllBlobsKey;
blob_number = DatabaseMetaDataKey::kAllBlobsKey;
deleted_dbs_.erase(deleted_database_it);
}
}
if (delete_blob_in_backend)
report_unused_blob_.Run(database_id, blob_key);
if (use_tracker_.empty())
report_unused_blob_.Run(database_id, blob_number);
if (blob_reference_tracker_.empty())
report_outstanding_blobs_.Run(false);
}
void IndexedDBActiveBlobRegistry::ReleaseBlobRefThreadSafe(
void IndexedDBActiveBlobRegistry::MarkBlobInactiveThreadSafe(
scoped_refptr<base::TaskRunner> task_runner,
base::WeakPtr<IndexedDBActiveBlobRegistry> weak_ptr,
int64_t database_id,
int64_t blob_key,
int64_t blob_number,
const base::FilePath& unused) {
task_runner->PostTask(
FROM_HERE, base::BindOnce(&IndexedDBActiveBlobRegistry::ReleaseBlobRef,
std::move(weak_ptr), database_id, blob_key));
FROM_HERE, base::BindOnce(&IndexedDBActiveBlobRegistry::MarkBlobInactive,
std::move(weak_ptr), database_id, blob_number));
}
} // namespace content
......@@ -21,10 +21,10 @@
namespace content {
// Keeps track of blobs that have been sent to the renderer as database
// responses, and determines when the file should be deleted. The database entry
// that the blob files live in could be deleted in the database, but the file
// would need to stay alive while it is still used in the renderer.
// Keeps track of blobs that have been sent to clients as database responses,
// and determines when Blob files can be deleted. The database entry that links
// to the blob file can be deleted in the database, but the blob file still
// needs to stay alive while it is still active (i.e. referenced by a client).
// This class must be used on a single sequence, and will call the given
// callbacks back on the same sequence it is constructed on.
class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
......@@ -32,7 +32,7 @@ class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
using ReportOutstandingBlobsCallback = base::RepeatingCallback<void(bool)>;
using ReportUnusedBlobCallback =
base::RepeatingCallback<void(int64_t /*database_id*/,
int64_t /*blob_key*/)>;
int64_t /*blob_number*/)>;
explicit IndexedDBActiveBlobRegistry(
ReportOutstandingBlobsCallback report_outstanding_blobs,
......@@ -40,48 +40,61 @@ class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
~IndexedDBActiveBlobRegistry();
// Most methods of this class, and the closure returned by
// GetAddBlobRefCallback, should only be called on the backing_store's task
// runner. The exception is the closure returned by GetFinalReleaseCallback,
// which just calls ReleaseBlobRefThreadSafe.
// Marks a given blob or a while database as deleted by a transaction, and
// returns if the given blob key (or database) was previously used.
// Use DatabaseMetaDataKey::AllBlobsKey for "the whole database".
bool MarkDeletedCheckIfUsed(int64_t database_id, int64_t blob_key);
// GetMarkBlobActiveCallback, should only be called on the backing_store's
// task runner. The exception is the closure returned by
// GetFinalReleaseCallback, which just calls MarkBlobInactiveThreadSafe.
// Called when the given database is deleted (and all blob infos inside of
// it). Returns true if any of the deleted blobs are active (i.e. referenced
// by a client).
bool MarkDatabaseDeletedAndCheckIfReferenced(int64_t database_id);
// Called when the given blob handle is deleted by a transaction, and returns
// if the blob file has one or more external references.
bool MarkBlobInfoDeletedAndCheckIfReferenced(int64_t database_id,
int64_t blob_number);
// When called, the returned callback will mark the given blob entry as
// inactive (i.e. no longer referenced by a client).
IndexedDBBlobInfo::ReleaseCallback GetFinalReleaseCallback(
int64_t database_id,
int64_t blob_key);
// This closure holds a raw pointer to the IndexedDBActiveBlobRegistry,
// and may not be called after it is deleted.
base::RepeatingClosure GetAddBlobRefCallback(int64_t database_id,
int64_t blob_key);
int64_t blob_number);
// When called, the returned closure will mark the given blob entry as active
// (i.e. referenced by the client). Calling this multiple times does nothing.
// This closure holds a raw pointer to the IndexedDBActiveBlobRegistry, and
// may not be called after it is deleted.
base::RepeatingClosure GetMarkBlobActiveCallback(int64_t database_id,
int64_t blob_number);
// Call this to force the registry to drop its use counts, permitting the
// factory to drop any blob-related refcount for the backing store.
// This will also turn any outstanding callbacks into no-ops.
void ForceShutdown();
private:
enum class BlobState { kAlive, kDeleted };
// Maps blob_key -> BlobState; if the record's absent, it's not in active use
// and we don't care if it's deleted.
enum class BlobState { kLinked, kUnlinked };
// Maps blob_number -> BlobState; if the record's absent, it's not in active
// use and we don't care if it's deleted.
typedef std::map<int64_t, BlobState> SingleDBMap;
void AddBlobRef(int64_t database_id, int64_t blob_key);
void MarkBlobActive(int64_t database_id, int64_t blob_number);
// Removes a reference to the given blob.
void ReleaseBlobRef(int64_t database_id, int64_t blob_key);
static void ReleaseBlobRefThreadSafe(
void MarkBlobInactive(int64_t database_id, int64_t blob_number);
static void MarkBlobInactiveThreadSafe(
scoped_refptr<base::TaskRunner> task_runner,
base::WeakPtr<IndexedDBActiveBlobRegistry> weak_ptr,
int64_t database_id,
int64_t blob_key,
int64_t blob_number,
const base::FilePath& unused);
SEQUENCE_CHECKER(sequence_checker_);
std::map<int64_t, SingleDBMap> use_tracker_;
// Databases that have been marked as deleted by MarkDeletedCheckIfUsed.
// This stores, for every database, the blobs that are currently being used in
// that database.
std::map<int64_t, SingleDBMap> blob_reference_tracker_;
// Databases that have been marked as deleted by
// MarkDatabaseDeletedAndCheckIfReferenced.
std::set<int64_t> deleted_dbs_;
ReportOutstandingBlobsCallback report_outstanding_blobs_;
ReportUnusedBlobCallback report_unused_blob_;
......
......@@ -87,7 +87,8 @@ TEST_F(IndexedDBActiveBlobRegistryTest, DeleteUnused) {
EXPECT_TRUE(report_outstanding_state_.no_calls());
EXPECT_TRUE(unused_blobs_.empty());
EXPECT_FALSE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey0));
EXPECT_FALSE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(kDatabaseId0,
kBlobKey0));
RunUntilIdle();
EXPECT_TRUE(report_outstanding_state_.no_calls());
......@@ -99,7 +100,7 @@ TEST_F(IndexedDBActiveBlobRegistryTest, SimpleUse) {
EXPECT_TRUE(unused_blobs_.empty());
base::Closure add_ref =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey0);
ReleaseCallback release =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0);
std::move(add_ref).Run();
......@@ -122,7 +123,7 @@ TEST_F(IndexedDBActiveBlobRegistryTest, DeleteWhileInUse) {
EXPECT_TRUE(unused_blobs_.empty());
base::Closure add_ref =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey0);
ReleaseCallback release =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0);
......@@ -133,7 +134,8 @@ TEST_F(IndexedDBActiveBlobRegistryTest, DeleteWhileInUse) {
EXPECT_EQ(0, report_outstanding_state_.false_calls);
EXPECT_TRUE(unused_blobs_.empty());
EXPECT_TRUE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey0));
EXPECT_TRUE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(kDatabaseId0,
kBlobKey0));
RunUntilIdle();
EXPECT_EQ(1, report_outstanding_state_.true_calls);
......@@ -155,19 +157,19 @@ TEST_F(IndexedDBActiveBlobRegistryTest, MultipleBlobs) {
EXPECT_TRUE(unused_blobs_.empty());
base::Closure add_ref_00 =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey0);
ReleaseCallback release_00 =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0);
base::Closure add_ref_01 =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey1);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey1);
ReleaseCallback release_01 =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey1);
base::Closure add_ref_10 =
registry()->GetAddBlobRefCallback(kDatabaseId1, kBlobKey0);
registry()->GetMarkBlobActiveCallback(kDatabaseId1, kBlobKey0);
ReleaseCallback release_10 =
registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobKey0);
base::Closure add_ref_11 =
registry()->GetAddBlobRefCallback(kDatabaseId1, kBlobKey1);
registry()->GetMarkBlobActiveCallback(kDatabaseId1, kBlobKey1);
ReleaseCallback release_11 =
registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobKey1);
......@@ -188,7 +190,8 @@ TEST_F(IndexedDBActiveBlobRegistryTest, MultipleBlobs) {
EXPECT_EQ(0, report_outstanding_state_.false_calls);
EXPECT_TRUE(unused_blobs_.empty());
EXPECT_TRUE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey1));
EXPECT_TRUE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(kDatabaseId0,
kBlobKey1));
RunUntilIdle();
EXPECT_EQ(1, report_outstanding_state_.true_calls);
......@@ -220,11 +223,11 @@ TEST_F(IndexedDBActiveBlobRegistryTest, ForceShutdown) {
EXPECT_TRUE(unused_blobs_.empty());
base::Closure add_ref_0 =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey0);
ReleaseCallback release_0 =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0);
base::Closure add_ref_1 =
registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey1);
registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobKey1);
ReleaseCallback release_1 =
registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey1);
......
......@@ -130,7 +130,7 @@ std::string ComputeOriginIdentifier(const Origin& origin) {
// need be.
// Read and decode the specified blob journal via the supplied transaction.
// The key must be either the primary journal key or live journal key.
// The key must be either the recovery journal key or active journal key.
template <typename TransactionType>
Status GetBlobJournal(const StringPiece& key,
TransactionType* transaction,
......@@ -155,26 +155,26 @@ Status GetBlobJournal(const StringPiece& key,
}
template <typename TransactionType>
Status GetPrimaryBlobJournal(TransactionType* transaction,
Status GetRecoveryBlobJournal(TransactionType* transaction,
BlobJournalType* journal) {
return GetBlobJournal(BlobJournalKey::Encode(), transaction, journal);
return GetBlobJournal(RecoveryBlobJournalKey::Encode(), transaction, journal);
}
template <typename TransactionType>
Status GetLiveBlobJournal(TransactionType* transaction,
Status GetActiveBlobJournal(TransactionType* transaction,
BlobJournalType* journal) {
return GetBlobJournal(LiveBlobJournalKey::Encode(), transaction, journal);
return GetBlobJournal(ActiveBlobJournalKey::Encode(), transaction, journal);
}
// Clear the specified blob journal via the supplied transaction.
// The key must be either the primary journal key or live journal key.
// The key must be either the recovery journal key or active journal key.
template <typename TransactionType>
void ClearBlobJournal(TransactionType* transaction, const std::string& key) {
transaction->Remove(key);
}
// Overwrite the specified blob journal via the supplied transaction.
// The key must be either the primary journal key or live journal key.
// The key must be either the recovery journal key or active journal key.
template <typename TransactionType>
leveldb::Status UpdateBlobJournal(TransactionType* transaction,
const std::string& key,
......@@ -185,19 +185,21 @@ leveldb::Status UpdateBlobJournal(TransactionType* transaction,
}
template <typename TransactionType>
leveldb::Status UpdatePrimaryBlobJournal(TransactionType* transaction,
leveldb::Status UpdateRecoveryBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) {
return UpdateBlobJournal(transaction, BlobJournalKey::Encode(), journal);
return UpdateBlobJournal(transaction, RecoveryBlobJournalKey::Encode(),
journal);
}
template <typename TransactionType>
leveldb::Status UpdateLiveBlobJournal(TransactionType* transaction,
leveldb::Status UpdateActiveBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) {
return UpdateBlobJournal(transaction, LiveBlobJournalKey::Encode(), journal);
return UpdateBlobJournal(transaction, ActiveBlobJournalKey::Encode(),
journal);
}
// Append blobs to the specified blob journal via the supplied transaction.
// The key must be either the primary journal key or live journal key.
// The key must be either the recovery journal key or active journal key.
template <typename TransactionType>
Status AppendBlobsToBlobJournal(TransactionType* transaction,
const std::string& key,
......@@ -213,21 +215,21 @@ Status AppendBlobsToBlobJournal(TransactionType* transaction,
}
template <typename TransactionType>
Status AppendBlobsToPrimaryBlobJournal(TransactionType* transaction,
Status AppendBlobsToRecoveryBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) {
return AppendBlobsToBlobJournal(transaction, BlobJournalKey::Encode(),
return AppendBlobsToBlobJournal(transaction, RecoveryBlobJournalKey::Encode(),
journal);
}
template <typename TransactionType>
Status AppendBlobsToLiveBlobJournal(TransactionType* transaction,
Status AppendBlobsToActiveBlobJournal(TransactionType* transaction,
const BlobJournalType& journal) {
return AppendBlobsToBlobJournal(transaction, LiveBlobJournalKey::Encode(),
return AppendBlobsToBlobJournal(transaction, ActiveBlobJournalKey::Encode(),
journal);
}
// Append a database to the specified blob journal via the supplied transaction.
// The key must be either the primary journal key or live journal key.
// The key must be either the recovery journal key or active journal key.
Status MergeDatabaseIntoBlobJournal(
TransactionalLevelDBTransaction* transaction,
const std::string& key,
......@@ -242,18 +244,18 @@ Status MergeDatabaseIntoBlobJournal(
return Status::OK();
}
Status MergeDatabaseIntoPrimaryBlobJournal(
Status MergeDatabaseIntoRecoveryBlobJournal(
TransactionalLevelDBTransaction* leveldb_transaction,
int64_t database_id) {
return MergeDatabaseIntoBlobJournal(leveldb_transaction,
BlobJournalKey::Encode(), database_id);
return MergeDatabaseIntoBlobJournal(
leveldb_transaction, RecoveryBlobJournalKey::Encode(), database_id);
}
Status MergeDatabaseIntoLiveBlobJournal(
Status MergeDatabaseIntoActiveBlobJournal(
TransactionalLevelDBTransaction* leveldb_transaction,
int64_t database_id) {
return MergeDatabaseIntoBlobJournal(
leveldb_transaction, LiveBlobJournalKey::Encode(), database_id);
leveldb_transaction, ActiveBlobJournalKey::Encode(), database_id);
}
// Blob Data is encoded as a series of:
......@@ -263,7 +265,7 @@ Status MergeDatabaseIntoLiveBlobJournal(
// (for Files only) fileName [string-with-length]
// }
// There is no length field; just read until you run out of data.
std::string EncodeBlobData(const std::vector<IndexedDBBlobInfo*>& blob_info) {
std::string EncodeBlobInfos(const std::vector<IndexedDBBlobInfo*>& blob_info) {
std::string ret;
for (const auto* info : blob_info) {
EncodeBool(info->is_file(), &ret);
......@@ -277,7 +279,7 @@ std::string EncodeBlobData(const std::vector<IndexedDBBlobInfo*>& blob_info) {
return ret;
}
bool DecodeBlobData(const std::string& data,
bool DecodeBlobInfos(const std::string& data,
std::vector<IndexedDBBlobInfo>* output) {
std::vector<IndexedDBBlobInfo> ret;
output->clear();
......@@ -569,7 +571,7 @@ constexpr const base::TimeDelta
constexpr const base::TimeDelta
IndexedDBBackingStore::kInitialJournalCleaningWindowTime;
leveldb::Status IndexedDBBackingStore::Initialize(bool clean_live_journal) {
leveldb::Status IndexedDBBackingStore::Initialize(bool clean_active_journal) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
#if DCHECK_IS_ON()
DCHECK(!initialized_);
......@@ -728,8 +730,8 @@ leveldb::Status IndexedDBBackingStore::Initialize(bool clean_live_journal) {
return s;
}
if (clean_live_journal) {
s = CleanUpBlobJournal(LiveBlobJournalKey::Encode());
if (clean_active_journal) {
s = CleanUpBlobJournal(ActiveBlobJournalKey::Encode());
if (!s.ok()) {
indexed_db::ReportOpenStatus(
indexed_db::
......@@ -956,13 +958,14 @@ Status IndexedDBBackingStore::DeleteDatabase(
return s;
bool need_cleanup = false;
if (active_blob_registry()->MarkDeletedCheckIfUsed(
id, DatabaseMetaDataKey::kAllBlobsKey)) {
s = MergeDatabaseIntoLiveBlobJournal(transaction, id);
bool database_has_blob_references =
active_blob_registry()->MarkDatabaseDeletedAndCheckIfReferenced(id);
if (database_has_blob_references) {
s = MergeDatabaseIntoActiveBlobJournal(transaction, id);
if (!s.ok())
return s;
} else {
s = MergeDatabaseIntoPrimaryBlobJournal(transaction, id);
s = MergeDatabaseIntoRecoveryBlobJournal(transaction, id);
if (!s.ok())
return s;
need_cleanup = true;
......@@ -978,7 +981,7 @@ Status IndexedDBBackingStore::DeleteDatabase(
// If another transaction is running, this will defer processing
// the journal until completion.
if (need_cleanup)
CleanPrimaryJournalIgnoreReturn();
CleanRecoveryJournalIgnoreReturn();
return s;
}
......@@ -1651,24 +1654,24 @@ void IndexedDBBackingStore::ReportBlobUnused(int64_t database_id,
std::unique_ptr<LevelDBDirectTransaction> transaction =
transactional_leveldb_factory_->CreateLevelDBDirectTransaction(db_.get());
BlobJournalType live_blob_journal, primary_journal;
if (!GetLiveBlobJournal(transaction.get(), &live_blob_journal).ok())
BlobJournalType active_blob_journal, recovery_journal;
if (!GetActiveBlobJournal(transaction.get(), &active_blob_journal).ok())
return;
DCHECK(!live_blob_journal.empty());
if (!GetPrimaryBlobJournal(transaction.get(), &primary_journal).ok())
DCHECK(!active_blob_journal.empty());
if (!GetRecoveryBlobJournal(transaction.get(), &recovery_journal).ok())
return;
// There are several cases to handle. If blob_key is kAllBlobsKey, we want to
// remove all entries with database_id from the live_blob journal and add only
// kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key)
// and we hit kAllBlobsKey for the right database_id in the journal, we leave
// the kAllBlobsKey entry in the live_blob journal but add the specific blob
// to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a
// matching (database_id, blob_key) tuple, we should move it to the primary
// journal.
BlobJournalType new_live_blob_journal;
for (auto journal_iter = live_blob_journal.begin();
journal_iter != live_blob_journal.end(); ++journal_iter) {
// remove all entries with database_id from the active blob journal and add
// only kAllBlobsKey to the recovery journal. Otherwise if
// IsValidBlobKey(blob_key) and we hit kAllBlobsKey for the right database_id
// in the journal, we leave the kAllBlobsKey entry in the active blob journal
// but add the specific blob to the recovery. Otherwise if
// IsValidBlobKey(blob_key) and we find a matching (database_id, blob_key)
// tuple, we should move it to the recovery journal.
BlobJournalType new_active_blob_journal;
for (auto journal_iter = active_blob_journal.begin();
journal_iter != active_blob_journal.end(); ++journal_iter) {
int64_t current_database_id = journal_iter->first;
int64_t current_blob_key = journal_iter->second;
bool current_all_blobs =
......@@ -1678,23 +1681,24 @@ void IndexedDBBackingStore::ReportBlobUnused(int64_t database_id,
if (current_database_id == database_id &&
(all_blobs || current_all_blobs || blob_key == current_blob_key)) {
if (!all_blobs) {
primary_journal.push_back({database_id, current_blob_key});
recovery_journal.push_back({database_id, current_blob_key});
if (current_all_blobs)
new_live_blob_journal.push_back(*journal_iter);
new_live_blob_journal.insert(new_live_blob_journal.end(),
++journal_iter,
live_blob_journal.end()); // All the rest.
new_active_blob_journal.push_back(*journal_iter);
new_active_blob_journal.insert(
new_active_blob_journal.end(), ++journal_iter,
active_blob_journal.end()); // All the rest.
break;
}
} else {
new_live_blob_journal.push_back(*journal_iter);
new_active_blob_journal.push_back(*journal_iter);
}
}
if (all_blobs) {
primary_journal.push_back({database_id, DatabaseMetaDataKey::kAllBlobsKey});
recovery_journal.push_back(
{database_id, DatabaseMetaDataKey::kAllBlobsKey});
}
UpdatePrimaryBlobJournal(transaction.get(), primary_journal);
UpdateLiveBlobJournal(transaction.get(), new_live_blob_journal);
UpdateRecoveryBlobJournal(transaction.get(), recovery_journal);
UpdateActiveBlobJournal(transaction.get(), new_active_blob_journal);
transaction->Commit();
// We could just do the deletions/cleaning here, but if there are a lot of
// blobs about to be garbage collected, it'd be better to wait and do them all
......@@ -1717,7 +1721,7 @@ void IndexedDBBackingStore::StartJournalCleaningTimer() {
if (num_aggregated_journal_cleaning_requests_ >= kMaxJournalCleanRequests) {
journal_cleaning_timer_.AbandonAndStop();
CleanPrimaryJournalIgnoreReturn();
CleanRecoveryJournalIgnoreReturn();
return;
}
......@@ -1735,13 +1739,13 @@ void IndexedDBBackingStore::StartJournalCleaningTimer() {
if (delay <= base::TimeDelta::FromSeconds(0)) {
journal_cleaning_timer_.AbandonAndStop();
CleanPrimaryJournalIgnoreReturn();
CleanRecoveryJournalIgnoreReturn();
return;
}
journal_cleaning_timer_.Start(
FROM_HERE, delay, this,
&IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn);
&IndexedDBBackingStore::CleanRecoveryJournalIgnoreReturn);
}
// This assumes a file path of dbId/second-to-LSB-of-counter/counter.
......@@ -1822,7 +1826,7 @@ void IndexedDBBackingStore::DidCommitTransaction() {
if (committing_transaction_count_ == 0 &&
execute_journal_cleaning_on_no_txns_) {
execute_journal_cleaning_on_no_txns_ = false;
CleanPrimaryJournalIgnoreReturn();
CleanRecoveryJournalIgnoreReturn();
}
}
......@@ -1861,7 +1865,7 @@ Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
if (!s.ok())
return s;
if (found) {
if (!DecodeBlobData(encoded_value, &value->blob_info)) {
if (!DecodeBlobInfos(encoded_value, &value->blob_info)) {
INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD);
return InternalInconsistencyStatus();
}
......@@ -1869,7 +1873,7 @@ Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
entry.set_file_path(
backing_store_->GetBlobFileName(database_id, entry.key()));
entry.set_mark_used_callback(
backing_store_->active_blob_registry()->GetAddBlobRefCallback(
backing_store_->active_blob_registry()->GetMarkBlobActiveCallback(
database_id, entry.key()));
entry.set_release_callback(
backing_store_->active_blob_registry()->GetFinalReleaseCallback(
......@@ -1893,14 +1897,14 @@ IndexedDBBackingStore::Transaction::AsWeakPtr() {
return ptr_factory_.GetWeakPtr();
}
void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() {
void IndexedDBBackingStore::CleanRecoveryJournalIgnoreReturn() {
// While a transaction is busy it is not safe to clean the journal.
if (committing_transaction_count_ > 0) {
execute_journal_cleaning_on_no_txns_ = true;
return;
}
num_aggregated_journal_cleaning_requests_ = 0;
CleanUpBlobJournal(BlobJournalKey::Encode());
CleanUpBlobJournal(RecoveryBlobJournalKey::Encode());
}
Status IndexedDBBackingStore::ClearIndex(
......@@ -2945,10 +2949,10 @@ Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
return InternalInconsistencyStatus();
}
new_blob_entries->push_back(
{blob_entry_key, EncodeBlobData(new_blob_keys)});
{blob_entry_key, EncodeBlobInfos(new_blob_keys)});
}
AppendBlobsToPrimaryBlobJournal(direct_txn.get(), blobs_to_write_);
AppendBlobsToRecoveryBlobJournal(direct_txn.get(), blobs_to_write_);
return direct_txn->Commit();
}
......@@ -2980,7 +2984,7 @@ bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
&found);
if (s.ok() && found) {
std::vector<IndexedDBBlobInfo> blob_info;
if (!DecodeBlobData(blob_entry_value_bytes, &blob_info)) {
if (!DecodeBlobInfos(blob_entry_value_bytes, &blob_info)) {
INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
transaction_ = nullptr;
return false;
......@@ -2999,16 +3003,18 @@ bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
}
void IndexedDBBackingStore::Transaction::PartitionBlobsToRemove(
BlobJournalType* dead_blobs,
BlobJournalType* live_blobs) const {
BlobJournalType* inactive_blobs,
BlobJournalType* active_blobs) const {
DCHECK(backing_store_);
IndexedDBActiveBlobRegistry* registry =
backing_store_->active_blob_registry();
for (const auto& iter : blobs_to_remove_) {
if (registry->MarkDeletedCheckIfUsed(iter.first, iter.second))
live_blobs->push_back(iter);
bool is_blob_referenced = registry->MarkBlobInfoDeletedAndCheckIfReferenced(
iter.first, iter.second);
if (is_blob_referenced)
active_blobs->push_back(iter);
else
dead_blobs->push_back(iter);
inactive_blobs->push_back(iter);
}
}
......@@ -3062,45 +3068,45 @@ Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
backing_store_->DidCommitTransaction();
BlobJournalType primary_journal, live_journal, saved_primary_journal,
dead_blobs;
BlobJournalType recovery_journal, active_journal, saved_recovery_journal,
inactive_blobs;
if (!blob_change_map_.empty()) {
IDB_TRACE("IndexedDBBackingStore::Transaction.BlobJournal");
// Read the persisted states of the primary/live blob journals,
// Read the persisted states of the recovery/live blob journals,
// so that they can be updated correctly by the transaction.
std::unique_ptr<LevelDBDirectTransaction> journal_transaction =
transactional_leveldb_factory_->CreateLevelDBDirectTransaction(
backing_store_->db_.get());
s = GetPrimaryBlobJournal(journal_transaction.get(), &primary_journal);
s = GetRecoveryBlobJournal(journal_transaction.get(), &recovery_journal);
if (!s.ok())
return s;
s = GetLiveBlobJournal(journal_transaction.get(), &live_journal);
s = GetActiveBlobJournal(journal_transaction.get(), &active_journal);
if (!s.ok())
return s;
// Remove newly added blobs from the journal - they will be accounted
// for in blob entry tables in the transaction.
std::sort(primary_journal.begin(), primary_journal.end());
std::sort(recovery_journal.begin(), recovery_journal.end());
std::sort(blobs_to_write_.begin(), blobs_to_write_.end());
BlobJournalType new_journal = base::STLSetDifference<BlobJournalType>(
primary_journal, blobs_to_write_);
primary_journal.swap(new_journal);
recovery_journal, blobs_to_write_);
recovery_journal.swap(new_journal);
// Append newly deleted blobs to appropriate primary/live journals.
saved_primary_journal = primary_journal;
BlobJournalType live_blobs;
// Append newly deleted blobs to appropriate recovery/active journals.
saved_recovery_journal = recovery_journal;
BlobJournalType active_blobs;
if (!blobs_to_remove_.empty()) {
DCHECK(!backing_store_->is_incognito());
PartitionBlobsToRemove(&dead_blobs, &live_blobs);
PartitionBlobsToRemove(&inactive_blobs, &active_blobs);
}
primary_journal.insert(primary_journal.end(), dead_blobs.begin(),
dead_blobs.end());
live_journal.insert(live_journal.end(), live_blobs.begin(),
live_blobs.end());
s = UpdatePrimaryBlobJournal(transaction_.get(), primary_journal);
recovery_journal.insert(recovery_journal.end(), inactive_blobs.begin(),
inactive_blobs.end());
active_journal.insert(active_journal.end(), active_blobs.begin(),
active_blobs.end());
s = UpdateRecoveryBlobJournal(transaction_.get(), recovery_journal);
if (!s.ok())
return s;
s = UpdateLiveBlobJournal(transaction_.get(), live_journal);
s = UpdateActiveBlobJournal(transaction_.get(), active_journal);
if (!s.ok())
return s;
}
......@@ -3132,13 +3138,13 @@ Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
}
// Actually delete dead blob files, then remove those entries
// from the persisted primary journal.
if (dead_blobs.empty())
// from the persisted recovery journal.
if (inactive_blobs.empty())
return Status::OK();
DCHECK(!blob_change_map_.empty());
s = backing_store_->CleanUpBlobJournalEntries(dead_blobs);
s = backing_store_->CleanUpBlobJournalEntries(inactive_blobs);
if (!s.ok()) {
INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
return s;
......@@ -3147,8 +3153,8 @@ Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
std::unique_ptr<LevelDBDirectTransaction> update_journal_transaction =
transactional_leveldb_factory_->CreateLevelDBDirectTransaction(
backing_store_->db_.get());
UpdatePrimaryBlobJournal(update_journal_transaction.get(),
saved_primary_journal);
UpdateRecoveryBlobJournal(update_journal_transaction.get(),
saved_recovery_journal);
s = update_journal_transaction->Commit();
return s;
}
......
......@@ -424,7 +424,7 @@ class CONTENT_EXPORT IndexedDBBackingStore {
// Initializes the backing store. This must be called before doing any
// operations or method calls on this object.
leveldb::Status Initialize(bool clean_live_blob_journal);
leveldb::Status Initialize(bool clean_active_blob_journal);
const url::Origin& origin() const { return origin_; }
base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
......@@ -518,7 +518,7 @@ class CONTENT_EXPORT IndexedDBBackingStore {
std::unique_ptr<blink::IndexedDBKey>* found_primary_key,
bool* exists) WARN_UNUSED_RESULT;
// Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
// Public for IndexedDBActiveBlobRegistry::MarkBlobInactive.
virtual void ReportBlobUnused(int64_t database_id, int64_t blob_key);
base::FilePath GetBlobFileName(int64_t database_id, int64_t key) const;
......@@ -613,16 +613,16 @@ class CONTENT_EXPORT IndexedDBBackingStore {
// Remove the referenced file on disk.
virtual bool RemoveBlobFile(int64_t database_id, int64_t key) const;
// Schedule a call to CleanPrimaryJournalIgnoreReturn() via
// Schedule a call to CleanRecoveryJournalIgnoreReturn() via
// an owned timer. If this object is destroyed, the timer
// will automatically be cancelled.
virtual void StartJournalCleaningTimer();
// Attempt to clean the primary journal. This will remove
// 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 CleanPrimaryJournalIgnoreReturn();
void CleanRecoveryJournalIgnoreReturn();
private:
leveldb::Status FindKeyInIndex(
......
......@@ -904,7 +904,7 @@ TEST_F(IndexedDBBackingStoreTestWithBlobs, BlobJournalInterleavedTransactions) {
RunAllTasksUntilIdle();
}
TEST_F(IndexedDBBackingStoreTestWithBlobs, LiveBlobJournal) {
TEST_F(IndexedDBBackingStoreTestWithBlobs, ActiveBlobJournal) {
std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1;
TestCallback callback_creator1;
std::unique_ptr<IndexedDBBackingStore::Transaction> transaction3;
......
......@@ -919,7 +919,7 @@ IndexedDBFactoryImpl::OpenAndVerifyIndexedDBBackingStore(
weak_factory_.GetWeakPtr(), origin),
context_->TaskRunner());
status = backing_store->Initialize(
/*cleanup_live_journal=*/(!is_incognito_and_in_memory &&
/*cleanup_active_journal=*/(!is_incognito_and_in_memory &&
first_open_since_startup));
if (UNLIKELY(!status.ok()))
......
......@@ -63,8 +63,8 @@ constexpr unsigned char kBlobEntryIndexId = 3;
constexpr unsigned char kSchemaVersionTypeByte = 0;
constexpr unsigned char kMaxDatabaseIdTypeByte = 1;
constexpr unsigned char kDataVersionTypeByte = 2;
constexpr unsigned char kBlobJournalTypeByte = 3;
constexpr unsigned char kLiveBlobJournalTypeByte = 4;
constexpr unsigned char kRecoveryBlobJournalTypeByte = 3;
constexpr unsigned char kActiveBlobJournalTypeByte = 4;
constexpr unsigned char kEarliestSweepTimeTypeByte = 5;
constexpr unsigned char kMaxSimpleGlobalMetaDataTypeByte =
6; // Insert before this and increment.
......@@ -1013,11 +1013,11 @@ std::string IndexedDBKeyToDebugString(base::StringPiece key) {
case kDataVersionTypeByte:
result << "kDataVersionTypeByte";
break;
case kBlobJournalTypeByte:
result << "kBlobJournalTypeByte";
case kRecoveryBlobJournalTypeByte:
result << "kRecoveryBlobJournalTypeByte";
break;
case kLiveBlobJournalTypeByte:
result << "kLiveBlobJournalTypeByte";
case kActiveBlobJournalTypeByte:
result << "kActiveBlobJournalTypeByte";
break;
case kEarliestSweepTimeTypeByte:
result << "kEarliestSweepTimeTypeByte";
......@@ -1444,15 +1444,15 @@ std::string DataVersionKey::Encode() {
return ret;
}
std::string BlobJournalKey::Encode() {
std::string RecoveryBlobJournalKey::Encode() {
std::string ret = KeyPrefix::EncodeEmpty();
ret.push_back(kBlobJournalTypeByte);
ret.push_back(kRecoveryBlobJournalTypeByte);
return ret;
}
std::string LiveBlobJournalKey::Encode() {
std::string ActiveBlobJournalKey::Encode() {
std::string ret = KeyPrefix::EncodeEmpty();
ret.push_back(kLiveBlobJournalTypeByte);
ret.push_back(kActiveBlobJournalTypeByte);
return ret;
}
......
......@@ -225,12 +225,12 @@ class DataVersionKey {
CONTENT_EXPORT static std::string Encode();
};
class BlobJournalKey {
class RecoveryBlobJournalKey {
public:
static std::string Encode();
};
class LiveBlobJournalKey {
class ActiveBlobJournalKey {
public:
static std::string Encode();
};
......
......@@ -151,8 +151,8 @@ key | value
«0, 0, 0, 0» | backing store schema version (Int) [`SchemaVersionKey`]
«0, 0, 0, 1» | maximum allocated database (Int) [`MaxDatabaseIdKey`]
«0, 0, 0, 2» | data format version (Int) [`DataVersionKey`]
«0, 0, 0, 3» | primary BlobJournal [`BlobJournalKey`]
«0, 0, 0, 4» | live BlobJournal [`LiveBlobJournalKey`]
«0, 0, 0, 3» | recovery BlobJournal [`RecoveryBlobJournalKey`]
«0, 0, 0, 4» | active BlobJournal [`ActiveBlobJournalKey`]
«0, 0, 0, 5» | earliest sweep time (microseconds) (Int) [`EarliestSweepKey`]
«0, 0, 0, 100, database id (VarInt)» | Existence implies the database id is in the free list [`DatabaseFreeListKey`] - _obsolete_
«0, 0, 0, 201, origin (StringWithLength), database name (StringWithLength)» | Database id (Int) [`DatabaseNameKey`]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment