proto_leveldb_wrapper.cc 16 KB

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