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()); |