mem_backend_impl.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Copyright (c) 2012 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 "net/disk_cache/memory/mem_backend_impl.h"
  5. #include <algorithm>
  6. #include <functional>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/logging.h"
  11. #include "base/system/sys_info.h"
  12. #include "base/threading/sequenced_task_runner_handle.h"
  13. #include "base/time/clock.h"
  14. #include "net/base/net_errors.h"
  15. #include "net/disk_cache/cache_util.h"
  16. #include "net/disk_cache/memory/mem_entry_impl.h"
  17. using base::Time;
  18. namespace disk_cache {
  19. namespace {
  20. const int kDefaultInMemoryCacheSize = 10 * 1024 * 1024;
  21. const int kDefaultEvictionSize = kDefaultInMemoryCacheSize / 10;
  22. // Returns the next entry after |node| in |lru_list| that's not a child
  23. // of |node|. This is useful when dooming, since dooming a parent entry
  24. // will also doom its children.
  25. base::LinkNode<MemEntryImpl>* NextSkippingChildren(
  26. const base::LinkedList<MemEntryImpl>& lru_list,
  27. base::LinkNode<MemEntryImpl>* node) {
  28. MemEntryImpl* cur = node->value();
  29. do {
  30. node = node->next();
  31. } while (node != lru_list.end() && node->value()->parent() == cur);
  32. return node;
  33. }
  34. } // namespace
  35. MemBackendImpl::MemBackendImpl(net::NetLog* net_log)
  36. : Backend(net::MEMORY_CACHE),
  37. net_log_(net_log),
  38. memory_pressure_listener_(
  39. FROM_HERE,
  40. base::BindRepeating(&MemBackendImpl::OnMemoryPressure,
  41. base::Unretained(this))) {}
  42. MemBackendImpl::~MemBackendImpl() {
  43. while (!entries_.empty())
  44. entries_.begin()->second->Doom();
  45. if (!post_cleanup_callback_.is_null())
  46. base::SequencedTaskRunnerHandle::Get()->PostTask(
  47. FROM_HERE, std::move(post_cleanup_callback_));
  48. }
  49. // static
  50. std::unique_ptr<MemBackendImpl> MemBackendImpl::CreateBackend(
  51. int64_t max_bytes,
  52. net::NetLog* net_log) {
  53. std::unique_ptr<MemBackendImpl> cache(
  54. std::make_unique<MemBackendImpl>(net_log));
  55. if (cache->SetMaxSize(max_bytes) && cache->Init())
  56. return cache;
  57. LOG(ERROR) << "Unable to create cache";
  58. return nullptr;
  59. }
  60. bool MemBackendImpl::Init() {
  61. if (max_size_)
  62. return true;
  63. uint64_t total_memory = base::SysInfo::AmountOfPhysicalMemory();
  64. if (total_memory == 0) {
  65. max_size_ = kDefaultInMemoryCacheSize;
  66. return true;
  67. }
  68. // We want to use up to 2% of the computer's memory, with a limit of 50 MB,
  69. // reached on system with more than 2.5 GB of RAM.
  70. total_memory = total_memory * 2 / 100;
  71. if (total_memory > static_cast<uint64_t>(kDefaultInMemoryCacheSize) * 5)
  72. max_size_ = kDefaultInMemoryCacheSize * 5;
  73. else
  74. max_size_ = static_cast<int32_t>(total_memory);
  75. return true;
  76. }
  77. bool MemBackendImpl::SetMaxSize(int64_t max_bytes) {
  78. if (max_bytes < 0 || max_bytes > std::numeric_limits<int>::max())
  79. return false;
  80. // Zero size means use the default.
  81. if (!max_bytes)
  82. return true;
  83. max_size_ = max_bytes;
  84. return true;
  85. }
  86. int64_t MemBackendImpl::MaxFileSize() const {
  87. return max_size_ / 8;
  88. }
  89. void MemBackendImpl::OnEntryInserted(MemEntryImpl* entry) {
  90. lru_list_.Append(entry);
  91. }
  92. void MemBackendImpl::OnEntryUpdated(MemEntryImpl* entry) {
  93. // LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
  94. entry->RemoveFromList();
  95. lru_list_.Append(entry);
  96. }
  97. void MemBackendImpl::OnEntryDoomed(MemEntryImpl* entry) {
  98. if (entry->type() == MemEntryImpl::EntryType::kParent)
  99. entries_.erase(entry->key());
  100. // LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
  101. entry->RemoveFromList();
  102. }
  103. void MemBackendImpl::ModifyStorageSize(int32_t delta) {
  104. current_size_ += delta;
  105. if (delta > 0)
  106. EvictIfNeeded();
  107. }
  108. bool MemBackendImpl::HasExceededStorageSize() const {
  109. return current_size_ > max_size_;
  110. }
  111. void MemBackendImpl::SetPostCleanupCallback(base::OnceClosure cb) {
  112. DCHECK(post_cleanup_callback_.is_null());
  113. post_cleanup_callback_ = std::move(cb);
  114. }
  115. // static
  116. base::Time MemBackendImpl::Now(const base::WeakPtr<MemBackendImpl>& self) {
  117. MemBackendImpl* instance = self.get();
  118. if (instance && instance->custom_clock_for_testing_)
  119. return instance->custom_clock_for_testing_->Now();
  120. return Time::Now();
  121. }
  122. void MemBackendImpl::SetClockForTesting(base::Clock* clock) {
  123. custom_clock_for_testing_ = clock;
  124. }
  125. int32_t MemBackendImpl::GetEntryCount() const {
  126. return static_cast<int32_t>(entries_.size());
  127. }
  128. EntryResult MemBackendImpl::OpenOrCreateEntry(const std::string& key,
  129. net::RequestPriority priority,
  130. EntryResultCallback callback) {
  131. EntryResult result = OpenEntry(key, priority, EntryResultCallback());
  132. if (result.net_error() == net::OK)
  133. return result;
  134. // Key was not opened, try creating it instead.
  135. return CreateEntry(key, priority, EntryResultCallback());
  136. }
  137. EntryResult MemBackendImpl::OpenEntry(const std::string& key,
  138. net::RequestPriority request_priority,
  139. EntryResultCallback callback) {
  140. auto it = entries_.find(key);
  141. if (it == entries_.end())
  142. return EntryResult::MakeError(net::ERR_FAILED);
  143. it->second->Open();
  144. return EntryResult::MakeOpened(it->second);
  145. }
  146. EntryResult MemBackendImpl::CreateEntry(const std::string& key,
  147. net::RequestPriority request_priority,
  148. EntryResultCallback callback) {
  149. std::pair<EntryMap::iterator, bool> create_result =
  150. entries_.insert(EntryMap::value_type(key, nullptr));
  151. const bool did_insert = create_result.second;
  152. if (!did_insert)
  153. return EntryResult::MakeError(net::ERR_FAILED);
  154. MemEntryImpl* cache_entry =
  155. new MemEntryImpl(weak_factory_.GetWeakPtr(), key, net_log_);
  156. create_result.first->second = cache_entry;
  157. return EntryResult::MakeCreated(cache_entry);
  158. }
  159. net::Error MemBackendImpl::DoomEntry(const std::string& key,
  160. net::RequestPriority priority,
  161. CompletionOnceCallback callback) {
  162. auto it = entries_.find(key);
  163. if (it == entries_.end())
  164. return net::ERR_FAILED;
  165. it->second->Doom();
  166. return net::OK;
  167. }
  168. net::Error MemBackendImpl::DoomAllEntries(CompletionOnceCallback callback) {
  169. return DoomEntriesBetween(Time(), Time(), std::move(callback));
  170. }
  171. net::Error MemBackendImpl::DoomEntriesBetween(Time initial_time,
  172. Time end_time,
  173. CompletionOnceCallback callback) {
  174. if (end_time.is_null())
  175. end_time = Time::Max();
  176. DCHECK_GE(end_time, initial_time);
  177. base::LinkNode<MemEntryImpl>* node = lru_list_.head();
  178. while (node != lru_list_.end()) {
  179. MemEntryImpl* candidate = node->value();
  180. node = NextSkippingChildren(lru_list_, node);
  181. if (candidate->GetLastUsed() >= initial_time &&
  182. candidate->GetLastUsed() < end_time) {
  183. candidate->Doom();
  184. }
  185. }
  186. return net::OK;
  187. }
  188. net::Error MemBackendImpl::DoomEntriesSince(Time initial_time,
  189. CompletionOnceCallback callback) {
  190. return DoomEntriesBetween(initial_time, Time::Max(), std::move(callback));
  191. }
  192. int64_t MemBackendImpl::CalculateSizeOfAllEntries(
  193. Int64CompletionOnceCallback callback) {
  194. return current_size_;
  195. }
  196. int64_t MemBackendImpl::CalculateSizeOfEntriesBetween(
  197. base::Time initial_time,
  198. base::Time end_time,
  199. Int64CompletionOnceCallback callback) {
  200. if (end_time.is_null())
  201. end_time = Time::Max();
  202. DCHECK_GE(end_time, initial_time);
  203. int size = 0;
  204. base::LinkNode<MemEntryImpl>* node = lru_list_.head();
  205. while (node != lru_list_.end()) {
  206. MemEntryImpl* entry = node->value();
  207. if (entry->GetLastUsed() >= initial_time &&
  208. entry->GetLastUsed() < end_time) {
  209. size += entry->GetStorageSize();
  210. }
  211. node = node->next();
  212. }
  213. return size;
  214. }
  215. class MemBackendImpl::MemIterator final : public Backend::Iterator {
  216. public:
  217. explicit MemIterator(base::WeakPtr<MemBackendImpl> backend)
  218. : backend_(backend) {}
  219. EntryResult OpenNextEntry(EntryResultCallback callback) override {
  220. if (!backend_)
  221. return EntryResult::MakeError(net::ERR_FAILED);
  222. if (!backend_keys_) {
  223. backend_keys_ = std::make_unique<Strings>(backend_->entries_.size());
  224. for (const auto& iter : backend_->entries_)
  225. backend_keys_->push_back(iter.first);
  226. current_ = backend_keys_->begin();
  227. } else {
  228. current_++;
  229. }
  230. while (true) {
  231. if (current_ == backend_keys_->end()) {
  232. backend_keys_.reset();
  233. return EntryResult::MakeError(net::ERR_FAILED);
  234. }
  235. const auto& entry_iter = backend_->entries_.find(*current_);
  236. if (entry_iter == backend_->entries_.end()) {
  237. // The key is no longer in the cache, move on to the next key.
  238. current_++;
  239. continue;
  240. }
  241. entry_iter->second->Open();
  242. return EntryResult::MakeOpened(entry_iter->second);
  243. }
  244. }
  245. private:
  246. using Strings = std::vector<std::string>;
  247. base::WeakPtr<MemBackendImpl> backend_;
  248. std::unique_ptr<Strings> backend_keys_;
  249. Strings::iterator current_;
  250. };
  251. std::unique_ptr<Backend::Iterator> MemBackendImpl::CreateIterator() {
  252. return std::make_unique<MemIterator>(weak_factory_.GetWeakPtr());
  253. }
  254. void MemBackendImpl::OnExternalCacheHit(const std::string& key) {
  255. auto it = entries_.find(key);
  256. if (it != entries_.end())
  257. it->second->UpdateStateOnUse(MemEntryImpl::ENTRY_WAS_NOT_MODIFIED);
  258. }
  259. void MemBackendImpl::EvictIfNeeded() {
  260. if (current_size_ <= max_size_)
  261. return;
  262. int target_size = std::max(0, max_size_ - kDefaultEvictionSize);
  263. EvictTill(target_size);
  264. }
  265. void MemBackendImpl::EvictTill(int target_size) {
  266. base::LinkNode<MemEntryImpl>* entry = lru_list_.head();
  267. while (current_size_ > target_size && entry != lru_list_.end()) {
  268. MemEntryImpl* to_doom = entry->value();
  269. entry = NextSkippingChildren(lru_list_, entry);
  270. if (!to_doom->InUse())
  271. to_doom->Doom();
  272. }
  273. }
  274. void MemBackendImpl::OnMemoryPressure(
  275. base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
  276. switch (memory_pressure_level) {
  277. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
  278. break;
  279. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
  280. EvictTill(max_size_ / 2);
  281. break;
  282. case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
  283. EvictTill(max_size_ / 10);
  284. break;
  285. }
  286. }
  287. } // namespace disk_cache