Chromium Code Reviews| Index: content/browser/dom_storage/dom_storage_namespace.cc |
| diff --git a/content/browser/dom_storage/dom_storage_namespace.cc b/content/browser/dom_storage/dom_storage_namespace.cc |
| index 72fae88fcedd3743a0f2d1707a6aa4a3f087975f..6ba3f6b0f87cdaaad00b7e9aeea82e105a02b440 100644 |
| --- a/content/browser/dom_storage/dom_storage_namespace.cc |
| +++ b/content/browser/dom_storage/dom_storage_namespace.cc |
| @@ -4,9 +4,12 @@ |
| #include "content/browser/dom_storage/dom_storage_namespace.h" |
| +#include <algorithm> |
| + |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| +#include "base/sys_info.h" |
| #include "content/browser/dom_storage/dom_storage_area.h" |
| #include "content/browser/dom_storage/dom_storage_task_runner.h" |
| #include "content/browser/dom_storage/session_storage_database.h" |
| @@ -30,7 +33,8 @@ DOMStorageNamespace::DOMStorageNamespace( |
| : namespace_id_(namespace_id), |
| persistent_namespace_id_(persistent_namespace_id), |
| task_runner_(task_runner), |
| - session_storage_database_(session_storage_database) { |
| + session_storage_database_(session_storage_database), |
| + is_low_end_device_(base::SysInfo::IsLowEndDevice()) { |
| DCHECK_NE(kLocalStorageNamespaceId, namespace_id); |
| } |
| @@ -120,6 +124,11 @@ void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) { |
| void DOMStorageNamespace::PurgeMemory(PurgeOption option) { |
| if (directory_.empty()) |
| return; // We can't purge w/o backing on disk. |
| + |
| + option = std::max(option, FindPurgeLevel()); |
| + if (option == PURGE_UNSPECIFIED) |
| + return; |
| + |
| AreaMap::iterator it = areas_.begin(); |
| while (it != areas_.end()) { |
| const AreaHolder& holder = it->second; |
| @@ -131,7 +140,10 @@ void DOMStorageNamespace::PurgeMemory(PurgeOption option) { |
| // we can drop it from memory. |
| holder.area_->ScheduleImmediateCommit(); |
| } |
| - ++it; |
| + |
| + if (option == PURGE_AGGRESSIVE) |
| + holder.area_->TrimDatabase(); |
| + it++; |
| continue; |
| } |
| @@ -148,9 +160,63 @@ void DOMStorageNamespace::PurgeMemory(PurgeOption option) { |
| // for opened areas. |
| holder.area_->PurgeMemory(); |
| } |
| + it++; |
| + } |
| +} |
| + |
| +// This function works based on the cache sizes without including the database |
| +// size since it can be expensive trying to estimate the sqlite usage for all |
| +// databases. |
| +DOMStorageNamespace::PurgeOption DOMStorageNamespace::FindPurgeLevel() { |
| + // Maximum in-memory cache usage of all databases. |
| + size_t in_memory_areas_size_budget = 20 * 1024 * 1024; |
| + // Maximum in-memory cache usage of databases that are open. |
| + size_t inactive_in_memory_area_size_budget = 20 * 1024 * 1024; |
| + // Number of areas over which the open databases can be purged. |
| + size_t active_in_memory_areas_unpurged = 100; |
| +#if defined(OS_ANDROID) |
|
michaeln
2016/05/09 22:12:17
This might be more complicated then it needs to be
ssid
2016/05/10 02:04:16
I agree this is very complicated. I was expecting
|
| + if (is_low_end_device_) { |
| + // For low-end devices, when the cache size reaches 5Mib, only 10 open |
| + // databases are allowed before being purged. |
| + active_in_memory_areas_unpurged = 10; |
| + in_memory_areas_size_budget = 5 * 1024 * 1024; |
| + // Clear most of the inactive database on low-end device. |
| + inactive_in_memory_area_size_budget = 100 * 1024; |
| + } else { |
| + // Set a low cache budget for inactive database cache on android. |
| + inactive_in_memory_area_size_budget = 1024 * 1024; |
|
ssid
2016/05/06 03:28:51
I chose these values based on what sizes I observe
michaeln
2016/05/09 22:12:17
we don't have stats for the number of 'area in use
|
| + } |
| +#endif |
| + |
| + size_t total_cache_size = 0; |
| + size_t area_count = 0; |
| + size_t active_areas_cache_size = 0; |
| + unsigned active_areas_count = 0; |
| + for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) { |
| + if (it->second.area_->IsLoadedInMemory()) { |
| + size_t cache_size = it->second.area_->map_usage_in_bytes(); |
|
ssid
2016/05/06 03:28:52
Do you think just the cache size is a good estimat
michaeln
2016/05/09 22:12:17
Sure, this is what we have to work with.
|
| + total_cache_size += cache_size; |
| + ++area_count; |
| + if (it->second.open_count_ > 0) { |
| + active_areas_cache_size += cache_size; |
| + ++active_areas_count; |
| + } |
| + } |
| + } |
| + |
| + if (active_areas_cache_size > in_memory_areas_size_budget && |
| + active_areas_count > active_in_memory_areas_unpurged) { |
| + return PURGE_AGGRESSIVE; |
| + } |
| - ++it; |
| + size_t purgeable_cache_size = total_cache_size - active_areas_cache_size; |
| + if (purgeable_cache_size) { |
| + if (purgeable_cache_size > inactive_in_memory_area_size_budget || |
| + total_cache_size > in_memory_areas_size_budget) { |
| + return PURGE_UNOPENED; |
| + } |
| } |
| + return PURGE_UNSPECIFIED; |
| } |
| void DOMStorageNamespace::Shutdown() { |
| @@ -167,15 +233,6 @@ void DOMStorageNamespace::Flush() { |
| } |
| } |
| -unsigned int DOMStorageNamespace::CountInMemoryAreas() const { |
| - unsigned int area_count = 0; |
| - for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) { |
| - if (it->second.area_->IsLoadedInMemory()) |
| - ++area_count; |
| - } |
| - return area_count; |
| -} |
| - |
| void DOMStorageNamespace::OnMemoryDump( |
| base::trace_event::ProcessMemoryDump* pmd) { |
| DCHECK(task_runner_->IsRunningOnPrimarySequence()); |