Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: content/browser/dom_storage/dom_storage_namespace.cc

Issue 1953703004: Purge browser cache for dom storage in a smarter way (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@dom_storage
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/dom_storage/dom_storage_namespace.h" 5 #include "content/browser/dom_storage/dom_storage_namespace.h"
6 6
7 #include <algorithm>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/location.h" 10 #include "base/location.h"
9 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/sys_info.h"
10 #include "content/browser/dom_storage/dom_storage_area.h" 13 #include "content/browser/dom_storage/dom_storage_area.h"
11 #include "content/browser/dom_storage/dom_storage_task_runner.h" 14 #include "content/browser/dom_storage/dom_storage_task_runner.h"
12 #include "content/browser/dom_storage/session_storage_database.h" 15 #include "content/browser/dom_storage/session_storage_database.h"
13 #include "content/common/dom_storage/dom_storage_types.h" 16 #include "content/common/dom_storage/dom_storage_types.h"
14 17
15 namespace content { 18 namespace content {
16 19
17 DOMStorageNamespace::DOMStorageNamespace( 20 DOMStorageNamespace::DOMStorageNamespace(
18 const base::FilePath& directory, 21 const base::FilePath& directory,
19 DOMStorageTaskRunner* task_runner) 22 DOMStorageTaskRunner* task_runner)
20 : namespace_id_(kLocalStorageNamespaceId), 23 : namespace_id_(kLocalStorageNamespaceId),
21 directory_(directory), 24 directory_(directory),
22 task_runner_(task_runner) { 25 task_runner_(task_runner) {
23 } 26 }
24 27
25 DOMStorageNamespace::DOMStorageNamespace( 28 DOMStorageNamespace::DOMStorageNamespace(
26 int64_t namespace_id, 29 int64_t namespace_id,
27 const std::string& persistent_namespace_id, 30 const std::string& persistent_namespace_id,
28 SessionStorageDatabase* session_storage_database, 31 SessionStorageDatabase* session_storage_database,
29 DOMStorageTaskRunner* task_runner) 32 DOMStorageTaskRunner* task_runner)
30 : namespace_id_(namespace_id), 33 : namespace_id_(namespace_id),
31 persistent_namespace_id_(persistent_namespace_id), 34 persistent_namespace_id_(persistent_namespace_id),
32 task_runner_(task_runner), 35 task_runner_(task_runner),
33 session_storage_database_(session_storage_database) { 36 session_storage_database_(session_storage_database),
37 is_low_end_device_(base::SysInfo::IsLowEndDevice()) {
34 DCHECK_NE(kLocalStorageNamespaceId, namespace_id); 38 DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
35 } 39 }
36 40
37 DOMStorageNamespace::~DOMStorageNamespace() { 41 DOMStorageNamespace::~DOMStorageNamespace() {
38 } 42 }
39 43
40 DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) { 44 DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
41 if (AreaHolder* holder = GetAreaHolder(origin)) { 45 if (AreaHolder* holder = GetAreaHolder(origin)) {
42 ++(holder->open_count_); 46 ++(holder->open_count_);
43 return holder->area_.get(); 47 return holder->area_.get();
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 117
114 void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) { 118 void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
115 DOMStorageArea* area = OpenStorageArea(origin); 119 DOMStorageArea* area = OpenStorageArea(origin);
116 area->FastClear(); 120 area->FastClear();
117 CloseStorageArea(area); 121 CloseStorageArea(area);
118 } 122 }
119 123
120 void DOMStorageNamespace::PurgeMemory(PurgeOption option) { 124 void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
121 if (directory_.empty()) 125 if (directory_.empty())
122 return; // We can't purge w/o backing on disk. 126 return; // We can't purge w/o backing on disk.
127
128 option = std::max(option, FindPurgeLevel());
129 if (option == PURGE_UNSPECIFIED)
130 return;
131
123 AreaMap::iterator it = areas_.begin(); 132 AreaMap::iterator it = areas_.begin();
124 while (it != areas_.end()) { 133 while (it != areas_.end()) {
125 const AreaHolder& holder = it->second; 134 const AreaHolder& holder = it->second;
126 135
127 // We can't purge if there are changes pending. 136 // We can't purge if there are changes pending.
128 if (holder.area_->HasUncommittedChanges()) { 137 if (holder.area_->HasUncommittedChanges()) {
129 if (holder.open_count_ == 0) { 138 if (holder.open_count_ == 0) {
130 // Schedule an immediate commit so the next time we're asked to purge, 139 // Schedule an immediate commit so the next time we're asked to purge,
131 // we can drop it from memory. 140 // we can drop it from memory.
132 holder.area_->ScheduleImmediateCommit(); 141 holder.area_->ScheduleImmediateCommit();
133 } 142 }
134 ++it; 143
144 if (option == PURGE_AGGRESSIVE)
145 holder.area_->TrimDatabase();
146 it++;
135 continue; 147 continue;
136 } 148 }
137 149
138 // If not in use, we can shut it down and remove 150 // If not in use, we can shut it down and remove
139 // it from our collection entirely. 151 // it from our collection entirely.
140 if (holder.open_count_ == 0) { 152 if (holder.open_count_ == 0) {
141 holder.area_->Shutdown(); 153 holder.area_->Shutdown();
142 areas_.erase(it++); 154 areas_.erase(it++);
143 continue; 155 continue;
144 } 156 }
145 157
146 if (option == PURGE_AGGRESSIVE) { 158 if (option == PURGE_AGGRESSIVE) {
147 // If aggressive is true, we clear caches and such 159 // If aggressive is true, we clear caches and such
148 // for opened areas. 160 // for opened areas.
149 holder.area_->PurgeMemory(); 161 holder.area_->PurgeMemory();
150 } 162 }
151 163 it++;
152 ++it;
153 } 164 }
154 } 165 }
155 166
167 // This function works based on the cache sizes without including the database
168 // size since it can be expensive trying to estimate the sqlite usage for all
169 // databases.
170 DOMStorageNamespace::PurgeOption DOMStorageNamespace::FindPurgeLevel() {
171 // Maximum in-memory cache usage of all databases.
172 size_t in_memory_areas_size_budget = 20 * 1024 * 1024;
173 // Maximum in-memory cache usage of databases that are open.
174 size_t inactive_in_memory_area_size_budget = 20 * 1024 * 1024;
175 // Number of areas over which the open databases can be purged.
176 size_t active_in_memory_areas_unpurged = 100;
177 #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
178 if (is_low_end_device_) {
179 // For low-end devices, when the cache size reaches 5Mib, only 10 open
180 // databases are allowed before being purged.
181 active_in_memory_areas_unpurged = 10;
182 in_memory_areas_size_budget = 5 * 1024 * 1024;
183 // Clear most of the inactive database on low-end device.
184 inactive_in_memory_area_size_budget = 100 * 1024;
185 } else {
186 // Set a low cache budget for inactive database cache on android.
187 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
188 }
189 #endif
190
191 size_t total_cache_size = 0;
192 size_t area_count = 0;
193 size_t active_areas_cache_size = 0;
194 unsigned active_areas_count = 0;
195 for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
196 if (it->second.area_->IsLoadedInMemory()) {
197 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.
198 total_cache_size += cache_size;
199 ++area_count;
200 if (it->second.open_count_ > 0) {
201 active_areas_cache_size += cache_size;
202 ++active_areas_count;
203 }
204 }
205 }
206
207 if (active_areas_cache_size > in_memory_areas_size_budget &&
208 active_areas_count > active_in_memory_areas_unpurged) {
209 return PURGE_AGGRESSIVE;
210 }
211
212 size_t purgeable_cache_size = total_cache_size - active_areas_cache_size;
213 if (purgeable_cache_size) {
214 if (purgeable_cache_size > inactive_in_memory_area_size_budget ||
215 total_cache_size > in_memory_areas_size_budget) {
216 return PURGE_UNOPENED;
217 }
218 }
219 return PURGE_UNSPECIFIED;
220 }
221
156 void DOMStorageNamespace::Shutdown() { 222 void DOMStorageNamespace::Shutdown() {
157 AreaMap::const_iterator it = areas_.begin(); 223 AreaMap::const_iterator it = areas_.begin();
158 for (; it != areas_.end(); ++it) 224 for (; it != areas_.end(); ++it)
159 it->second.area_->Shutdown(); 225 it->second.area_->Shutdown();
160 } 226 }
161 227
162 void DOMStorageNamespace::Flush() { 228 void DOMStorageNamespace::Flush() {
163 for (auto& entry : areas_) { 229 for (auto& entry : areas_) {
164 if (!entry.second.area_->HasUncommittedChanges()) 230 if (!entry.second.area_->HasUncommittedChanges())
165 continue; 231 continue;
166 entry.second.area_->ScheduleImmediateCommit(); 232 entry.second.area_->ScheduleImmediateCommit();
167 } 233 }
168 } 234 }
169 235
170 unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
171 unsigned int area_count = 0;
172 for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
173 if (it->second.area_->IsLoadedInMemory())
174 ++area_count;
175 }
176 return area_count;
177 }
178
179 void DOMStorageNamespace::OnMemoryDump( 236 void DOMStorageNamespace::OnMemoryDump(
180 base::trace_event::ProcessMemoryDump* pmd) { 237 base::trace_event::ProcessMemoryDump* pmd) {
181 DCHECK(task_runner_->IsRunningOnPrimarySequence()); 238 DCHECK(task_runner_->IsRunningOnPrimarySequence());
182 for (const auto& it : areas_) 239 for (const auto& it : areas_)
183 it.second.area_->OnMemoryDump(pmd); 240 it.second.area_->OnMemoryDump(pmd);
184 } 241 }
185 242
186 DOMStorageNamespace::AreaHolder* 243 DOMStorageNamespace::AreaHolder*
187 DOMStorageNamespace::GetAreaHolder(const GURL& origin) { 244 DOMStorageNamespace::GetAreaHolder(const GURL& origin) {
188 AreaMap::iterator found = areas_.find(origin); 245 AreaMap::iterator found = areas_.find(origin);
(...skipping 12 matching lines...) Expand all
201 DOMStorageArea* area, int count) 258 DOMStorageArea* area, int count)
202 : area_(area), open_count_(count) { 259 : area_(area), open_count_(count) {
203 } 260 }
204 261
205 DOMStorageNamespace::AreaHolder::AreaHolder(const AreaHolder& other) = default; 262 DOMStorageNamespace::AreaHolder::AreaHolder(const AreaHolder& other) = default;
206 263
207 DOMStorageNamespace::AreaHolder::~AreaHolder() { 264 DOMStorageNamespace::AreaHolder::~AreaHolder() {
208 } 265 }
209 266
210 } // namespace content 267 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698