Commit 7f0cff2a authored by Min Qin's avatar Min Qin Committed by Commit Bot

Allow proto database to filter returned entries on key

This CL allows proto db to take a filter to filter out returned entries
Test is also included.
This will facilitate the in-progress download database work.

BUG=842245

Change-Id: I63426527743811ab31560e74a8dc45f922333a00
Reviewed-on: https://chromium-review.googlesource.com/1067149
Commit-Queue: Min Qin <qinmin@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561590}
parent 86ed62be
...@@ -100,6 +100,11 @@ bool LevelDB::Save(const base::StringPairs& entries_to_save, ...@@ -100,6 +100,11 @@ bool LevelDB::Save(const base::StringPairs& entries_to_save,
} }
bool LevelDB::Load(std::vector<std::string>* entries) { bool LevelDB::Load(std::vector<std::string>* entries) {
return LoadWithFilter(KeyFilter(), entries);
}
bool LevelDB::LoadWithFilter(const KeyFilter& filter,
std::vector<std::string>* entries) {
DFAKE_SCOPED_LOCK(thread_checker_); DFAKE_SCOPED_LOCK(thread_checker_);
if (!db_) if (!db_)
return false; return false;
...@@ -107,6 +112,11 @@ bool LevelDB::Load(std::vector<std::string>* entries) { ...@@ -107,6 +112,11 @@ bool LevelDB::Load(std::vector<std::string>* entries) {
leveldb::ReadOptions options; leveldb::ReadOptions options;
std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options)); std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) { for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
if (!filter.is_null()) {
leveldb::Slice key_slice = db_iterator->key();
if (!filter.Run(std::string(key_slice.data(), key_slice.size())))
continue;
}
leveldb::Slice value_slice = db_iterator->value(); leveldb::Slice value_slice = db_iterator->value();
std::string entry(value_slice.data(), value_slice.size()); std::string entry(value_slice.data(), value_slice.size());
entries->push_back(entry); entries->push_back(entry);
......
...@@ -40,6 +40,8 @@ class LevelDB { ...@@ -40,6 +40,8 @@ class LevelDB {
explicit LevelDB(const char* client_name); explicit LevelDB(const char* client_name);
virtual ~LevelDB(); virtual ~LevelDB();
using KeyFilter = base::RepeatingCallback<bool(const std::string& key)>;
// Initializes a leveldb with the given options. If |database_dir| is // Initializes a leveldb with the given options. If |database_dir| is
// empty, this opens an in-memory db. // empty, this opens an in-memory db.
virtual bool Init(const base::FilePath& database_dir, virtual bool Init(const base::FilePath& database_dir,
...@@ -48,6 +50,8 @@ class LevelDB { ...@@ -48,6 +50,8 @@ class LevelDB {
virtual bool Save(const base::StringPairs& pairs_to_save, virtual bool Save(const base::StringPairs& pairs_to_save,
const std::vector<std::string>& keys_to_remove); const std::vector<std::string>& keys_to_remove);
virtual bool Load(std::vector<std::string>* entries); virtual bool Load(std::vector<std::string>* entries);
virtual bool LoadWithFilter(const KeyFilter& filter,
std::vector<std::string>* entries);
virtual bool LoadKeys(std::vector<std::string>* keys); virtual bool LoadKeys(std::vector<std::string>* keys);
virtual bool Get(const std::string& key, bool* found, std::string* entry); virtual bool Get(const std::string& key, bool* found, std::string* entry);
// Close (if currently open) and then destroy (i.e. delete) the database // Close (if currently open) and then destroy (i.e. delete) the database
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "components/leveldb_proto/leveldb_database.h"
#include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/env_chromium.h"
namespace base { namespace base {
...@@ -59,6 +60,12 @@ class ProtoDatabase { ...@@ -59,6 +60,12 @@ class ProtoDatabase {
// when complete. // when complete.
virtual void LoadEntries(LoadCallback callback) = 0; virtual void LoadEntries(LoadCallback callback) = 0;
// Asynchronously loads entries that satisfies the |filter| from the database
// and invokes |callback| when complete. The filter will be called on
// ProtoDatabase's taskrunner.
virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter,
LoadCallback callback) = 0;
// Asynchronously loads all keys from the database and invokes |callback| with // Asynchronously loads all keys from the database and invokes |callback| with
// those keys when complete. // those keys when complete.
virtual void LoadKeys(LoadKeysCallback callback) = 0; virtual void LoadKeys(LoadKeysCallback callback) = 0;
......
...@@ -51,6 +51,9 @@ class ProtoDatabaseImpl : public ProtoDatabase<T> { ...@@ -51,6 +51,9 @@ class ProtoDatabaseImpl : public ProtoDatabase<T> {
std::unique_ptr<KeyVector> keys_to_remove, std::unique_ptr<KeyVector> keys_to_remove,
typename ProtoDatabase<T>::UpdateCallback callback) override; typename ProtoDatabase<T>::UpdateCallback callback) override;
void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override; void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadEntriesWithFilter(
const LevelDB::KeyFilter& key_filter,
typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override; void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
void GetEntry(const std::string& key, void GetEntry(const std::string& key,
typename ProtoDatabase<T>::GetCallback callback) override; typename ProtoDatabase<T>::GetCallback callback) override;
...@@ -152,6 +155,7 @@ void UpdateEntriesFromTaskRunner( ...@@ -152,6 +155,7 @@ void UpdateEntriesFromTaskRunner(
template <typename T> template <typename T>
void LoadEntriesFromTaskRunner(LevelDB* database, void LoadEntriesFromTaskRunner(LevelDB* database,
const LevelDB::KeyFilter& filter,
std::vector<T>* entries, std::vector<T>* entries,
bool* success) { bool* success) {
DCHECK(success); DCHECK(success);
...@@ -160,7 +164,7 @@ void LoadEntriesFromTaskRunner(LevelDB* database, ...@@ -160,7 +164,7 @@ void LoadEntriesFromTaskRunner(LevelDB* database,
entries->clear(); entries->clear();
std::vector<std::string> loaded_entries; std::vector<std::string> loaded_entries;
*success = database->Load(&loaded_entries); *success = database->LoadWithFilter(filter, &loaded_entries);
for (const auto& serialized_entry : loaded_entries) { for (const auto& serialized_entry : loaded_entries) {
T entry; T entry;
...@@ -286,6 +290,13 @@ void ProtoDatabaseImpl<T>::UpdateEntries( ...@@ -286,6 +290,13 @@ void ProtoDatabaseImpl<T>::UpdateEntries(
template <typename T> template <typename T>
void ProtoDatabaseImpl<T>::LoadEntries( void ProtoDatabaseImpl<T>::LoadEntries(
typename ProtoDatabase<T>::LoadCallback callback) { typename ProtoDatabase<T>::LoadCallback callback) {
LoadEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
}
template <typename T>
void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
const LevelDB::KeyFilter& key_filter,
typename ProtoDatabase<T>::LoadCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
bool* success = new bool(false); bool* success = new bool(false);
...@@ -296,7 +307,7 @@ void ProtoDatabaseImpl<T>::LoadEntries( ...@@ -296,7 +307,7 @@ void ProtoDatabaseImpl<T>::LoadEntries(
task_runner_->PostTaskAndReply( task_runner_->PostTaskAndReply(
FROM_HERE, FROM_HERE,
base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()), base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
entries_ptr, success), key_filter, entries_ptr, success),
base::BindOnce(RunLoadCallback<T>, std::move(callback), base::BindOnce(RunLoadCallback<T>, std::move(callback),
base::Owned(success), std::move(entries))); base::Owned(success), std::move(entries)));
} }
......
...@@ -53,6 +53,8 @@ class MockDB : public LevelDB { ...@@ -53,6 +53,8 @@ class MockDB : public LevelDB {
const leveldb_env::Options& options)); const leveldb_env::Options& options));
MOCK_METHOD2(Save, bool(const KeyValueVector&, const KeyVector&)); MOCK_METHOD2(Save, bool(const KeyValueVector&, const KeyVector&));
MOCK_METHOD1(Load, bool(std::vector<std::string>*)); MOCK_METHOD1(Load, bool(std::vector<std::string>*));
MOCK_METHOD2(LoadWithFilter,
bool(const KeyFilter&, std::vector<std::string>*));
MOCK_METHOD3(Get, bool(const std::string&, bool*, std::string*)); MOCK_METHOD3(Get, bool(const std::string&, bool*, std::string*));
MOCK_METHOD0(Destroy, bool()); MOCK_METHOD0(Destroy, bool());
...@@ -116,6 +118,10 @@ Matcher<const Options&> OptionsEq(const Options& expected) { ...@@ -116,6 +118,10 @@ Matcher<const Options&> OptionsEq(const Options& expected) {
return MakeMatcher(new OptionsEqMatcher(expected)); return MakeMatcher(new OptionsEqMatcher(expected));
} }
bool ZeroFilter(const std::string& key) {
return key == "0";
}
} // namespace } // namespace
EntryMap GetSmallModel() { EntryMap GetSmallModel() {
...@@ -245,7 +251,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBDestroyFailure) { ...@@ -245,7 +251,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBDestroyFailure) {
} }
ACTION_P(AppendLoadEntries, model) { ACTION_P(AppendLoadEntries, model) {
std::vector<std::string>* output = arg0; std::vector<std::string>* output = arg1;
for (const auto& pair : model) for (const auto& pair : model)
output->push_back(pair.second.SerializeAsString()); output->push_back(pair.second.SerializeAsString());
...@@ -274,7 +280,8 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) { ...@@ -274,7 +280,8 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) {
base::WrapUnique(mock_db), path, CreateSimpleOptions(), base::WrapUnique(mock_db), path, CreateSimpleOptions(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model)); EXPECT_CALL(*mock_db, LoadWithFilter(_, _))
.WillOnce(AppendLoadEntries(model));
EXPECT_CALL(caller, LoadCallback1(true, _)) EXPECT_CALL(caller, LoadCallback1(true, _))
.WillOnce(VerifyLoadEntries(testing::ByRef(model))); .WillOnce(VerifyLoadEntries(testing::ByRef(model)));
db_->LoadEntries( db_->LoadEntries(
...@@ -295,7 +302,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) { ...@@ -295,7 +302,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) {
base::WrapUnique(mock_db), path, CreateSimpleOptions(), base::WrapUnique(mock_db), path, CreateSimpleOptions(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false)); EXPECT_CALL(*mock_db, LoadWithFilter(_, _)).WillOnce(Return(false));
EXPECT_CALL(caller, LoadCallback1(false, _)); EXPECT_CALL(caller, LoadCallback1(false, _));
db_->LoadEntries( db_->LoadEntries(
base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
...@@ -696,6 +703,34 @@ TEST_F(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) { ...@@ -696,6 +703,34 @@ TEST_F(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) {
TestLevelDBSaveAndLoad(true); TestLevelDBSaveAndLoad(true);
} }
TEST_F(ProtoDatabaseImplLevelDBTest, TestDBLoadWithFilter) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
EntryMap model = GetSmallModel();
KeyValueVector save_entries;
std::vector<std::string> load_entries;
KeyVector remove_keys;
for (const auto& pair : model) {
save_entries.push_back(
std::make_pair(pair.second.id(), pair.second.SerializeAsString()));
}
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
EXPECT_TRUE(db->Init(temp_dir.GetPath(), CreateSimpleOptions()));
EXPECT_TRUE(db->Save(save_entries, remove_keys));
EXPECT_TRUE(
db->LoadWithFilter(base::BindRepeating(&ZeroFilter), &load_entries));
EXPECT_EQ(load_entries.size(), 1u);
TestProto entry;
ASSERT_TRUE(entry.ParseFromString(load_entries[0]));
EXPECT_EQ(entry.SerializeAsString(), model["0"].SerializeAsString());
}
TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) { TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
ScopedTempDir temp_dir; ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
......
...@@ -40,6 +40,9 @@ class FakeDB : public ProtoDatabase<T> { ...@@ -40,6 +40,9 @@ class FakeDB : public ProtoDatabase<T> {
std::unique_ptr<std::vector<std::string>> keys_to_remove, std::unique_ptr<std::vector<std::string>> keys_to_remove,
typename ProtoDatabase<T>::UpdateCallback callback) override; typename ProtoDatabase<T>::UpdateCallback callback) override;
void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override; void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadEntriesWithFilter(
const LevelDB::KeyFilter& key_filter,
typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override; void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
void GetEntry(const std::string& key, void GetEntry(const std::string& key,
typename ProtoDatabase<T>::GetCallback callback) override; typename ProtoDatabase<T>::GetCallback callback) override;
...@@ -118,9 +121,18 @@ void FakeDB<T>::UpdateEntries( ...@@ -118,9 +121,18 @@ void FakeDB<T>::UpdateEntries(
template <typename T> template <typename T>
void FakeDB<T>::LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) { void FakeDB<T>::LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) {
LoadEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
}
template <typename T>
void FakeDB<T>::LoadEntriesWithFilter(
const LevelDB::KeyFilter& key_filter,
typename ProtoDatabase<T>::LoadCallback callback) {
std::unique_ptr<std::vector<T>> entries(new std::vector<T>()); std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
for (const auto& pair : *db_) for (const auto& pair : *db_) {
entries->push_back(pair.second); if (key_filter.is_null() || key_filter.Run(pair.first))
entries->push_back(pair.second);
}
load_callback_ = load_callback_ =
base::BindOnce(RunLoadCallback, std::move(callback), std::move(entries)); base::BindOnce(RunLoadCallback, std::move(callback), std::move(entries));
......
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