Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: components/leveldb_proto/core/proto_database_impl.h

Issue 330833002: Extract protobuf database into a new 'leveldb_proto' component (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressed comments Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #ifndef COMPONENTS_LEVELDB_PROTO_CORE_PROTO_DATABASE_IMPL_H_
6 #define COMPONENTS_LEVELDB_PROTO_CORE_PROTO_DATABASE_IMPL_H_
7
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/file_util.h"
13 #include "base/files/file_path.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/string_util.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/threading/thread_checker.h"
20 #include "base/threading/thread_collision_warner.h"
21 #include "components/leveldb_proto/core/proto_database.h"
22 #include "third_party/leveldatabase/src/include/leveldb/db.h"
23 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
24 #include "third_party/leveldatabase/src/include/leveldb/options.h"
25 #include "third_party/leveldatabase/src/include/leveldb/slice.h"
26 #include "third_party/leveldatabase/src/include/leveldb/status.h"
27 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
28
29 namespace leveldb_proto {
30
31 typedef std::vector<std::pair<std::string, std::string> > KeyValueVector;
32 typedef std::vector<std::string> KeyVector;
33
34 // When the ProtoDatabaseImpl instance is deleted, in-progress asynchronous
35 // operations will be completed and the corresponding callbacks will be called.
36 // Construction/calls/destruction should all happen on the same thread.
37 template <typename T>
38 class ProtoDatabaseImpl : public ProtoDatabase<T> {
39 public:
40 // The underlying database. Calls to this type may be blocking.
41 class Database {
cjhopman 2014/06/16 22:44:44 Since this is an inner class of ProtoDatabaseImpl
Mathieu 2014/06/17 17:40:59 Per discussion, I removed Database and kept LevelD
42 public:
43 virtual bool Init(const base::FilePath& database_dir) = 0;
44 virtual bool Save(const KeyValueVector& pairs_to_save,
45 const KeyVector& keys_to_remove) = 0;
46 virtual bool Load(std::vector<std::string>* entries) = 0;
47 virtual ~Database() {}
48 };
49
50 // Once constructed, function calls and destruction should all occur on the
51 // same thread (not necessarily the same as the constructor).
52 class LevelDB : public Database {
53 public:
54 LevelDB();
55 virtual ~LevelDB();
56 virtual bool Init(const base::FilePath& database_dir) OVERRIDE;
57 virtual bool Save(const KeyValueVector& pairs_to_save,
58 const KeyVector& keys_to_remove) OVERRIDE;
59 virtual bool Load(std::vector<std::string>* entries) OVERRIDE;
60
61 private:
62 DFAKE_MUTEX(thread_checker_);
63 scoped_ptr<leveldb::DB> db_;
64 };
65
66 // All blocking calls/disk access will happen on the provided |task_runner|.
67 explicit ProtoDatabaseImpl(
68 scoped_refptr<base::SequencedTaskRunner> task_runner);
69
70 virtual ~ProtoDatabaseImpl();
71
72 // ProtoDatabase implementation.
73 // TODO(cjhopman): Perhaps Init() shouldn't be exposed to users and not just
74 // part of the constructor
75 virtual void Init(const base::FilePath& database_dir,
76 typename ProtoDatabase<T>::InitCallback callback) OVERRIDE;
77 virtual void UpdateEntries(
78 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
79 scoped_ptr<KeyVector> keys_to_remove,
80 typename ProtoDatabase<T>::UpdateCallback callback) OVERRIDE;
81 virtual void LoadEntries(
82 typename ProtoDatabase<T>::LoadCallback callback) OVERRIDE;
83
84 // Allow callers to provide their own Database implementation.
85 void InitWithDatabase(scoped_ptr<Database> database,
86 const base::FilePath& database_dir,
87 typename ProtoDatabase<T>::InitCallback callback);
88
89 private:
90 base::ThreadChecker thread_checker_;
91
92 // Used to run blocking tasks in-order.
93 scoped_refptr<base::SequencedTaskRunner> task_runner_;
94
95 scoped_ptr<Database> db_;
96
97 DISALLOW_COPY_AND_ASSIGN(ProtoDatabaseImpl);
98 };
99
100 template <typename T>
101 ProtoDatabaseImpl<T>::LevelDB::LevelDB() {}
102
103 template <typename T>
104 ProtoDatabaseImpl<T>::LevelDB::~LevelDB() {
105 DFAKE_SCOPED_LOCK(thread_checker_);
106 }
107
108 template <typename T>
109 bool ProtoDatabaseImpl<T>::LevelDB::Init(const base::FilePath& database_dir) {
110 DFAKE_SCOPED_LOCK(thread_checker_);
111
112 leveldb::Options options;
113 options.create_if_missing = true;
114 options.max_open_files = 0; // Use minimum.
115
116 std::string path = database_dir.AsUTF8Unsafe();
117
118 leveldb::DB* db = NULL;
119 leveldb::Status status = leveldb::DB::Open(options, path, &db);
120 if (status.IsCorruption()) {
121 base::DeleteFile(database_dir, true);
122 status = leveldb::DB::Open(options, path, &db);
123 }
124
125 if (status.ok()) {
126 CHECK(db);
127 db_.reset(db);
128 return true;
129 }
130
131 LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
132 << status.ToString();
133 return false;
134 }
135
136 template <typename T>
137 bool ProtoDatabaseImpl<T>::LevelDB::Save(const KeyValueVector& entries_to_save,
138 const KeyVector& keys_to_remove) {
139 DFAKE_SCOPED_LOCK(thread_checker_);
140
141 leveldb::WriteBatch updates;
142 for (KeyValueVector::const_iterator it = entries_to_save.begin();
143 it != entries_to_save.end(); ++it) {
144 updates.Put(leveldb::Slice(it->first), leveldb::Slice(it->second));
145 }
146 for (KeyVector::const_iterator it = keys_to_remove.begin();
147 it != keys_to_remove.end(); ++it) {
148 updates.Delete(leveldb::Slice(*it));
149 }
150
151 leveldb::WriteOptions options;
152 options.sync = true;
153 leveldb::Status status = db_->Write(options, &updates);
154 if (status.ok()) return true;
155
156 DLOG(WARNING) << "Failed writing leveldb_proto entries: "
157 << status.ToString();
158 return false;
159 }
160
161 template <typename T>
162 bool ProtoDatabaseImpl<T>::LevelDB::Load(std::vector<std::string>* entries) {
163 DFAKE_SCOPED_LOCK(thread_checker_);
164
165 leveldb::ReadOptions options;
166 scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
167 for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
168 leveldb::Slice value_slice = db_iterator->value();
169 std::string entry(value_slice.data(), value_slice.size());
170 entries->push_back(entry);
171 }
172 return true;
173 }
174
175 namespace {
176
177 template <typename T>
178 void RunInitCallback(typename ProtoDatabase<T>::InitCallback callback,
179 const bool* success) {
180 callback.Run(*success);
181 }
182
183 template <typename T>
184 void RunUpdateCallback(typename ProtoDatabase<T>::UpdateCallback callback,
185 const bool* success) {
186 callback.Run(*success);
187 }
188
189 template <typename T>
190 void RunLoadCallback(typename ProtoDatabase<T>::LoadCallback callback,
191 const bool* success, scoped_ptr<std::vector<T> > entries) {
192 callback.Run(*success, entries.Pass());
193 }
194
195 template <typename T>
196 void InitFromTaskRunner(typename ProtoDatabaseImpl<T>::Database* database,
197 const base::FilePath& database_dir, bool* success) {
198 DCHECK(success);
199
200 // TODO(cjhopman): Histogram for database size.
201 *success = database->Init(database_dir);
202 }
203
204 template <typename T>
205 void UpdateEntriesFromTaskRunner(
206 typename ProtoDatabaseImpl<T>::Database* database,
207 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
208 scoped_ptr<KeyVector> keys_to_remove, bool* success) {
209 DCHECK(success);
210 // Serialize the values from Proto to string before passing on to database.
211 KeyValueVector pairs_to_save;
212 for (typename ProtoDatabase<T>::KeyEntryVector::iterator it =
213 entries_to_save->begin();
214 it != entries_to_save->end(); ++it) {
215 pairs_to_save.push_back(
216 std::make_pair(it->first, it->second.SerializeAsString()));
217 }
218 *success = database->Save(pairs_to_save, *keys_to_remove);
219 }
220
221 template <typename T>
222 void LoadEntriesFromTaskRunner(
223 typename ProtoDatabaseImpl<T>::Database* database, std::vector<T>* entries,
224 bool* success) {
225 DCHECK(success);
226 DCHECK(entries);
227
228 entries->clear();
229 std::vector<std::string> loaded_entries;
230 *success = database->Load(&loaded_entries);
231 for (std::vector<std::string>::iterator it = loaded_entries.begin();
232 it != loaded_entries.end(); ++it) {
233 T entry;
234 if (!entry.ParseFromString(*it)) {
235 DLOG(WARNING) << "Unable to parse leveldb_proto entry " << *it;
236 // TODO(cjhopman): Decide what to do about un-parseable entries.
237 }
238 entries->push_back(entry);
239 }
240 }
241
242 } // namespace
243
244 template <typename T>
245 ProtoDatabaseImpl<T>::ProtoDatabaseImpl(
246 scoped_refptr<base::SequencedTaskRunner> task_runner)
247 : task_runner_(task_runner) {}
248
249 template <typename T>
250 ProtoDatabaseImpl<T>::~ProtoDatabaseImpl() {
251 DCHECK(thread_checker_.CalledOnValidThread());
252 if (!task_runner_->DeleteSoon(FROM_HERE, db_.release())) {
253 DLOG(WARNING) << "DOM distiller database will not be deleted.";
254 }
255 }
256
257 template <typename T>
258 void ProtoDatabaseImpl<T>::Init(
259 const base::FilePath& database_dir,
260 typename ProtoDatabase<T>::InitCallback callback) {
261 DCHECK(thread_checker_.CalledOnValidThread());
262 InitWithDatabase(scoped_ptr<Database>(new LevelDB()), database_dir, callback);
263 }
264
265 template <typename T>
266 void ProtoDatabaseImpl<T>::InitWithDatabase(
267 scoped_ptr<Database> database, const base::FilePath& database_dir,
268 typename ProtoDatabase<T>::InitCallback callback) {
269 DCHECK(thread_checker_.CalledOnValidThread());
270 DCHECK(!db_);
271 DCHECK(database);
272 db_.reset(database.release());
273 bool* success = new bool(false);
274 task_runner_->PostTaskAndReply(
275 FROM_HERE, base::Bind(InitFromTaskRunner<T>, base::Unretained(db_.get()),
276 database_dir, success),
277 base::Bind(RunInitCallback<T>, callback, base::Owned(success)));
278 }
279
280 template <typename T>
281 void ProtoDatabaseImpl<T>::UpdateEntries(
282 scoped_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
283 scoped_ptr<KeyVector> keys_to_remove,
284 typename ProtoDatabase<T>::UpdateCallback callback) {
285 DCHECK(thread_checker_.CalledOnValidThread());
286 bool* success = new bool(false);
287 task_runner_->PostTaskAndReply(
288 FROM_HERE,
289 base::Bind(UpdateEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
290 base::Passed(&entries_to_save), base::Passed(&keys_to_remove),
291 success),
292 base::Bind(RunUpdateCallback<T>, callback, base::Owned(success)));
293 }
294
295 template <typename T>
296 void ProtoDatabaseImpl<T>::LoadEntries(
297 typename ProtoDatabase<T>::LoadCallback callback) {
298 DCHECK(thread_checker_.CalledOnValidThread());
299 bool* success = new bool(false);
300
301 scoped_ptr<std::vector<T> > entries(new std::vector<T>());
302 // Get this pointer before entries is base::Passed() so we can use it below.
303 std::vector<T>* entries_ptr = entries.get();
304
305 task_runner_->PostTaskAndReply(
306 FROM_HERE, base::Bind(LoadEntriesFromTaskRunner<T>,
307 base::Unretained(db_.get()), entries_ptr, success),
308 base::Bind(RunLoadCallback<T>, callback, base::Owned(success),
309 base::Passed(&entries)));
310 }
311
312 } // namespace leveldb_proto
313
314 #endif // COMPONENTS_LEVELDB_PROTO_CORE_PROTO_DATABASE_IMPL_H_
OLDNEW
« no previous file with comments | « components/leveldb_proto/core/proto_database.h ('k') | components/leveldb_proto/core/proto_database_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698