Roll src/third_party/WebKit 9f7fb92:f103b33 (svn 202621:202622)
[chromium-blink-merge.git] / components / leveldb_proto / proto_database_impl.h
blob087520170b93ea40b6b7ad40b0af6f851f835510
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_
6 #define COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_
8 #include <string>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/strings/string_util.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "base/threading/thread_checker.h"
19 #include "base/strings/string_split.h"
20 #include "components/leveldb_proto/leveldb_database.h"
21 #include "components/leveldb_proto/proto_database.h"
23 namespace leveldb_proto {
25 using KeyValueVector = base::StringPairs;
26 using KeyVector = std::vector<std::string>;
28 // When the ProtoDatabaseImpl instance is deleted, in-progress asynchronous
29 // operations will be completed and the corresponding callbacks will be called.
30 // Construction/calls/destruction should all happen on the same thread.
31 template <typename T>
32 class ProtoDatabaseImpl : public ProtoDatabase<T> {
33 public:
34 // All blocking calls/disk access will happen on the provided |task_runner|.
35 explicit ProtoDatabaseImpl(
36 const scoped_refptr<base::SequencedTaskRunner>& task_runner);
38 ~ProtoDatabaseImpl() override;
40 // ProtoDatabase implementation.
41 // TODO(cjhopman): Perhaps Init() shouldn't be exposed to users and not just
42 // part of the constructor
43 void Init(const base::FilePath& database_dir,
44 const typename ProtoDatabase<T>::InitCallback& callback) override;
45 void UpdateEntries(
46 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
47 scoped_ptr<KeyVector> keys_to_remove,
48 const typename ProtoDatabase<T>::UpdateCallback& callback) override;
49 void LoadEntries(
50 const typename ProtoDatabase<T>::LoadCallback& callback) override;
52 // Allow callers to provide their own Database implementation.
53 void InitWithDatabase(
54 scoped_ptr<LevelDB> database,
55 const base::FilePath& database_dir,
56 const typename ProtoDatabase<T>::InitCallback& callback);
58 private:
59 base::ThreadChecker thread_checker_;
61 // Used to run blocking tasks in-order.
62 scoped_refptr<base::SequencedTaskRunner> task_runner_;
64 scoped_ptr<LevelDB> db_;
66 DISALLOW_COPY_AND_ASSIGN(ProtoDatabaseImpl);
69 namespace {
71 template <typename T>
72 void RunInitCallback(const typename ProtoDatabase<T>::InitCallback& callback,
73 const bool* success) {
74 callback.Run(*success);
77 template <typename T>
78 void RunUpdateCallback(
79 const typename ProtoDatabase<T>::UpdateCallback& callback,
80 const bool* success) {
81 callback.Run(*success);
84 template <typename T>
85 void RunLoadCallback(const typename ProtoDatabase<T>::LoadCallback& callback,
86 const bool* success,
87 scoped_ptr<std::vector<T>> entries) {
88 callback.Run(*success, entries.Pass());
91 void InitFromTaskRunner(LevelDB* database, const base::FilePath& database_dir,
92 bool* success) {
93 DCHECK(success);
95 // TODO(cjhopman): Histogram for database size.
96 *success = database->Init(database_dir);
99 template <typename T>
100 void UpdateEntriesFromTaskRunner(
101 LevelDB* database,
102 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
103 scoped_ptr<KeyVector> keys_to_remove,
104 bool* success) {
105 DCHECK(success);
107 // Serialize the values from Proto to string before passing on to database.
108 KeyValueVector pairs_to_save;
109 for (const auto& pair : *entries_to_save) {
110 pairs_to_save.push_back(
111 std::make_pair(pair.first, pair.second.SerializeAsString()));
114 *success = database->Save(pairs_to_save, *keys_to_remove);
117 template <typename T>
118 void LoadEntriesFromTaskRunner(LevelDB* database,
119 std::vector<T>* entries,
120 bool* success) {
121 DCHECK(success);
122 DCHECK(entries);
124 entries->clear();
126 std::vector<std::string> loaded_entries;
127 *success = database->Load(&loaded_entries);
129 for (const auto& serialized_entry : loaded_entries) {
130 T entry;
131 if (!entry.ParseFromString(serialized_entry)) {
132 DLOG(WARNING) << "Unable to parse leveldb_proto entry";
133 // TODO(cjhopman): Decide what to do about un-parseable entries.
136 entries->push_back(entry);
140 } // namespace
142 template <typename T>
143 ProtoDatabaseImpl<T>::ProtoDatabaseImpl(
144 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
145 : task_runner_(task_runner) {}
147 template <typename T>
148 ProtoDatabaseImpl<T>::~ProtoDatabaseImpl() {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 if (!task_runner_->DeleteSoon(FROM_HERE, db_.release()))
151 DLOG(WARNING) << "Proto database will not be deleted.";
154 template <typename T>
155 void ProtoDatabaseImpl<T>::Init(
156 const base::FilePath& database_dir,
157 const typename ProtoDatabase<T>::InitCallback& callback) {
158 DCHECK(thread_checker_.CalledOnValidThread());
159 InitWithDatabase(make_scoped_ptr(new LevelDB()), database_dir, callback);
162 template <typename T>
163 void ProtoDatabaseImpl<T>::InitWithDatabase(
164 scoped_ptr<LevelDB> database,
165 const base::FilePath& database_dir,
166 const typename ProtoDatabase<T>::InitCallback& callback) {
167 DCHECK(thread_checker_.CalledOnValidThread());
168 DCHECK(!db_);
169 DCHECK(database);
170 db_.reset(database.release());
171 bool* success = new bool(false);
172 task_runner_->PostTaskAndReply(
173 FROM_HERE, base::Bind(InitFromTaskRunner, base::Unretained(db_.get()),
174 database_dir, success),
175 base::Bind(RunInitCallback<T>, callback, base::Owned(success)));
178 template <typename T>
179 void ProtoDatabaseImpl<T>::UpdateEntries(
180 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
181 scoped_ptr<KeyVector> keys_to_remove,
182 const typename ProtoDatabase<T>::UpdateCallback& callback) {
183 DCHECK(thread_checker_.CalledOnValidThread());
184 bool* success = new bool(false);
185 task_runner_->PostTaskAndReply(
186 FROM_HERE,
187 base::Bind(UpdateEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
188 base::Passed(&entries_to_save), base::Passed(&keys_to_remove),
189 success),
190 base::Bind(RunUpdateCallback<T>, callback, base::Owned(success)));
193 template <typename T>
194 void ProtoDatabaseImpl<T>::LoadEntries(
195 const typename ProtoDatabase<T>::LoadCallback& callback) {
196 DCHECK(thread_checker_.CalledOnValidThread());
197 bool* success = new bool(false);
199 scoped_ptr<std::vector<T> > entries(new std::vector<T>());
200 // Get this pointer before entries is base::Passed() so we can use it below.
201 std::vector<T>* entries_ptr = entries.get();
203 task_runner_->PostTaskAndReply(
204 FROM_HERE, base::Bind(LoadEntriesFromTaskRunner<T>,
205 base::Unretained(db_.get()), entries_ptr, success),
206 base::Bind(RunLoadCallback<T>, callback, base::Owned(success),
207 base::Passed(&entries)));
210 } // namespace leveldb_proto
212 #endif // COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_