download_db_impl.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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/download/database/download_db_impl.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/task/thread_pool.h"
  9. #include "components/download/database/download_db_conversions.h"
  10. #include "components/download/database/download_db_entry.h"
  11. #include "components/download/database/proto/download_entry.pb.h"
  12. #include "components/leveldb_proto/public/proto_database_provider.h"
  13. namespace download {
  14. namespace {
  15. const int kMaxNumInitializeAttempts = 3;
  16. using ProtoKeyVector = std::vector<std::string>;
  17. using ProtoEntryVector = std::vector<download_pb::DownloadDBEntry>;
  18. using ProtoKeyEntryVector =
  19. std::vector<std::pair<std::string, download_pb::DownloadDBEntry>>;
  20. // Returns the prefix to all keys in the database.
  21. std::string GetDatabaseKeyPrefix(DownloadNamespace download_namespace) {
  22. return DownloadNamespaceToString(download_namespace) + ",";
  23. }
  24. // Check if an input string is under a given namespace.
  25. bool IsUnderNameSpace(DownloadNamespace download_namespace,
  26. const std::string& key) {
  27. return base::StartsWith(key, GetDatabaseKeyPrefix(download_namespace),
  28. base::CompareCase::INSENSITIVE_ASCII);
  29. }
  30. void OnUpdateDone(bool success) {
  31. // TODO(qinmin): add UMA for this.
  32. if (!success)
  33. LOG(ERROR) << "Update Download DB failed.";
  34. }
  35. } // namespace
  36. DownloadDBImpl::DownloadDBImpl(
  37. DownloadNamespace download_namespace,
  38. const base::FilePath& database_dir,
  39. leveldb_proto::ProtoDatabaseProvider* db_provider)
  40. : download_namespace_(download_namespace) {
  41. DCHECK(!database_dir.empty());
  42. db_ = db_provider->GetDB<download_pb::DownloadDBEntry>(
  43. leveldb_proto::ProtoDbType::DOWNLOAD_DB, database_dir,
  44. base::ThreadPool::CreateSequencedTaskRunner(
  45. {base::MayBlock(),
  46. // USER_VISIBLE because it is required to display chrome://downloads.
  47. // https://crbug.com/976223
  48. base::TaskPriority::USER_VISIBLE,
  49. base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
  50. }
  51. DownloadDBImpl::DownloadDBImpl(
  52. DownloadNamespace download_namespace,
  53. std::unique_ptr<leveldb_proto::ProtoDatabase<download_pb::DownloadDBEntry>>
  54. db)
  55. : db_(std::move(db)), download_namespace_(download_namespace) {}
  56. DownloadDBImpl::~DownloadDBImpl() = default;
  57. bool DownloadDBImpl::IsInitialized() {
  58. return is_initialized_;
  59. }
  60. void DownloadDBImpl::Initialize(DownloadDBCallback callback) {
  61. DCHECK(!IsInitialized());
  62. // These options reduce memory consumption.
  63. leveldb_env::Options options = leveldb_proto::CreateSimpleOptions();
  64. options.reuse_logs = false;
  65. options.write_buffer_size = 64 << 10; // 64 KiB
  66. db_->Init(options,
  67. base::BindOnce(&DownloadDBImpl::OnDatabaseInitialized,
  68. weak_factory_.GetWeakPtr(), std::move(callback)));
  69. }
  70. void DownloadDBImpl::DestroyAndReinitialize(DownloadDBCallback callback) {
  71. is_initialized_ = false;
  72. db_->Destroy(base::BindOnce(&DownloadDBImpl::OnDatabaseDestroyed,
  73. weak_factory_.GetWeakPtr(), std::move(callback)));
  74. }
  75. void DownloadDBImpl::AddOrReplace(const DownloadDBEntry& entry) {
  76. AddOrReplaceEntries(std::vector<DownloadDBEntry>{entry},
  77. base::BindOnce(&OnUpdateDone));
  78. }
  79. void DownloadDBImpl::AddOrReplaceEntries(
  80. const std::vector<DownloadDBEntry>& entries,
  81. DownloadDBCallback callback) {
  82. DCHECK(IsInitialized());
  83. auto entries_to_save = std::make_unique<ProtoKeyEntryVector>();
  84. for (const auto& entry : entries) {
  85. download_pb::DownloadDBEntry proto =
  86. DownloadDBConversions::DownloadDBEntryToProto(entry);
  87. entries_to_save->emplace_back(GetEntryKey(entry.GetGuid()),
  88. std::move(proto));
  89. }
  90. db_->UpdateEntries(std::move(entries_to_save),
  91. std::make_unique<ProtoKeyVector>(), std::move(callback));
  92. }
  93. void DownloadDBImpl::LoadEntries(LoadEntriesCallback callback) {
  94. db_->LoadEntriesWithFilter(
  95. base::BindRepeating(&IsUnderNameSpace, download_namespace_),
  96. base::BindOnce(&DownloadDBImpl::OnAllEntriesLoaded,
  97. weak_factory_.GetWeakPtr(), std::move(callback)));
  98. }
  99. void DownloadDBImpl::Remove(const std::string& guid) {
  100. DCHECK(IsInitialized());
  101. auto keys_to_remove = std::make_unique<ProtoKeyVector>();
  102. keys_to_remove->push_back(GetEntryKey(guid));
  103. db_->UpdateEntries(std::make_unique<ProtoKeyEntryVector>(),
  104. std::move(keys_to_remove),
  105. base::BindOnce(&DownloadDBImpl::OnRemoveDone,
  106. weak_factory_.GetWeakPtr()));
  107. }
  108. std::string DownloadDBImpl::GetEntryKey(const std::string& guid) const {
  109. return GetDatabaseKeyPrefix(download_namespace_) + guid;
  110. }
  111. void DownloadDBImpl::OnAllEntriesLoaded(
  112. LoadEntriesCallback callback,
  113. bool success,
  114. std::unique_ptr<ProtoEntryVector> entries) {
  115. auto result = std::make_unique<std::vector<DownloadDBEntry>>();
  116. if (!success) {
  117. std::move(callback).Run(success, std::move(result));
  118. return;
  119. }
  120. for (const auto& entry : *entries.get()) {
  121. result->emplace_back(
  122. DownloadDBConversions::DownloadDBEntryFromProto(entry));
  123. }
  124. std::move(callback).Run(success, std::move(result));
  125. }
  126. void DownloadDBImpl::OnDatabaseInitialized(
  127. DownloadDBCallback callback,
  128. leveldb_proto::Enums::InitStatus status) {
  129. bool success = status == leveldb_proto::Enums::InitStatus::kOK;
  130. if (!success) {
  131. DestroyAndReinitialize(std::move(callback));
  132. return;
  133. }
  134. is_initialized_ = success;
  135. std::move(callback).Run(success);
  136. }
  137. void DownloadDBImpl::OnDatabaseDestroyed(DownloadDBCallback callback,
  138. bool success) {
  139. if (!success) {
  140. std::move(callback).Run(success);
  141. return;
  142. }
  143. num_initialize_attempts_++;
  144. if (num_initialize_attempts_ >= kMaxNumInitializeAttempts)
  145. std::move(callback).Run(false);
  146. else
  147. Initialize(std::move(callback));
  148. }
  149. void DownloadDBImpl::OnRemoveDone(bool success) {
  150. // TODO(qinmin): add UMA for this.
  151. if (!success)
  152. LOG(ERROR) << "Remove entry from Download DB failed.";
  153. }
  154. } // namespace download