Commit 01f313e6 authored by Salvador Guerrero's avatar Salvador Guerrero Committed by Commit Bot

Fixed Destroy method on unique proto databases that failed to initialize

Some leveldb_proto clients attempt to destroy their database when it
fails to initialize, this would fail because we needed to have an
initialized instance in order to destroy it.

This change calls the static method leveldb::DestroyDB which will try
to erase the database directory. This will ensure that clients using a
DB selector will be able to recover from a failed initialization

Renamed wrapper to DB impl on proto_database_impl_unittest to match new
class name

Bug: 870813
Change-Id: I9cbf4482cde132f68abeecb3b210c289bba0b1b2
Reviewed-on: https://chromium-review.googlesource.com/c/1484086
Commit-Queue: Salvador Guerrero <salg@google.com>
Reviewed-by: default avatarssid <ssid@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635839}
parent d8fc62f5
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "components/leveldb_proto/internal/proto_database_impl.h" #include "components/leveldb_proto/internal/proto_database_impl.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
...@@ -114,7 +115,7 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -114,7 +115,7 @@ class ProtoDatabaseImplTest : public testing::Test {
shared_db_temp_dir_.reset(); shared_db_temp_dir_.reset();
} }
std::unique_ptr<ProtoDatabaseImpl<TestProto>> CreateWrapper( std::unique_ptr<ProtoDatabaseImpl<TestProto>> CreateDBImpl(
ProtoDbType db_type, ProtoDbType db_type,
const base::FilePath& db_dir, const base::FilePath& db_dir,
const scoped_refptr<base::SequencedTaskRunner>& task_runner, const scoped_refptr<base::SequencedTaskRunner>& task_runner,
...@@ -153,20 +154,20 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -153,20 +154,20 @@ class ProtoDatabaseImplTest : public testing::Test {
// Uses ProtoDatabaseImpl's 3 parameter Init to bypass the check that gets // Uses ProtoDatabaseImpl's 3 parameter Init to bypass the check that gets
// |use_shared_db|'s value. // |use_shared_db|'s value.
void InitWrapper(ProtoDatabaseImpl<TestProto>* wrapper, void InitDBImpl(ProtoDatabaseImpl<TestProto>* db_impl,
const std::string& client_name, const std::string& client_name,
bool use_shared_db, bool use_shared_db,
Callbacks::InitStatusCallback callback) { Callbacks::InitStatusCallback callback) {
wrapper->Init(client_name, use_shared_db, std::move(callback)); db_impl->Init(client_name, use_shared_db, std::move(callback));
} }
void InitWrapperAndWait(ProtoDatabaseImpl<TestProto>* wrapper, void InitDBImplAndWait(ProtoDatabaseImpl<TestProto>* db_impl,
const std::string& client_name, const std::string& client_name,
bool use_shared_db, bool use_shared_db,
Enums::InitStatus expect_status) { Enums::InitStatus expect_status) {
base::RunLoop init_loop; base::RunLoop init_loop;
InitWrapper( InitDBImpl(
wrapper, client_name, use_shared_db, db_impl, client_name, use_shared_db,
base::BindOnce( base::BindOnce(
[](base::OnceClosure closure, Enums::InitStatus expect_status, [](base::OnceClosure closure, Enums::InitStatus expect_status,
Enums::InitStatus status) { Enums::InitStatus status) {
...@@ -214,8 +215,8 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -214,8 +215,8 @@ class ProtoDatabaseImplTest : public testing::Test {
// Just uses each entry's key to fill out the id/data fields in TestProto as // Just uses each entry's key to fill out the id/data fields in TestProto as
// well. // well.
void AddDataToWrapper(ProtoDatabaseImpl<TestProto>* wrapper, void AddDataToDBImpl(ProtoDatabaseImpl<TestProto>* db_impl,
std::vector<std::string>* entry_keys) { std::vector<std::string>* entry_keys) {
auto data_set = auto data_set =
std::make_unique<std::vector<std::pair<std::string, TestProto>>>(); std::make_unique<std::vector<std::pair<std::string, TestProto>>>();
for (const auto& key : *entry_keys) { for (const auto& key : *entry_keys) {
...@@ -226,7 +227,7 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -226,7 +227,7 @@ class ProtoDatabaseImplTest : public testing::Test {
} }
base::RunLoop data_loop; base::RunLoop data_loop;
wrapper->UpdateEntries(std::move(data_set), db_impl->UpdateEntries(std::move(data_set),
std::make_unique<std::vector<std::string>>(), std::make_unique<std::vector<std::string>>(),
base::BindOnce( base::BindOnce(
[](base::OnceClosure closure, bool success) { [](base::OnceClosure closure, bool success) {
...@@ -237,10 +238,10 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -237,10 +238,10 @@ class ProtoDatabaseImplTest : public testing::Test {
data_loop.Run(); data_loop.Run();
} }
void VerifyDataInWrapper(ProtoDatabaseImpl<TestProto>* wrapper, void VerifyDataInDBImpl(ProtoDatabaseImpl<TestProto>* db_impl,
std::vector<std::string>* entry_keys) { std::vector<std::string>* entry_keys) {
base::RunLoop load_loop; base::RunLoop load_loop;
wrapper->LoadKeysAndEntries(base::BindOnce( db_impl->LoadKeysAndEntries(base::BindOnce(
[](base::OnceClosure closure, std::vector<std::string>* entry_keys, [](base::OnceClosure closure, std::vector<std::string>* entry_keys,
bool success, bool success,
std::unique_ptr<std::map<std::string, TestProto>> keys_entries) { std::unique_ptr<std::map<std::string, TestProto>> keys_entries) {
...@@ -322,11 +323,11 @@ class ProtoDatabaseImplTest : public testing::Test { ...@@ -322,11 +323,11 @@ class ProtoDatabaseImplTest : public testing::Test {
TEST_F(ProtoDatabaseImplTest, FailsBothDatabases) { TEST_F(ProtoDatabaseImplTest, FailsBothDatabases) {
auto db_provider = CreateProviderNoSharedDB(); auto db_provider = CreateProviderNoSharedDB();
auto shared_db_provider = CreateSharedProvider(db_provider.get()); auto shared_db_provider = CreateSharedProvider(db_provider.get());
auto wrapper = CreateWrapper(ProtoDbType::TEST_DATABASE1, temp_dir(), auto db_impl = CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir(),
GetTestThreadTaskRunner(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider.get())); CreateSharedProvider(db_provider.get()));
InitWrapperAndWait(wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kError); Enums::InitStatus::kError);
} }
TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) { TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) {
...@@ -342,7 +343,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) { ...@@ -342,7 +343,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) {
true, // We should be using a shared DB. true, // We should be using a shared DB.
nullptr, // Shared DB failed to open. nullptr, // Shared DB failed to open.
Enums::InitStatus::kError, // Shared DB had an IO error. Enums::InitStatus::kError, // Shared DB had an IO error.
Enums::InitStatus::kError); // Then the wrapper should return an error. Enums::InitStatus::kError); // Then the DB impl should return an error.
CallOnGetSharedDBClientAndWait( CallOnGetSharedDBClientAndWait(
std::move(unique_db), // Unique DB opens fine. std::move(unique_db), // Unique DB opens fine.
...@@ -350,7 +351,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) { ...@@ -350,7 +351,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB) {
true, // We should be using a shared DB. true, // We should be using a shared DB.
nullptr, // Shared DB failed to open. nullptr, // Shared DB failed to open.
Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist. Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist.
Enums::InitStatus::kError); // Then the wrapper should return an error. Enums::InitStatus::kError); // Then the DB impl should return an error.
} }
TEST_F(ProtoDatabaseImplTest, TEST_F(ProtoDatabaseImplTest,
...@@ -370,7 +371,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -370,7 +371,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kOK); // Then the wrapper should return the shared DB. Enums::InitStatus::kOK); // Then the DB impl should return the shared DB.
} }
TEST_F(ProtoDatabaseImplTest, Fails_UseShared_HasSharedDB_UniqueHadIOError) { TEST_F(ProtoDatabaseImplTest, Fails_UseShared_HasSharedDB_UniqueHadIOError) {
...@@ -389,7 +390,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_HasSharedDB_UniqueHadIOError) { ...@@ -389,7 +390,7 @@ TEST_F(ProtoDatabaseImplTest, Fails_UseShared_HasSharedDB_UniqueHadIOError) {
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kError); // Then the wrapper should return an error. Enums::InitStatus::kError); // Then the DB impl should return an error.
} }
TEST_F(ProtoDatabaseImplTest, TEST_F(ProtoDatabaseImplTest,
...@@ -409,7 +410,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -409,7 +410,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kOK); // Then the wrapper should use the shared DB. Enums::InitStatus::kOK); // Then the DB impl should use the shared DB.
shared_db_client = GetSharedClient(); shared_db_client = GetSharedClient();
...@@ -427,7 +428,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -427,7 +428,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kOK); // Then the wrapper should use the shared DB. Enums::InitStatus::kOK); // Then the DB impl should use the shared DB.
} }
TEST_F(ProtoDatabaseImplTest, TEST_F(ProtoDatabaseImplTest,
...@@ -447,7 +448,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -447,7 +448,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kError); // Then the wrapper should throw an error. Enums::InitStatus::kError); // Then the DB impl should throw an error.
shared_db_client = GetSharedClient(); shared_db_client = GetSharedClient();
...@@ -464,7 +465,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -464,7 +465,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kError); // Then the wrapper should throw an error. Enums::InitStatus::kError); // Then the DB impl should throw an error.
} }
TEST_F(ProtoDatabaseImplTest, TEST_F(ProtoDatabaseImplTest,
...@@ -483,7 +484,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -483,7 +484,7 @@ TEST_F(ProtoDatabaseImplTest,
false, // We should be using a unique DB. false, // We should be using a unique DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kOK); // Then the wrapper should use the shared DB. Enums::InitStatus::kOK); // Then the DB impl should use the shared DB.
shared_db_client = GetSharedClient(); shared_db_client = GetSharedClient();
...@@ -500,7 +501,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -500,7 +501,7 @@ TEST_F(ProtoDatabaseImplTest,
true, // We should be using a shared DB. true, // We should be using a shared DB.
std::move(shared_db_client), // Shared DB opens fine. std::move(shared_db_client), // Shared DB opens fine.
Enums::InitStatus::kOK, Enums::InitStatus::kOK,
Enums::InitStatus::kOK); // Then the wrapper should use the shared DB. Enums::InitStatus::kOK); // Then the DB impl should use the shared DB.
} }
TEST_F(ProtoDatabaseImplTest, TEST_F(ProtoDatabaseImplTest,
...@@ -516,7 +517,7 @@ TEST_F(ProtoDatabaseImplTest, ...@@ -516,7 +517,7 @@ TEST_F(ProtoDatabaseImplTest,
false, // We should be using a unique DB. false, // We should be using a unique DB.
nullptr, // Shared DB failed to open. nullptr, // Shared DB failed to open.
Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist. Enums::InitStatus::kInvalidOperation, // Shared DB doesn't exist.
Enums::InitStatus::kOK); // Then the wrapper should return the unique DB. Enums::InitStatus::kOK); // Then the DB impl should return the unique DB.
} }
TEST_F(ProtoDatabaseImplTest, Fails_DontUseShared_SharedDBFailed) { TEST_F(ProtoDatabaseImplTest, Fails_DontUseShared_SharedDBFailed) {
...@@ -532,36 +533,36 @@ TEST_F(ProtoDatabaseImplTest, Fails_DontUseShared_SharedDBFailed) { ...@@ -532,36 +533,36 @@ TEST_F(ProtoDatabaseImplTest, Fails_DontUseShared_SharedDBFailed) {
false, // We should be using a unique DB. false, // We should be using a unique DB.
nullptr, // Shared DB failed to open. nullptr, // Shared DB failed to open.
Enums::InitStatus::kError, // Shared DB had an IO error. Enums::InitStatus::kError, // Shared DB had an IO error.
Enums::InitStatus::kError); // Then the wrapper should return an error. Enums::InitStatus::kError); // Then the DB impl should return an error.
} }
TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB_NoUniqueDB) { TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB_NoUniqueDB) {
auto db_provider = CreateProviderNoSharedDB(); auto db_provider = CreateProviderNoSharedDB();
auto wrapper = CreateWrapper(ProtoDbType::TEST_DATABASE1, temp_dir(), auto db_impl = CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir(),
GetTestThreadTaskRunner(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider.get())); CreateSharedProvider(db_provider.get()));
InitWrapperAndWait(wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kError); Enums::InitStatus::kError);
} }
// Migration tests: // Migration tests:
TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) { TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) {
// First we create a unique DB so our second pass has a unique DB available. // First we create a unique DB so our second pass has a unique DB available.
auto db_provider_noshared = CreateProviderNoSharedDB(); auto db_provider_noshared = CreateProviderNoSharedDB();
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_noshared.get())); CreateSharedProvider(db_provider_noshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// Kill the wrapper so it doesn't have a lock on the DB anymore. // Kill the DB impl so it doesn't have a lock on the DB anymore.
unique_wrapper.reset(); unique_db_impl.reset();
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
...@@ -570,22 +571,22 @@ TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) { ...@@ -570,22 +571,22 @@ TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) {
TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_SharedToUnique) { TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_SharedToUnique) {
// First we create a unique DB so our second pass has a unique DB available. // First we create a unique DB so our second pass has a unique DB available.
auto db_provider = CreateProviderWithSharedDB(); auto db_provider = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper(ProtoDbType::TEST_DATABASE1, temp_dir(), auto shared_db_impl = CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir(),
GetTestThreadTaskRunner(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider.get())); CreateSharedProvider(db_provider.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// As the unique DB doesn't exist then the wrapper sets the migration status // As the unique DB doesn't exist then the DB impl sets the migration status
// to migrated to shared. // to migrated to shared.
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
auto unique_wrapper = CreateWrapper(ProtoDbType::TEST_DATABASE1, temp_dir(), auto unique_db_impl = CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir(),
GetTestThreadTaskRunner(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider.get())); CreateSharedProvider(db_provider.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
...@@ -598,22 +599,22 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared) { ...@@ -598,22 +599,22 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared) {
// First we create a unique DB so our second pass has a unique DB available. // First we create a unique DB so our second pass has a unique DB available.
auto db_provider_noshared = CreateProviderNoSharedDB(); auto db_provider_noshared = CreateProviderNoSharedDB();
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_noshared.get())); CreateSharedProvider(db_provider_noshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(unique_wrapper.get(), data_set.get()); AddDataToDBImpl(unique_db_impl.get(), data_set.get());
// Kill the wrapper so it doesn't have a lock on the DB anymore. // Kill the DB impl so it doesn't have a lock on the DB anymore.
unique_wrapper.reset(); unique_db_impl.reset();
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
VerifyDataInWrapper(shared_wrapper.get(), data_set.get()); VerifyDataInDBImpl(shared_db_impl.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
...@@ -627,24 +628,24 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique) { ...@@ -627,24 +628,24 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique) {
// First we create a shared DB so our second pass has a shared DB available. // First we create a shared DB so our second pass has a shared DB available.
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(shared_wrapper.get(), data_set.get()); AddDataToDBImpl(shared_db_impl.get(), data_set.get());
// As the unique DB doesn't exist then the wrapper sets the migration status // As the unique DB doesn't exist then the DB impl sets the migration status
// is set to migrated to shared. // to migrated to shared.
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
VerifyDataInWrapper(unique_wrapper.get(), data_set.get()); VerifyDataInDBImpl(unique_db_impl.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
...@@ -657,28 +658,28 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_UniqueObsolete) { ...@@ -657,28 +658,28 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_UniqueObsolete) {
// First we create a unique DB so our second pass has a unique DB available. // First we create a unique DB so our second pass has a unique DB available.
auto db_provider_noshared = CreateProviderNoSharedDB(); auto db_provider_noshared = CreateProviderNoSharedDB();
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_noshared.get())); CreateSharedProvider(db_provider_noshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(unique_wrapper.get(), data_set.get()); AddDataToDBImpl(unique_db_impl.get(), data_set.get());
// Kill the wrapper so it doesn't have a lock on the DB anymore. // Kill the DB impl so it doesn't have a lock on the DB anymore.
unique_wrapper.reset(); unique_db_impl.reset();
UpdateClientMetadata( UpdateClientMetadata(
SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// Unique DB should be deleted in migration. So, shared DB should be clean. // Unique DB should be deleted in migration. So, shared DB should be clean.
data_set->clear(); data_set->clear();
VerifyDataInWrapper(shared_wrapper.get(), data_set.get()); VerifyDataInDBImpl(shared_db_impl.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
...@@ -691,42 +692,42 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_SharedObsolete) { ...@@ -691,42 +692,42 @@ TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_SharedObsolete) {
// First we create a shared DB so our second pass has a shared DB available. // First we create a shared DB so our second pass has a shared DB available.
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(shared_wrapper.get(), data_set.get()); AddDataToDBImpl(shared_db_impl.get(), data_set.get());
// As there's no unique DB, the wrapper is going to set the state to migrated // As there's no unique DB, the DB impl is going to set the state to migrated
// to shared. // to shared.
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
// Force create an unique DB, which was deleted by migration. // Force create an unique DB, which was deleted by migration.
auto db_provider_noshared = CreateProviderNoSharedDB(); auto db_provider_noshared = CreateProviderNoSharedDB();
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_noshared.get())); CreateSharedProvider(db_provider_noshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
unique_wrapper.reset(); unique_db_impl.reset();
UpdateClientMetadata( UpdateClientMetadata(
SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED); SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
shared_wrapper.reset(); shared_db_impl.reset();
db_provider_withshared = CreateProviderWithSharedDB(); db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper1 = CreateWrapper( auto shared_db_impl1 = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper1.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl1.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// Shared DB should be deleted in migration. So, shared DB should be clean. // Shared DB should be deleted in migration. So, shared DB should be clean.
data_set->clear(); data_set->clear();
VerifyDataInWrapper(shared_wrapper1.get(), data_set.get()); VerifyDataInDBImpl(shared_db_impl1.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
...@@ -739,14 +740,14 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) { ...@@ -739,14 +740,14 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) {
// First we create a shared DB so our second pass has a shared DB available. // First we create a shared DB so our second pass has a shared DB available.
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, true, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(shared_wrapper.get(), data_set.get()); AddDataToDBImpl(shared_db_impl.get(), data_set.get());
// As there's no Unique DB, the wrapper changes the migration status to // As there's no Unique DB, the DB impl changes the migration status to
// migrated to shared. // migrated to shared.
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
...@@ -754,15 +755,15 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) { ...@@ -754,15 +755,15 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) {
UpdateClientMetadata( UpdateClientMetadata(
SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED); SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// Shared DB should be deleted in migration. So, unique DB should be clean. // Shared DB should be deleted in migration. So, unique DB should be clean.
data_set->clear(); data_set->clear();
VerifyDataInWrapper(unique_wrapper.get(), data_set.get()); VerifyDataInDBImpl(unique_db_impl.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
...@@ -775,30 +776,60 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_UniqueObsolete) { ...@@ -775,30 +776,60 @@ TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_UniqueObsolete) {
// First we create a shared DB so our second pass has a shared DB available. // First we create a shared DB so our second pass has a shared DB available.
auto db_provider_noshared = CreateProviderNoSharedDB(); auto db_provider_noshared = CreateProviderNoSharedDB();
auto unique_wrapper = CreateWrapper( auto unique_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_noshared.get())); CreateSharedProvider(db_provider_noshared.get()));
InitWrapperAndWait(unique_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(unique_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
AddDataToWrapper(unique_wrapper.get(), data_set.get()); AddDataToDBImpl(unique_db_impl.get(), data_set.get());
UpdateClientMetadata( UpdateClientMetadata(
SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED); SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
unique_wrapper.reset(); unique_db_impl.reset();
auto db_provider_withshared = CreateProviderWithSharedDB(); auto db_provider_withshared = CreateProviderWithSharedDB();
auto shared_wrapper = CreateWrapper( auto shared_db_impl = CreateDBImpl(
ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(), ProtoDbType::TEST_DATABASE1, temp_dir(), GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider_withshared.get())); CreateSharedProvider(db_provider_withshared.get()));
InitWrapperAndWait(shared_wrapper.get(), kDefaultClientName, false, InitDBImplAndWait(shared_db_impl.get(), kDefaultClientName, false,
Enums::InitStatus::kOK); Enums::InitStatus::kOK);
// Unique DB should be deleted in migration. So, unique DB should be clean. // Unique DB should be deleted in migration. So, unique DB should be clean.
data_set->clear(); data_set->clear();
VerifyDataInWrapper(shared_wrapper.get(), data_set.get()); VerifyDataInDBImpl(shared_db_impl.get(), data_set.get());
EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL, EXPECT_EQ(SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL,
GetClientMigrationStatus()); GetClientMigrationStatus());
} }
TEST_F(ProtoDatabaseImplTest, DestroyShouldWorkWhenUniqueInitFailed) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
auto db_provider = CreateProviderNoSharedDB();
auto shared_db_provider = CreateSharedProvider(db_provider.get());
auto db_impl = CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir.GetPath(),
GetTestThreadTaskRunner(),
CreateSharedProvider(db_provider.get()));
// Try to initialize a db and fail.
InitDBImplAndWait(db_impl.get(), kDefaultClientName, true,
Enums::InitStatus::kError);
base::RunLoop run_destroy;
// Call destroy on the db, it should destroy the db directory.
db_impl->Destroy(base::BindOnce(
[](base::OnceClosure closure, bool success) {
std::move(closure).Run();
EXPECT_TRUE(success);
},
run_destroy.QuitClosure()));
run_destroy.Run();
// Verify the db is actually destroyed.
EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
}
} // namespace leveldb_proto } // namespace leveldb_proto
\ No newline at end of file
...@@ -51,6 +51,8 @@ void ProtoDatabaseSelector::InitWithDatabase( ...@@ -51,6 +51,8 @@ void ProtoDatabaseSelector::InitWithDatabase(
if (!db_) if (!db_)
db_ = std::make_unique<UniqueProtoDatabase>(task_runner_); db_ = std::make_unique<UniqueProtoDatabase>(task_runner_);
unique_database_dir_ = database_dir;
db_->InitWithDatabase( db_->InitWithDatabase(
database, database_dir, options, false, database, database_dir, options, false,
base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback), base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback),
...@@ -67,16 +69,17 @@ void ProtoDatabaseSelector::InitUniqueOrShared( ...@@ -67,16 +69,17 @@ void ProtoDatabaseSelector::InitUniqueOrShared(
Callbacks::InitStatusCallback callback) { Callbacks::InitStatusCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
init_status_ = InitStatus::IN_PROGRESS; init_status_ = InitStatus::IN_PROGRESS;
unique_database_dir_ = db_dir;
client_name_ = client_name;
auto unique_db = auto unique_db =
std::make_unique<UniqueProtoDatabase>(db_dir, options, task_runner_); std::make_unique<UniqueProtoDatabase>(db_dir, options, task_runner_);
auto* unique_db_ptr = unique_db.get(); auto* unique_db_ptr = unique_db.get();
unique_db_ptr->Init( unique_db_ptr->Init(
client_name.c_str(), client_name, base::BindOnce(&ProtoDatabaseSelector::OnInitUniqueDB, this,
base::BindOnce( std::move(unique_db), use_shared_db,
&ProtoDatabaseSelector::OnInitUniqueDB, this, std::move(unique_db), base::BindOnce(&RunInitCallbackOnTaskRunner,
use_shared_db, std::move(callback),
base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback), callback_task_runner)));
callback_task_runner)));
} }
void ProtoDatabaseSelector::OnInitUniqueDB( void ProtoDatabaseSelector::OnInitUniqueDB(
...@@ -535,9 +538,16 @@ void ProtoDatabaseSelector::GetEntry(const std::string& key, ...@@ -535,9 +538,16 @@ void ProtoDatabaseSelector::GetEntry(const std::string& key,
void ProtoDatabaseSelector::Destroy(Callbacks::DestroyCallback callback) { void ProtoDatabaseSelector::Destroy(Callbacks::DestroyCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!db_) { if (!db_) {
if (!unique_database_dir_.empty()) {
ProtoLevelDBWrapper::Destroy(unique_database_dir_, client_name_,
task_runner_, std::move(callback));
return;
}
std::move(callback).Run(false); std::move(callback).Run(false);
return; return;
} }
db_->Destroy(std::move(callback)); db_->Destroy(std::move(callback));
} }
......
...@@ -161,6 +161,8 @@ class ProtoDatabaseSelector ...@@ -161,6 +161,8 @@ class ProtoDatabaseSelector
InitStatus init_status_ = InitStatus::NOT_STARTED; InitStatus init_status_ = InitStatus::NOT_STARTED;
base::queue<base::OnceClosure> pending_tasks_; base::queue<base::OnceClosure> pending_tasks_;
std::unique_ptr<UniqueProtoDatabase> db_; std::unique_ptr<UniqueProtoDatabase> db_;
base::FilePath unique_database_dir_;
std::string client_name_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
}; };
......
...@@ -44,6 +44,18 @@ bool DestroyFromTaskRunner(LevelDB* database, const std::string& client_id) { ...@@ -44,6 +44,18 @@ bool DestroyFromTaskRunner(LevelDB* database, const std::string& client_id) {
return success; return success;
} }
bool DestroyWithDirectoryFromTaskRunner(const base::FilePath& db_dir,
const std::string& client_id) {
leveldb::Status result = leveldb::DestroyDB(
db_dir.AsUTF8Unsafe(), leveldb_proto::CreateSimpleOptions());
bool success = result.ok();
if (!client_id.empty())
ProtoLevelDBWrapperMetrics::RecordDestroy(client_id, success);
return success;
}
void LoadKeysFromTaskRunner( void LoadKeysFromTaskRunner(
LevelDB* database, LevelDB* database,
const std::string& target_prefix, const std::string& target_prefix,
...@@ -376,6 +388,17 @@ void ProtoLevelDBWrapper::Destroy(Callbacks::DestroyCallback callback) { ...@@ -376,6 +388,17 @@ void ProtoLevelDBWrapper::Destroy(Callbacks::DestroyCallback callback) {
std::move(callback)); std::move(callback));
} }
void ProtoLevelDBWrapper::Destroy(
const base::FilePath& db_dir,
const std::string& client_id,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
Callbacks::DestroyCallback callback) {
base::PostTaskAndReplyWithResult(
task_runner.get(), FROM_HERE,
base::BindOnce(DestroyWithDirectoryFromTaskRunner, db_dir, client_id),
std::move(callback));
}
void ProtoLevelDBWrapper::SetMetricsId(const std::string& id) { void ProtoLevelDBWrapper::SetMetricsId(const std::string& id) {
metrics_id_ = id; metrics_id_ = id;
} }
......
...@@ -40,6 +40,13 @@ using ValueVector = std::vector<std::string>; ...@@ -40,6 +40,13 @@ using ValueVector = std::vector<std::string>;
// Construction/calls/destruction should all happen on the same thread. // Construction/calls/destruction should all happen on the same thread.
class ProtoLevelDBWrapper { class ProtoLevelDBWrapper {
public: public:
// Used to destroy database when initialization fails.
static void Destroy(
const base::FilePath& db_dir,
const std::string& client_id,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
Callbacks::DestroyCallback callback);
// All blocking calls/disk access will happen on the provided |task_runner|. // All blocking calls/disk access will happen on the provided |task_runner|.
ProtoLevelDBWrapper( ProtoLevelDBWrapper(
const scoped_refptr<base::SequencedTaskRunner>& task_runner); const scoped_refptr<base::SequencedTaskRunner>& task_runner);
......
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