123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/leveldb_proto/internal/shared_proto_database_client.h"
- #include <memory>
- #include <utility>
- #include "base/check.h"
- #include "base/check_op.h"
- #include "base/notreached.h"
- #include "base/strings/strcat.h"
- #include "base/strings/stringprintf.h"
- #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
- #include "components/leveldb_proto/internal/shared_proto_database.h"
- #include "components/leveldb_proto/public/proto_database.h"
- #include "components/leveldb_proto/public/shared_proto_database_client_list.h"
- namespace leveldb_proto {
- namespace {
- const ProtoDbType* g_obsolete_client_list_for_testing = nullptr;
- // Holds the db wrapper alive and callback is called at destruction. This class
- // is used to post multiple update tasks on |db_wrapper| and keep the instance
- // alive till all the callbacks are returned.
- class ObsoleteClientsDbHolder
- : public base::RefCounted<ObsoleteClientsDbHolder> {
- public:
- ObsoleteClientsDbHolder(std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
- Callbacks::UpdateCallback callback)
- : success_(true),
- owned_db_wrapper_(std::move(db_wrapper)),
- callback_(std::move(callback)) {}
- void set_success(bool success) { success_ &= success; }
- private:
- friend class base::RefCounted<ObsoleteClientsDbHolder>;
- ~ObsoleteClientsDbHolder() { std::move(callback_).Run(success_); }
- bool success_;
- std::unique_ptr<ProtoLevelDBWrapper> owned_db_wrapper_;
- Callbacks::UpdateCallback callback_;
- };
- PhysicalKey MakePhysicalKey(const KeyPrefix& prefix, const LogicalKey& key) {
- return PhysicalKey(base::StrCat({prefix.value(), key.value()}));
- }
- } // namespace
- // static
- bool SharedProtoDatabaseClient::HasPrefix(const PhysicalKey& key,
- const KeyPrefix& prefix) {
- return base::StartsWith(key.value(), prefix.value(),
- base::CompareCase::SENSITIVE);
- }
- // static
- absl::optional<LogicalKey> SharedProtoDatabaseClient::StripPrefix(
- const PhysicalKey& key,
- const KeyPrefix& prefix) {
- if (!HasPrefix(key, prefix))
- return absl::nullopt;
- return LogicalKey(key.value().substr(prefix.value().length()));
- }
- // static
- std::unique_ptr<KeyVector> SharedProtoDatabaseClient::PrefixStrings(
- std::unique_ptr<KeyVector> strings,
- const KeyPrefix& prefix) {
- for (auto& str : *strings)
- str.assign(MakePhysicalKey(prefix, LogicalKey(str)).value());
- return strings;
- }
- // static
- bool SharedProtoDatabaseClient::KeyFilterStripPrefix(
- const KeyFilter& key_filter,
- const KeyPrefix& prefix,
- const PhysicalKey& key) {
- if (key_filter.is_null())
- return true;
- absl::optional<LogicalKey> stripped = StripPrefix(key, prefix);
- if (!stripped)
- return false;
- return key_filter.Run(stripped->value());
- }
- // static
- bool SharedProtoDatabaseClient::KeyStringFilterStripPrefix(
- const KeyFilter& key_filter,
- const KeyPrefix& prefix,
- const std::string& key) {
- return KeyFilterStripPrefix(key_filter, prefix, PhysicalKey(key));
- }
- // static
- Enums::KeyIteratorAction
- SharedProtoDatabaseClient::KeyIteratorControllerStripPrefix(
- const KeyIteratorController& controller,
- const KeyPrefix& prefix,
- const PhysicalKey& key) {
- DCHECK(!controller.is_null());
- absl::optional<LogicalKey> stripped = StripPrefix(key, prefix);
- if (!stripped)
- return Enums::kSkipAndStop;
- return controller.Run(stripped->value());
- }
- // static
- Enums::KeyIteratorAction
- SharedProtoDatabaseClient::KeyStringIteratorControllerStripPrefix(
- const KeyIteratorController& controller,
- const KeyPrefix& prefix,
- const std::string& key) {
- return KeyIteratorControllerStripPrefix(controller, prefix, PhysicalKey(key));
- }
- // static
- void SharedProtoDatabaseClient::GetSharedDatabaseInitStatusAsync(
- const std::string& client_db_id,
- const scoped_refptr<SharedProtoDatabase>& shared_db,
- Callbacks::InitStatusCallback callback) {
- shared_db->GetDatabaseInitStatusAsync(client_db_id, std::move(callback));
- }
- // static
- void SharedProtoDatabaseClient::UpdateClientMetadataAsync(
- const scoped_refptr<SharedProtoDatabase>& shared_db,
- const std::string& client_db_id,
- SharedDBMetadataProto::MigrationStatus migration_status,
- ClientCorruptCallback callback) {
- shared_db->UpdateClientMetadataAsync(client_db_id, migration_status,
- std::move(callback));
- }
- // static
- void SharedProtoDatabaseClient::DestroyObsoleteSharedProtoDatabaseClients(
- std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
- Callbacks::UpdateCallback callback) {
- ProtoLevelDBWrapper* db_wrapper_ptr = db_wrapper.get();
- scoped_refptr<ObsoleteClientsDbHolder> db_holder =
- new ObsoleteClientsDbHolder(std::move(db_wrapper), std::move(callback));
- const ProtoDbType* list = g_obsolete_client_list_for_testing
- ? g_obsolete_client_list_for_testing
- : kObsoleteSharedProtoDbTypeClients;
- for (size_t i = 0; list[i] != ProtoDbType::LAST; ++i) {
- // Callback keeps a ref pointer to db_holder alive till the changes are
- // done. |db_holder| will be destroyed once all the RemoveKeys() calls
- // return.
- Callbacks::UpdateCallback callback_wrapper =
- base::BindOnce([](scoped_refptr<ObsoleteClientsDbHolder> db_holder,
- bool success) { db_holder->set_success(success); },
- db_holder);
- // Remove all type prefixes for the client.
- // TODO(ssid): Support cleanup of namespaces for clients. This code assumes
- // the prefix contains the client namespace at the beginning.
- db_wrapper_ptr->RemoveKeys(
- base::BindRepeating([](const std::string& key) { return true; }),
- SharedProtoDatabaseClient::PrefixForDatabase(list[i]).value(),
- std::move(callback_wrapper));
- }
- }
- // static
- void SharedProtoDatabaseClient::SetObsoleteClientListForTesting(
- const ProtoDbType* list) {
- g_obsolete_client_list_for_testing = list;
- }
- // static
- KeyPrefix SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType db_type) {
- return KeyPrefix(base::StringPrintf("%d_", static_cast<int>(db_type)));
- }
- SharedProtoDatabaseClient::SharedProtoDatabaseClient(
- std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
- ProtoDbType db_type,
- const scoped_refptr<SharedProtoDatabase>& parent_db)
- : UniqueProtoDatabase(std::move(db_wrapper)),
- prefix_(PrefixForDatabase(db_type)),
- parent_db_(parent_db) {
- DETACH_FROM_SEQUENCE(sequence_checker_);
- }
- SharedProtoDatabaseClient::~SharedProtoDatabaseClient() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
- void SharedProtoDatabaseClient::Init(const std::string& client_uma_name,
- Callbacks::InitStatusCallback callback) {
- SetMetricsId(client_uma_name);
- GetSharedDatabaseInitStatusAsync(client_db_id(), parent_db_,
- std::move(callback));
- }
- void SharedProtoDatabaseClient::InitWithDatabase(
- LevelDB* database,
- const base::FilePath& database_dir,
- const leveldb_env::Options& options,
- bool destroy_on_corruption,
- Callbacks::InitStatusCallback callback) {
- NOTREACHED();
- }
- void SharedProtoDatabaseClient::UpdateEntries(
- std::unique_ptr<KeyValueVector> entries_to_save,
- std::unique_ptr<KeyVector> keys_to_remove,
- Callbacks::UpdateCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::UpdateEntries(
- PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
- PrefixStrings(std::move(keys_to_remove), prefix_), std::move(callback));
- }
- void SharedProtoDatabaseClient::UpdateEntriesWithRemoveFilter(
- std::unique_ptr<KeyValueVector> entries_to_save,
- const KeyFilter& delete_key_filter,
- Callbacks::UpdateCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
- std::string(), std::move(callback));
- }
- void SharedProtoDatabaseClient::UpdateEntriesWithRemoveFilter(
- std::unique_ptr<KeyValueVector> entries_to_save,
- const KeyFilter& delete_key_filter,
- const std::string& target_prefix,
- Callbacks::UpdateCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::UpdateEntriesWithRemoveFilter(
- PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
- base::BindRepeating(&KeyStringFilterStripPrefix, delete_key_filter,
- prefix_),
- MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
- std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadEntries(Callbacks::LoadCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- LoadEntriesWithFilter(KeyFilter(), std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadEntriesWithFilter(
- const KeyFilter& filter,
- Callbacks::LoadCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- LoadEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
- std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadEntriesWithFilter(
- const KeyFilter& filter,
- const leveldb::ReadOptions& options,
- const std::string& target_prefix,
- Callbacks::LoadCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::LoadEntriesWithFilter(
- base::BindRepeating(&KeyStringFilterStripPrefix, filter, prefix_),
- options, MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
- std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadKeys(Callbacks::LoadKeysCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- LoadKeys(std::string(), std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadKeys(const std::string& target_prefix,
- Callbacks::LoadKeysCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::LoadKeys(
- MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
- base::BindOnce(&SharedProtoDatabaseClient::StripPrefixLoadKeysCallback,
- std::move(callback), prefix_));
- }
- void SharedProtoDatabaseClient::LoadKeysAndEntries(
- Callbacks::LoadKeysAndEntriesCallback callback) {
- LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadKeysAndEntriesWithFilter(
- const KeyFilter& filter,
- Callbacks::LoadKeysAndEntriesCallback callback) {
- LoadKeysAndEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
- std::move(callback));
- }
- void SharedProtoDatabaseClient::LoadKeysAndEntriesWithFilter(
- const KeyFilter& filter,
- const leveldb::ReadOptions& options,
- const std::string& target_prefix,
- Callbacks::LoadKeysAndEntriesCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::LoadKeysAndEntriesWithFilter(
- base::BindRepeating(&KeyStringFilterStripPrefix, filter, prefix_),
- options, MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
- base::BindOnce(
- &SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
- std::move(callback), prefix_));
- }
- void SharedProtoDatabaseClient::LoadKeysAndEntriesInRange(
- const std::string& start,
- const std::string& end,
- Callbacks::LoadKeysAndEntriesCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::LoadKeysAndEntriesInRange(
- MakePhysicalKey(prefix_, LogicalKey(start)).value(),
- MakePhysicalKey(prefix_, LogicalKey(end)).value(),
- base::BindOnce(
- &SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
- std::move(callback), prefix_));
- }
- void SharedProtoDatabaseClient::LoadKeysAndEntriesWhile(
- const std::string& start,
- const leveldb_proto::KeyIteratorController& controller,
- Callbacks::LoadKeysAndEntriesCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::LoadKeysAndEntriesWhile(
- MakePhysicalKey(prefix_, LogicalKey(start)).value(),
- base::BindRepeating(&KeyStringIteratorControllerStripPrefix, controller,
- prefix_),
- base::BindOnce(
- &SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
- std::move(callback), prefix_));
- }
- void SharedProtoDatabaseClient::GetEntry(const std::string& key,
- Callbacks::GetCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::GetEntry(
- MakePhysicalKey(prefix_, LogicalKey(key)).value(), std::move(callback));
- }
- void SharedProtoDatabaseClient::Destroy(Callbacks::DestroyCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UpdateEntriesWithRemoveFilter(
- std::make_unique<KeyValueVector>(),
- base::BindRepeating([](const std::string& key) { return true; }),
- base::BindOnce([](Callbacks::DestroyCallback callback,
- bool success) { std::move(callback).Run(success); },
- std::move(callback)));
- }
- void SharedProtoDatabaseClient::UpdateClientInitMetadata(
- SharedDBMetadataProto::MigrationStatus migration_status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- migration_status_ = migration_status;
- // Tell the SharedProtoDatabase that we've seen the corruption state so it's
- // safe to update its records for this client.
- UpdateClientMetadataAsync(parent_db_, client_db_id(), migration_status_,
- base::BindOnce([](bool success) {
- // TODO(thildebr): Should we do anything special
- // here? If the shared DB can't update the
- // client's corruption counter to match its own,
- // then the client will think it's corrupt on the
- // next Init as well.
- }));
- }
- // static
- void SharedProtoDatabaseClient::StripPrefixLoadKeysCallback(
- Callbacks::LoadKeysCallback callback,
- const KeyPrefix& prefix,
- bool success,
- std::unique_ptr<leveldb_proto::KeyVector> keys) {
- auto stripped_keys = std::make_unique<leveldb_proto::KeyVector>();
- for (auto& key : *keys) {
- absl::optional<LogicalKey> stripped = StripPrefix(PhysicalKey(key), prefix);
- if (!stripped)
- continue;
- stripped_keys->emplace_back(stripped->value());
- }
- std::move(callback).Run(success, std::move(stripped_keys));
- }
- // static
- void SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback(
- Callbacks::LoadKeysAndEntriesCallback callback,
- const KeyPrefix& prefix,
- bool success,
- std::unique_ptr<KeyValueMap> keys_entries) {
- auto stripped_keys_map = std::make_unique<KeyValueMap>();
- for (auto& key_entry : *keys_entries) {
- absl::optional<LogicalKey> stripped_key =
- StripPrefix(PhysicalKey(key_entry.first), prefix);
- if (!stripped_key)
- continue;
- stripped_keys_map->insert(
- std::make_pair(stripped_key->value(), key_entry.second));
- }
- std::move(callback).Run(success, std::move(stripped_keys_map));
- }
- // static
- std::unique_ptr<KeyValueVector> SharedProtoDatabaseClient::PrefixKeyEntryVector(
- std::unique_ptr<KeyValueVector> kev,
- const KeyPrefix& prefix) {
- for (auto& key_entry_pair : *kev) {
- key_entry_pair.first =
- MakePhysicalKey(prefix, LogicalKey(key_entry_pair.first)).value();
- }
- return kev;
- }
- } // namespace leveldb_proto
|