1 // Copyright 2018 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 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
6
7 #include <string>
8
9 #include "base/sequenced_task_runner.h"
10 #include "base/task/post_task.h"
11 #include "base/task/task_traits.h"
12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "components/leveldb_proto/internal/leveldb_database.h"
14 #include "components/leveldb_proto/internal/proto_leveldb_wrapper_metrics.h"
15 #include "components/leveldb_proto/public/proto_database.h"
16
17 namespace leveldb_proto {
18
19 namespace {
20
InitFromTaskRunner(LevelDB * database,const base::FilePath & database_dir,const leveldb_env::Options & options,bool destroy_on_corruption,const std::string & client_id)21 Enums::InitStatus InitFromTaskRunner(LevelDB* database,
22 const base::FilePath& database_dir,
23 const leveldb_env::Options& options,
24 bool destroy_on_corruption,
25 const std::string& client_id) {
26 // TODO(cjhopman): Histogram for database size.
27 auto status = database->Init(database_dir, options, destroy_on_corruption);
28 ProtoLevelDBWrapperMetrics::RecordInit(client_id, status);
29
30 if (status.ok())
31 return Enums::InitStatus::kOK;
32 if (status.IsCorruption())
33 return Enums::InitStatus::kCorrupt;
34 if (status.IsNotSupportedError() || status.IsInvalidArgument())
35 return Enums::InitStatus::kInvalidOperation;
36 return Enums::InitStatus::kError;
37 }
38
DestroyFromTaskRunner(LevelDB * database,const std::string & client_id)39 bool DestroyFromTaskRunner(LevelDB* database, const std::string& client_id) {
40 auto status = database->Destroy();
41 bool success = status.ok();
42 ProtoLevelDBWrapperMetrics::RecordDestroy(client_id, success);
43
44 return success;
45 }
46
DestroyWithDirectoryFromTaskRunner(const base::FilePath & db_dir,const std::string & client_id)47 bool DestroyWithDirectoryFromTaskRunner(const base::FilePath& db_dir,
48 const std::string& client_id) {
49 leveldb::Status result = leveldb::DestroyDB(
50 db_dir.AsUTF8Unsafe(), leveldb_proto::CreateSimpleOptions());
51 bool success = result.ok();
52
53 if (!client_id.empty())
54 ProtoLevelDBWrapperMetrics::RecordDestroy(client_id, success);
55
56 return success;
57 }
58
LoadKeysFromTaskRunner(LevelDB * database,const std::string & target_prefix,const std::string & client_id,Callbacks::LoadKeysCallback callback,scoped_refptr<base::SequencedTaskRunner> callback_task_runner)59 void LoadKeysFromTaskRunner(
60 LevelDB* database,
61 const std::string& target_prefix,
62 const std::string& client_id,
63 Callbacks::LoadKeysCallback callback,
64 scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
65 auto keys = std::make_unique<KeyVector>();
66 bool success = database->LoadKeys(target_prefix, keys.get());
67 ProtoLevelDBWrapperMetrics::RecordLoadKeys(client_id, success);
68 callback_task_runner->PostTask(
69 FROM_HERE, base::BindOnce(std::move(callback), success, std::move(keys)));
70 }
71
RemoveKeysFromTaskRunner(LevelDB * database,const std::string & target_prefix,const KeyFilter & filter,const std::string & client_id,Callbacks::UpdateCallback callback,scoped_refptr<base::SequencedTaskRunner> callback_task_runner)72 void RemoveKeysFromTaskRunner(
73 LevelDB* database,
74 const std::string& target_prefix,
75 const KeyFilter& filter,
76 const std::string& client_id,
77 Callbacks::UpdateCallback callback,
78 scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
79 leveldb::Status status;
80 bool success = database->UpdateWithRemoveFilter(base::StringPairs(), filter,
81 target_prefix, &status);
82 ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
83 callback_task_runner->PostTask(FROM_HERE,
84 base::BindOnce(std::move(callback), success));
85 }
86
RunLoadCallback(Callbacks::LoadCallback callback,bool * success,std::unique_ptr<ValueVector> entries)87 void RunLoadCallback(Callbacks::LoadCallback callback,
88 bool* success,
89 std::unique_ptr<ValueVector> entries) {
90 std::move(callback).Run(*success, std::move(entries));
91 }
92
RunLoadKeysAndEntriesCallback(Callbacks::LoadKeysAndEntriesCallback callback,bool * success,std::unique_ptr<KeyValueMap> keys_entries)93 void RunLoadKeysAndEntriesCallback(
94 Callbacks::LoadKeysAndEntriesCallback callback,
95 bool* success,
96 std::unique_ptr<KeyValueMap> keys_entries) {
97 std::move(callback).Run(*success, std::move(keys_entries));
98 }
99
RunGetCallback(Callbacks::GetCallback callback,const bool * success,const bool * found,std::unique_ptr<std::string> entry)100 void RunGetCallback(Callbacks::GetCallback callback,
101 const bool* success,
102 const bool* found,
103 std::unique_ptr<std::string> entry) {
104 std::move(callback).Run(*success, *found ? std::move(entry) : nullptr);
105 }
106
UpdateEntriesFromTaskRunner(LevelDB * database,std::unique_ptr<KeyValueVector> entries_to_save,std::unique_ptr<KeyVector> keys_to_remove,const std::string & client_id)107 bool UpdateEntriesFromTaskRunner(
108 LevelDB* database,
109 std::unique_ptr<KeyValueVector> entries_to_save,
110 std::unique_ptr<KeyVector> keys_to_remove,
111 const std::string& client_id) {
112 DCHECK(entries_to_save);
113 DCHECK(keys_to_remove);
114 leveldb::Status status;
115 bool success = database->Save(*entries_to_save, *keys_to_remove, &status);
116 ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
117 return success;
118 }
119
UpdateEntriesWithRemoveFilterFromTaskRunner(LevelDB * database,std::unique_ptr<KeyValueVector> entries_to_save,const KeyFilter & delete_key_filter,const std::string & target_prefix,const std::string & client_id)120 bool UpdateEntriesWithRemoveFilterFromTaskRunner(
121 LevelDB* database,
122 std::unique_ptr<KeyValueVector> entries_to_save,
123 const KeyFilter& delete_key_filter,
124 const std::string& target_prefix,
125 const std::string& client_id) {
126 DCHECK(entries_to_save);
127 leveldb::Status status;
128 bool success = database->UpdateWithRemoveFilter(
129 *entries_to_save, delete_key_filter, target_prefix, &status);
130 ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
131 return success;
132 }
133
LoadKeysAndEntriesFromTaskRunner(LevelDB * database,const KeyFilter & while_callback,const KeyFilter & filter,const leveldb::ReadOptions & options,const std::string & target_prefix,const std::string & client_id,bool * success,KeyValueMap * keys_entries)134 void LoadKeysAndEntriesFromTaskRunner(LevelDB* database,
135 const KeyFilter& while_callback,
136 const KeyFilter& filter,
137 const leveldb::ReadOptions& options,
138 const std::string& target_prefix,
139 const std::string& client_id,
140 bool* success,
141 KeyValueMap* keys_entries) {
142 DCHECK(success);
143 DCHECK(keys_entries);
144 keys_entries->clear();
145
146 *success = database->LoadKeysAndEntriesWhile(filter, keys_entries, options,
147 target_prefix, while_callback);
148
149 ProtoLevelDBWrapperMetrics::RecordLoadKeysAndEntries(client_id, success);
150 }
151
LoadEntriesFromTaskRunner(LevelDB * database,const KeyFilter & filter,const leveldb::ReadOptions & options,const std::string & target_prefix,const std::string & client_id,bool * success,ValueVector * entries)152 void LoadEntriesFromTaskRunner(LevelDB* database,
153 const KeyFilter& filter,
154 const leveldb::ReadOptions& options,
155 const std::string& target_prefix,
156 const std::string& client_id,
157 bool* success,
158 ValueVector* entries) {
159 *success = database->LoadWithFilter(filter, entries, options, target_prefix);
160
161 ProtoLevelDBWrapperMetrics::RecordLoadEntries(client_id, success);
162 }
163
GetEntryFromTaskRunner(LevelDB * database,const std::string & key,const std::string & client_id,bool * success,bool * found,std::string * entry)164 void GetEntryFromTaskRunner(LevelDB* database,
165 const std::string& key,
166 const std::string& client_id,
167 bool* success,
168 bool* found,
169 std::string* entry) {
170 leveldb::Status status;
171 *success = database->Get(key, found, entry, &status);
172
173 ProtoLevelDBWrapperMetrics::RecordGet(client_id, *success, *found, status);
174 }
175 } // namespace
176
ProtoLevelDBWrapper(const scoped_refptr<base::SequencedTaskRunner> & task_runner)177 ProtoLevelDBWrapper::ProtoLevelDBWrapper(
178 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
179 : task_runner_(task_runner) {
180 DETACH_FROM_SEQUENCE(sequence_checker_);
181 }
182
ProtoLevelDBWrapper(const scoped_refptr<base::SequencedTaskRunner> & task_runner,LevelDB * db)183 ProtoLevelDBWrapper::ProtoLevelDBWrapper(
184 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
185 LevelDB* db)
186 : task_runner_(task_runner), db_(db) {
187 DETACH_FROM_SEQUENCE(sequence_checker_);
188 }
189
190 ProtoLevelDBWrapper::~ProtoLevelDBWrapper() = default;
191
RunInitCallback(Callbacks::InitCallback callback,const leveldb::Status * status)192 void ProtoLevelDBWrapper::RunInitCallback(Callbacks::InitCallback callback,
193 const leveldb::Status* status) {
194 std::move(callback).Run(status->ok());
195 }
196
InitWithDatabase(LevelDB * database,const base::FilePath & database_dir,const leveldb_env::Options & options,bool destroy_on_corruption,Callbacks::InitStatusCallback callback)197 void ProtoLevelDBWrapper::InitWithDatabase(
198 LevelDB* database,
199 const base::FilePath& database_dir,
200 const leveldb_env::Options& options,
201 bool destroy_on_corruption,
202 Callbacks::InitStatusCallback callback) {
203 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
204 DCHECK(database);
205 db_ = database;
206
207 base::PostTaskAndReplyWithResult(
208 task_runner_.get(), FROM_HERE,
209 base::BindOnce(InitFromTaskRunner, base::Unretained(db_), database_dir,
210 options, destroy_on_corruption, metrics_id_),
211 std::move(callback));
212 }
213
UpdateEntries(std::unique_ptr<KeyValueVector> entries_to_save,std::unique_ptr<KeyVector> keys_to_remove,typename Callbacks::UpdateCallback callback)214 void ProtoLevelDBWrapper::UpdateEntries(
215 std::unique_ptr<KeyValueVector> entries_to_save,
216 std::unique_ptr<KeyVector> keys_to_remove,
217 typename Callbacks::UpdateCallback callback) {
218 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
219 base::PostTaskAndReplyWithResult(
220 task_runner_.get(), FROM_HERE,
221 base::BindOnce(UpdateEntriesFromTaskRunner, base::Unretained(db_),
222 std::move(entries_to_save), std::move(keys_to_remove),
223 metrics_id_),
224 std::move(callback));
225 }
226
UpdateEntriesWithRemoveFilter(std::unique_ptr<KeyValueVector> entries_to_save,const KeyFilter & delete_key_filter,Callbacks::UpdateCallback callback)227 void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
228 std::unique_ptr<KeyValueVector> entries_to_save,
229 const KeyFilter& delete_key_filter,
230 Callbacks::UpdateCallback callback) {
231 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
232 UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
233 std::string(), std::move(callback));
234 }
235
UpdateEntriesWithRemoveFilter(std::unique_ptr<KeyValueVector> entries_to_save,const KeyFilter & delete_key_filter,const std::string & target_prefix,Callbacks::UpdateCallback callback)236 void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
237 std::unique_ptr<KeyValueVector> entries_to_save,
238 const KeyFilter& delete_key_filter,
239 const std::string& target_prefix,
240 Callbacks::UpdateCallback callback) {
241 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
242 base::PostTaskAndReplyWithResult(
243 task_runner_.get(), FROM_HERE,
244 base::BindOnce(UpdateEntriesWithRemoveFilterFromTaskRunner,
245 base::Unretained(db_), std::move(entries_to_save),
246 delete_key_filter, target_prefix, metrics_id_),
247 std::move(callback));
248 }
249
LoadEntries(Callbacks::LoadCallback callback)250 void ProtoLevelDBWrapper::LoadEntries(Callbacks::LoadCallback callback) {
251 LoadEntriesWithFilter(KeyFilter(), std::move(callback));
252 }
253
LoadEntriesWithFilter(const KeyFilter & key_filter,Callbacks::LoadCallback callback)254 void ProtoLevelDBWrapper::LoadEntriesWithFilter(
255 const KeyFilter& key_filter,
256 Callbacks::LoadCallback callback) {
257 LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(),
258 std::move(callback));
259 }
260
LoadEntriesWithFilter(const KeyFilter & key_filter,const leveldb::ReadOptions & options,const std::string & target_prefix,Callbacks::LoadCallback callback)261 void ProtoLevelDBWrapper::LoadEntriesWithFilter(
262 const KeyFilter& key_filter,
263 const leveldb::ReadOptions& options,
264 const std::string& target_prefix,
265 Callbacks::LoadCallback callback) {
266 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
267 bool* success = new bool(false);
268 auto entries = std::make_unique<ValueVector>();
269 // Get this pointer before |entries| is std::move()'d so we can use it below.
270 auto* entries_ptr = entries.get();
271
272 task_runner_->PostTaskAndReply(
273 FROM_HERE,
274 base::BindOnce(LoadEntriesFromTaskRunner, base::Unretained(db_),
275 key_filter, options, target_prefix, metrics_id_, success,
276 entries_ptr),
277 base::BindOnce(RunLoadCallback, std::move(callback), base::Owned(success),
278 std::move(entries)));
279 }
280
LoadKeysAndEntries(Callbacks::LoadKeysAndEntriesCallback callback)281 void ProtoLevelDBWrapper::LoadKeysAndEntries(
282 Callbacks::LoadKeysAndEntriesCallback callback) {
283 LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
284 }
285
LoadKeysAndEntriesWithFilter(const KeyFilter & key_filter,Callbacks::LoadKeysAndEntriesCallback callback)286 void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
287 const KeyFilter& key_filter,
288 Callbacks::LoadKeysAndEntriesCallback callback) {
289 LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(),
290 std::string(), std::move(callback));
291 }
292
LoadKeysAndEntriesWithFilter(const KeyFilter & key_filter,const leveldb::ReadOptions & options,const std::string & target_prefix,Callbacks::LoadKeysAndEntriesCallback callback)293 void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
294 const KeyFilter& key_filter,
295 const leveldb::ReadOptions& options,
296 const std::string& target_prefix,
297 Callbacks::LoadKeysAndEntriesCallback callback) {
298 LoadKeysAndEntriesWhile(
299 base::BindRepeating(
300 [](const std::string& prefix, const std::string& key) {
301 return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
302 },
303 target_prefix),
304 key_filter, options, target_prefix, std::move(callback));
305 }
306
LoadKeysAndEntriesInRange(const std::string & start,const std::string & end,Callbacks::LoadKeysAndEntriesCallback callback)307 void ProtoLevelDBWrapper::LoadKeysAndEntriesInRange(
308 const std::string& start,
309 const std::string& end,
310 Callbacks::LoadKeysAndEntriesCallback callback) {
311 LoadKeysAndEntriesWhile(
312 base::BindRepeating(
313 [](const std::string& range_end, const std::string& key) {
314 return key.compare(range_end) <= 0;
315 },
316 end),
317 KeyFilter(), leveldb::ReadOptions(), start, std::move(callback));
318 }
319
LoadKeysAndEntriesWhile(const KeyFilter & while_callback,const KeyFilter & filter,const leveldb::ReadOptions & options,const std::string & target_prefix,Callbacks::LoadKeysAndEntriesCallback callback)320 void ProtoLevelDBWrapper::LoadKeysAndEntriesWhile(
321 const KeyFilter& while_callback,
322 const KeyFilter& filter,
323 const leveldb::ReadOptions& options,
324 const std::string& target_prefix,
325 Callbacks::LoadKeysAndEntriesCallback callback) {
326 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
327 bool* success = new bool(false);
328 auto keys_entries = std::make_unique<KeyValueMap>();
329 // Get this pointer before |keys_entries| is std::move()'d so we can use it
330 // below.
331 auto* keys_entries_ptr = keys_entries.get();
332 task_runner_->PostTaskAndReply(
333 FROM_HERE,
334 base::BindOnce(LoadKeysAndEntriesFromTaskRunner, base::Unretained(db_),
335 while_callback, filter, options, target_prefix,
336 metrics_id_, success, keys_entries_ptr),
337 base::BindOnce(RunLoadKeysAndEntriesCallback, std::move(callback),
338 base::Owned(success), std::move(keys_entries)));
339 }
340
GetEntry(const std::string & key,Callbacks::GetCallback callback)341 void ProtoLevelDBWrapper::GetEntry(const std::string& key,
342 Callbacks::GetCallback callback) {
343 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
344 bool* success = new bool(false);
345 bool* found = new bool(false);
346 auto entry = std::make_unique<std::string>();
347 // Get this pointer before |entry| is std::move()'d so we can use it below.
348 auto* entry_ptr = entry.get();
349
350 task_runner_->PostTaskAndReply(
351 FROM_HERE,
352 base::BindOnce(GetEntryFromTaskRunner, base::Unretained(db_), key,
353 metrics_id_, success, found, entry_ptr),
354 base::BindOnce(RunGetCallback, std::move(callback), base::Owned(success),
355 base::Owned(found), std::move(entry)));
356 }
357
LoadKeys(typename Callbacks::LoadKeysCallback callback)358 void ProtoLevelDBWrapper::LoadKeys(
359 typename Callbacks::LoadKeysCallback callback) {
360 LoadKeys(std::string(), std::move(callback));
361 }
362
LoadKeys(const std::string & target_prefix,typename Callbacks::LoadKeysCallback callback)363 void ProtoLevelDBWrapper::LoadKeys(
364 const std::string& target_prefix,
365 typename Callbacks::LoadKeysCallback callback) {
366 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
367 task_runner_->PostTask(
368 FROM_HERE, base::BindOnce(LoadKeysFromTaskRunner, base::Unretained(db_),
369 target_prefix, metrics_id_, std::move(callback),
370 base::SequencedTaskRunnerHandle::Get()));
371 }
372
RemoveKeys(const KeyFilter & filter,const std::string & target_prefix,Callbacks::UpdateCallback callback)373 void ProtoLevelDBWrapper::RemoveKeys(const KeyFilter& filter,
374 const std::string& target_prefix,
375 Callbacks::UpdateCallback callback) {
376 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
377 task_runner_->PostTask(
378 FROM_HERE,
379 base::BindOnce(RemoveKeysFromTaskRunner, base::Unretained(db_),
380 target_prefix, filter, metrics_id_, std::move(callback),
381 base::SequencedTaskRunnerHandle::Get()));
382 }
383
Destroy(Callbacks::DestroyCallback callback)384 void ProtoLevelDBWrapper::Destroy(Callbacks::DestroyCallback callback) {
385 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
386 DCHECK(db_);
387
388 base::PostTaskAndReplyWithResult(
389 task_runner_.get(), FROM_HERE,
390 base::BindOnce(DestroyFromTaskRunner, base::Unretained(db_), metrics_id_),
391 std::move(callback));
392 }
393
Destroy(const base::FilePath & db_dir,const std::string & client_id,const scoped_refptr<base::SequencedTaskRunner> & task_runner,Callbacks::DestroyCallback callback)394 void ProtoLevelDBWrapper::Destroy(
395 const base::FilePath& db_dir,
396 const std::string& client_id,
397 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
398 Callbacks::DestroyCallback callback) {
399 base::PostTaskAndReplyWithResult(
400 task_runner.get(), FROM_HERE,
401 base::BindOnce(DestroyWithDirectoryFromTaskRunner, db_dir, client_id),
402 std::move(callback));
403 }
404
SetMetricsId(const std::string & id)405 void ProtoLevelDBWrapper::SetMetricsId(const std::string& id) {
406 metrics_id_ = id;
407 }
408
GetApproximateMemoryUse(uint64_t * approx_mem_use)409 bool ProtoLevelDBWrapper::GetApproximateMemoryUse(uint64_t* approx_mem_use) {
410 if (!db_)
411 return 0;
412
413 return db_->GetApproximateMemoryUse(approx_mem_use);
414 }
415
416 const scoped_refptr<base::SequencedTaskRunner>&
task_runner()417 ProtoLevelDBWrapper::task_runner() {
418 return task_runner_;
419 }
420
421 } // namespace leveldb_proto
422