OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "webkit/browser/dom_storage/dom_storage_area.h" | 5 #include "content/browser/dom_storage/dom_storage_area.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 13 #include "content/browser/dom_storage/dom_storage_namespace.h" |
| 14 #include "content/browser/dom_storage/dom_storage_task_runner.h" |
| 15 #include "content/browser/dom_storage/local_storage_database_adapter.h" |
| 16 #include "content/browser/dom_storage/session_storage_database.h" |
| 17 #include "content/browser/dom_storage/session_storage_database_adapter.h" |
| 18 #include "content/common/dom_storage/dom_storage_map.h" |
| 19 #include "content/common/dom_storage/dom_storage_types.h" |
13 #include "webkit/browser/database/database_util.h" | 20 #include "webkit/browser/database/database_util.h" |
14 #include "webkit/browser/dom_storage/dom_storage_namespace.h" | |
15 #include "webkit/browser/dom_storage/dom_storage_task_runner.h" | |
16 #include "webkit/browser/dom_storage/local_storage_database_adapter.h" | |
17 #include "webkit/browser/dom_storage/session_storage_database.h" | |
18 #include "webkit/browser/dom_storage/session_storage_database_adapter.h" | |
19 #include "webkit/common/database/database_identifier.h" | 21 #include "webkit/common/database/database_identifier.h" |
20 #include "webkit/common/dom_storage/dom_storage_map.h" | |
21 #include "webkit/common/dom_storage/dom_storage_types.h" | |
22 #include "webkit/common/fileapi/file_system_util.h" | 22 #include "webkit/common/fileapi/file_system_util.h" |
23 | 23 |
24 using webkit_database::DatabaseUtil; | 24 using webkit_database::DatabaseUtil; |
25 | 25 |
26 namespace dom_storage { | 26 namespace content { |
27 | 27 |
28 static const int kCommitTimerSeconds = 1; | 28 static const int kCommitTimerSeconds = 1; |
29 | 29 |
30 DomStorageArea::CommitBatch::CommitBatch() | 30 DOMStorageArea::CommitBatch::CommitBatch() |
31 : clear_all_first(false) { | 31 : clear_all_first(false) { |
32 } | 32 } |
33 DomStorageArea::CommitBatch::~CommitBatch() {} | 33 DOMStorageArea::CommitBatch::~CommitBatch() {} |
34 | 34 |
35 | 35 |
36 // static | 36 // static |
37 const base::FilePath::CharType DomStorageArea::kDatabaseFileExtension[] = | 37 const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] = |
38 FILE_PATH_LITERAL(".localstorage"); | 38 FILE_PATH_LITERAL(".localstorage"); |
39 | 39 |
40 // static | 40 // static |
41 base::FilePath DomStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) { | 41 base::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) { |
42 std::string filename = webkit_database::GetIdentifierFromOrigin(origin); | 42 std::string filename = webkit_database::GetIdentifierFromOrigin(origin); |
43 // There is no base::FilePath.AppendExtension() method, so start with just the | 43 // There is no base::FilePath.AppendExtension() method, so start with just the |
44 // extension as the filename, and then InsertBeforeExtension the desired | 44 // extension as the filename, and then InsertBeforeExtension the desired |
45 // name. | 45 // name. |
46 return base::FilePath().Append(kDatabaseFileExtension). | 46 return base::FilePath().Append(kDatabaseFileExtension). |
47 InsertBeforeExtensionASCII(filename); | 47 InsertBeforeExtensionASCII(filename); |
48 } | 48 } |
49 | 49 |
50 // static | 50 // static |
51 GURL DomStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) { | 51 GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) { |
52 DCHECK(name.MatchesExtension(kDatabaseFileExtension)); | 52 DCHECK(name.MatchesExtension(kDatabaseFileExtension)); |
53 std::string origin_id = | 53 std::string origin_id = |
54 name.BaseName().RemoveExtension().MaybeAsASCII(); | 54 name.BaseName().RemoveExtension().MaybeAsASCII(); |
55 return webkit_database::GetOriginFromIdentifier(origin_id); | 55 return webkit_database::GetOriginFromIdentifier(origin_id); |
56 } | 56 } |
57 | 57 |
58 DomStorageArea::DomStorageArea(const GURL& origin, const base::FilePath& directo
ry, | 58 DOMStorageArea::DOMStorageArea( |
59 DomStorageTaskRunner* task_runner) | 59 const GURL& origin, const base::FilePath& directory, |
| 60 DOMStorageTaskRunner* task_runner) |
60 : namespace_id_(kLocalStorageNamespaceId), origin_(origin), | 61 : namespace_id_(kLocalStorageNamespaceId), origin_(origin), |
61 directory_(directory), | 62 directory_(directory), |
62 task_runner_(task_runner), | 63 task_runner_(task_runner), |
63 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)), | 64 map_(new DOMStorageMap(kPerStorageAreaQuota + |
| 65 kPerStorageAreaOverQuotaAllowance)), |
64 is_initial_import_done_(true), | 66 is_initial_import_done_(true), |
65 is_shutdown_(false), | 67 is_shutdown_(false), |
66 commit_batches_in_flight_(0) { | 68 commit_batches_in_flight_(0) { |
67 if (!directory.empty()) { | 69 if (!directory.empty()) { |
68 base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); | 70 base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); |
69 backing_.reset(new LocalStorageDatabaseAdapter(path)); | 71 backing_.reset(new LocalStorageDatabaseAdapter(path)); |
70 is_initial_import_done_ = false; | 72 is_initial_import_done_ = false; |
71 } | 73 } |
72 } | 74 } |
73 | 75 |
74 DomStorageArea::DomStorageArea( | 76 DOMStorageArea::DOMStorageArea( |
75 int64 namespace_id, | 77 int64 namespace_id, |
76 const std::string& persistent_namespace_id, | 78 const std::string& persistent_namespace_id, |
77 const GURL& origin, | 79 const GURL& origin, |
78 SessionStorageDatabase* session_storage_backing, | 80 SessionStorageDatabase* session_storage_backing, |
79 DomStorageTaskRunner* task_runner) | 81 DOMStorageTaskRunner* task_runner) |
80 : namespace_id_(namespace_id), | 82 : namespace_id_(namespace_id), |
81 persistent_namespace_id_(persistent_namespace_id), | 83 persistent_namespace_id_(persistent_namespace_id), |
82 origin_(origin), | 84 origin_(origin), |
83 task_runner_(task_runner), | 85 task_runner_(task_runner), |
84 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)), | 86 map_(new DOMStorageMap(kPerStorageAreaQuota + |
| 87 kPerStorageAreaOverQuotaAllowance)), |
85 session_storage_backing_(session_storage_backing), | 88 session_storage_backing_(session_storage_backing), |
86 is_initial_import_done_(true), | 89 is_initial_import_done_(true), |
87 is_shutdown_(false), | 90 is_shutdown_(false), |
88 commit_batches_in_flight_(0) { | 91 commit_batches_in_flight_(0) { |
89 DCHECK(namespace_id != kLocalStorageNamespaceId); | 92 DCHECK(namespace_id != kLocalStorageNamespaceId); |
90 if (session_storage_backing) { | 93 if (session_storage_backing) { |
91 backing_.reset(new SessionStorageDatabaseAdapter( | 94 backing_.reset(new SessionStorageDatabaseAdapter( |
92 session_storage_backing, persistent_namespace_id, origin)); | 95 session_storage_backing, persistent_namespace_id, origin)); |
93 is_initial_import_done_ = false; | 96 is_initial_import_done_ = false; |
94 } | 97 } |
95 } | 98 } |
96 | 99 |
97 DomStorageArea::~DomStorageArea() { | 100 DOMStorageArea::~DOMStorageArea() { |
98 } | 101 } |
99 | 102 |
100 void DomStorageArea::ExtractValues(ValuesMap* map) { | 103 void DOMStorageArea::ExtractValues(DOMStorageValuesMap* map) { |
101 if (is_shutdown_) | 104 if (is_shutdown_) |
102 return; | 105 return; |
103 InitialImportIfNeeded(); | 106 InitialImportIfNeeded(); |
104 map_->ExtractValues(map); | 107 map_->ExtractValues(map); |
105 } | 108 } |
106 | 109 |
107 unsigned DomStorageArea::Length() { | 110 unsigned DOMStorageArea::Length() { |
108 if (is_shutdown_) | 111 if (is_shutdown_) |
109 return 0; | 112 return 0; |
110 InitialImportIfNeeded(); | 113 InitialImportIfNeeded(); |
111 return map_->Length(); | 114 return map_->Length(); |
112 } | 115 } |
113 | 116 |
114 base::NullableString16 DomStorageArea::Key(unsigned index) { | 117 base::NullableString16 DOMStorageArea::Key(unsigned index) { |
115 if (is_shutdown_) | 118 if (is_shutdown_) |
116 return base::NullableString16(); | 119 return base::NullableString16(); |
117 InitialImportIfNeeded(); | 120 InitialImportIfNeeded(); |
118 return map_->Key(index); | 121 return map_->Key(index); |
119 } | 122 } |
120 | 123 |
121 base::NullableString16 DomStorageArea::GetItem(const base::string16& key) { | 124 base::NullableString16 DOMStorageArea::GetItem(const base::string16& key) { |
122 if (is_shutdown_) | 125 if (is_shutdown_) |
123 return base::NullableString16(); | 126 return base::NullableString16(); |
124 InitialImportIfNeeded(); | 127 InitialImportIfNeeded(); |
125 return map_->GetItem(key); | 128 return map_->GetItem(key); |
126 } | 129 } |
127 | 130 |
128 bool DomStorageArea::SetItem(const base::string16& key, | 131 bool DOMStorageArea::SetItem(const base::string16& key, |
129 const base::string16& value, | 132 const base::string16& value, |
130 base::NullableString16* old_value) { | 133 base::NullableString16* old_value) { |
131 if (is_shutdown_) | 134 if (is_shutdown_) |
132 return false; | 135 return false; |
133 InitialImportIfNeeded(); | 136 InitialImportIfNeeded(); |
134 if (!map_->HasOneRef()) | 137 if (!map_->HasOneRef()) |
135 map_ = map_->DeepCopy(); | 138 map_ = map_->DeepCopy(); |
136 bool success = map_->SetItem(key, value, old_value); | 139 bool success = map_->SetItem(key, value, old_value); |
137 if (success && backing_) { | 140 if (success && backing_) { |
138 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); | 141 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); |
139 commit_batch->changed_values[key] = base::NullableString16(value, false); | 142 commit_batch->changed_values[key] = base::NullableString16(value, false); |
140 } | 143 } |
141 return success; | 144 return success; |
142 } | 145 } |
143 | 146 |
144 bool DomStorageArea::RemoveItem(const base::string16& key, | 147 bool DOMStorageArea::RemoveItem(const base::string16& key, |
145 base::string16* old_value) { | 148 base::string16* old_value) { |
146 if (is_shutdown_) | 149 if (is_shutdown_) |
147 return false; | 150 return false; |
148 InitialImportIfNeeded(); | 151 InitialImportIfNeeded(); |
149 if (!map_->HasOneRef()) | 152 if (!map_->HasOneRef()) |
150 map_ = map_->DeepCopy(); | 153 map_ = map_->DeepCopy(); |
151 bool success = map_->RemoveItem(key, old_value); | 154 bool success = map_->RemoveItem(key, old_value); |
152 if (success && backing_) { | 155 if (success && backing_) { |
153 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); | 156 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); |
154 commit_batch->changed_values[key] = base::NullableString16(); | 157 commit_batch->changed_values[key] = base::NullableString16(); |
155 } | 158 } |
156 return success; | 159 return success; |
157 } | 160 } |
158 | 161 |
159 bool DomStorageArea::Clear() { | 162 bool DOMStorageArea::Clear() { |
160 if (is_shutdown_) | 163 if (is_shutdown_) |
161 return false; | 164 return false; |
162 InitialImportIfNeeded(); | 165 InitialImportIfNeeded(); |
163 if (map_->Length() == 0) | 166 if (map_->Length() == 0) |
164 return false; | 167 return false; |
165 | 168 |
166 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); | 169 map_ = new DOMStorageMap(kPerStorageAreaQuota + |
| 170 kPerStorageAreaOverQuotaAllowance); |
167 | 171 |
168 if (backing_) { | 172 if (backing_) { |
169 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); | 173 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); |
170 commit_batch->clear_all_first = true; | 174 commit_batch->clear_all_first = true; |
171 commit_batch->changed_values.clear(); | 175 commit_batch->changed_values.clear(); |
172 } | 176 } |
173 | 177 |
174 return true; | 178 return true; |
175 } | 179 } |
176 | 180 |
177 void DomStorageArea::FastClear() { | 181 void DOMStorageArea::FastClear() { |
178 // TODO(marja): Unify clearing localStorage and sessionStorage. The problem is | 182 // TODO(marja): Unify clearing localStorage and sessionStorage. The problem is |
179 // to make the following 3 to work together: 1) FastClear, 2) PurgeMemory and | 183 // to make the following 3 to work together: 1) FastClear, 2) PurgeMemory and |
180 // 3) not creating events when clearing an empty area. | 184 // 3) not creating events when clearing an empty area. |
181 if (is_shutdown_) | 185 if (is_shutdown_) |
182 return; | 186 return; |
183 | 187 |
184 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); | 188 map_ = new DOMStorageMap(kPerStorageAreaQuota + |
| 189 kPerStorageAreaOverQuotaAllowance); |
185 // This ensures no import will happen while we're waiting to clear the data | 190 // This ensures no import will happen while we're waiting to clear the data |
186 // from the database. This mechanism fails if PurgeMemory is called. | 191 // from the database. This mechanism fails if PurgeMemory is called. |
187 is_initial_import_done_ = true; | 192 is_initial_import_done_ = true; |
188 | 193 |
189 if (backing_) { | 194 if (backing_) { |
190 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); | 195 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); |
191 commit_batch->clear_all_first = true; | 196 commit_batch->clear_all_first = true; |
192 commit_batch->changed_values.clear(); | 197 commit_batch->changed_values.clear(); |
193 } | 198 } |
194 } | 199 } |
195 | 200 |
196 DomStorageArea* DomStorageArea::ShallowCopy( | 201 DOMStorageArea* DOMStorageArea::ShallowCopy( |
197 int64 destination_namespace_id, | 202 int64 destination_namespace_id, |
198 const std::string& destination_persistent_namespace_id) { | 203 const std::string& destination_persistent_namespace_id) { |
199 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_); | 204 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_); |
200 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); | 205 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); |
201 | 206 |
202 DomStorageArea* copy = new DomStorageArea( | 207 DOMStorageArea* copy = new DOMStorageArea( |
203 destination_namespace_id, destination_persistent_namespace_id, origin_, | 208 destination_namespace_id, destination_persistent_namespace_id, origin_, |
204 session_storage_backing_.get(), task_runner_.get()); | 209 session_storage_backing_.get(), task_runner_.get()); |
205 copy->map_ = map_; | 210 copy->map_ = map_; |
206 copy->is_shutdown_ = is_shutdown_; | 211 copy->is_shutdown_ = is_shutdown_; |
207 copy->is_initial_import_done_ = true; | 212 copy->is_initial_import_done_ = true; |
208 | 213 |
209 // All the uncommitted changes to this area need to happen before the actual | 214 // All the uncommitted changes to this area need to happen before the actual |
210 // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer | 215 // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer |
211 // call might be in the event queue at this point, but it's handled gracefully | 216 // call might be in the event queue at this point, but it's handled gracefully |
212 // when it fires. | 217 // when it fires. |
213 if (commit_batch_) | 218 if (commit_batch_) |
214 OnCommitTimer(); | 219 OnCommitTimer(); |
215 return copy; | 220 return copy; |
216 } | 221 } |
217 | 222 |
218 bool DomStorageArea::HasUncommittedChanges() const { | 223 bool DOMStorageArea::HasUncommittedChanges() const { |
219 DCHECK(!is_shutdown_); | 224 DCHECK(!is_shutdown_); |
220 return commit_batch_.get() || commit_batches_in_flight_; | 225 return commit_batch_.get() || commit_batches_in_flight_; |
221 } | 226 } |
222 | 227 |
223 void DomStorageArea::DeleteOrigin() { | 228 void DOMStorageArea::DeleteOrigin() { |
224 DCHECK(!is_shutdown_); | 229 DCHECK(!is_shutdown_); |
225 // This function shouldn't be called for sessionStorage. | 230 // This function shouldn't be called for sessionStorage. |
226 DCHECK(!session_storage_backing_.get()); | 231 DCHECK(!session_storage_backing_.get()); |
227 if (HasUncommittedChanges()) { | 232 if (HasUncommittedChanges()) { |
228 // TODO(michaeln): This logically deletes the data immediately, | 233 // TODO(michaeln): This logically deletes the data immediately, |
229 // and in a matter of a second, deletes the rows from the backing | 234 // and in a matter of a second, deletes the rows from the backing |
230 // database file, but the file itself will linger until shutdown | 235 // database file, but the file itself will linger until shutdown |
231 // or purge time. Ideally, this should delete the file more | 236 // or purge time. Ideally, this should delete the file more |
232 // quickly. | 237 // quickly. |
233 Clear(); | 238 Clear(); |
234 return; | 239 return; |
235 } | 240 } |
236 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); | 241 map_ = new DOMStorageMap(kPerStorageAreaQuota + |
| 242 kPerStorageAreaOverQuotaAllowance); |
237 if (backing_) { | 243 if (backing_) { |
238 is_initial_import_done_ = false; | 244 is_initial_import_done_ = false; |
239 backing_->Reset(); | 245 backing_->Reset(); |
240 backing_->DeleteFiles(); | 246 backing_->DeleteFiles(); |
241 } | 247 } |
242 } | 248 } |
243 | 249 |
244 void DomStorageArea::PurgeMemory() { | 250 void DOMStorageArea::PurgeMemory() { |
245 DCHECK(!is_shutdown_); | 251 DCHECK(!is_shutdown_); |
246 // Purging sessionStorage is not supported; it won't work with FastClear. | 252 // Purging sessionStorage is not supported; it won't work with FastClear. |
247 DCHECK(!session_storage_backing_.get()); | 253 DCHECK(!session_storage_backing_.get()); |
248 if (!is_initial_import_done_ || // We're not using any memory. | 254 if (!is_initial_import_done_ || // We're not using any memory. |
249 !backing_.get() || // We can't purge anything. | 255 !backing_.get() || // We can't purge anything. |
250 HasUncommittedChanges()) // We leave things alone with changes pending. | 256 HasUncommittedChanges()) // We leave things alone with changes pending. |
251 return; | 257 return; |
252 | 258 |
253 // Drop the in memory cache, we'll reload when needed. | 259 // Drop the in memory cache, we'll reload when needed. |
254 is_initial_import_done_ = false; | 260 is_initial_import_done_ = false; |
255 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); | 261 map_ = new DOMStorageMap(kPerStorageAreaQuota + |
| 262 kPerStorageAreaOverQuotaAllowance); |
256 | 263 |
257 // Recreate the database object, this frees up the open sqlite connection | 264 // Recreate the database object, this frees up the open sqlite connection |
258 // and its page cache. | 265 // and its page cache. |
259 backing_->Reset(); | 266 backing_->Reset(); |
260 } | 267 } |
261 | 268 |
262 void DomStorageArea::Shutdown() { | 269 void DOMStorageArea::Shutdown() { |
263 DCHECK(!is_shutdown_); | 270 DCHECK(!is_shutdown_); |
264 is_shutdown_ = true; | 271 is_shutdown_ = true; |
265 map_ = NULL; | 272 map_ = NULL; |
266 if (!backing_) | 273 if (!backing_) |
267 return; | 274 return; |
268 | 275 |
269 bool success = task_runner_->PostShutdownBlockingTask( | 276 bool success = task_runner_->PostShutdownBlockingTask( |
270 FROM_HERE, | 277 FROM_HERE, |
271 DomStorageTaskRunner::COMMIT_SEQUENCE, | 278 DOMStorageTaskRunner::COMMIT_SEQUENCE, |
272 base::Bind(&DomStorageArea::ShutdownInCommitSequence, this)); | 279 base::Bind(&DOMStorageArea::ShutdownInCommitSequence, this)); |
273 DCHECK(success); | 280 DCHECK(success); |
274 } | 281 } |
275 | 282 |
276 void DomStorageArea::InitialImportIfNeeded() { | 283 void DOMStorageArea::InitialImportIfNeeded() { |
277 if (is_initial_import_done_) | 284 if (is_initial_import_done_) |
278 return; | 285 return; |
279 | 286 |
280 DCHECK(backing_.get()); | 287 DCHECK(backing_.get()); |
281 | 288 |
282 base::TimeTicks before = base::TimeTicks::Now(); | 289 base::TimeTicks before = base::TimeTicks::Now(); |
283 ValuesMap initial_values; | 290 DOMStorageValuesMap initial_values; |
284 backing_->ReadAllValues(&initial_values); | 291 backing_->ReadAllValues(&initial_values); |
285 map_->SwapValues(&initial_values); | 292 map_->SwapValues(&initial_values); |
286 is_initial_import_done_ = true; | 293 is_initial_import_done_ = true; |
287 base::TimeDelta time_to_import = base::TimeTicks::Now() - before; | 294 base::TimeDelta time_to_import = base::TimeTicks::Now() - before; |
288 UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage", | 295 UMA_HISTOGRAM_TIMES("LocalStorage.BrowserTimeToPrimeLocalStorage", |
289 time_to_import); | 296 time_to_import); |
290 | 297 |
291 size_t local_storage_size_kb = map_->bytes_used() / 1024; | 298 size_t local_storage_size_kb = map_->bytes_used() / 1024; |
292 // Track localStorage size, from 0-6MB. Note that the maximum size should be | 299 // Track localStorage size, from 0-6MB. Note that the maximum size should be |
293 // 5MB, but we add some slop since we want to make sure the max size is always | 300 // 5MB, but we add some slop since we want to make sure the max size is always |
294 // above what we see in practice, since histograms can't change. | 301 // above what we see in practice, since histograms can't change. |
295 UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.BrowserLocalStorageSizeInKB", | 302 UMA_HISTOGRAM_CUSTOM_COUNTS("LocalStorage.BrowserLocalStorageSizeInKB", |
296 local_storage_size_kb, | 303 local_storage_size_kb, |
297 0, 6 * 1024, 50); | 304 0, 6 * 1024, 50); |
298 if (local_storage_size_kb < 100) { | 305 if (local_storage_size_kb < 100) { |
299 UMA_HISTOGRAM_TIMES( | 306 UMA_HISTOGRAM_TIMES( |
300 "LocalStorage.BrowserTimeToPrimeLocalStorageUnder100KB", | 307 "LocalStorage.BrowserTimeToPrimeLocalStorageUnder100KB", |
301 time_to_import); | 308 time_to_import); |
302 } else if (local_storage_size_kb < 1000) { | 309 } else if (local_storage_size_kb < 1000) { |
303 UMA_HISTOGRAM_TIMES( | 310 UMA_HISTOGRAM_TIMES( |
304 "LocalStorage.BrowserTimeToPrimeLocalStorage100KBTo1MB", | 311 "LocalStorage.BrowserTimeToPrimeLocalStorage100KBTo1MB", |
305 time_to_import); | 312 time_to_import); |
306 } else { | 313 } else { |
307 UMA_HISTOGRAM_TIMES( | 314 UMA_HISTOGRAM_TIMES( |
308 "LocalStorage.BrowserTimeToPrimeLocalStorage1MBTo5MB", | 315 "LocalStorage.BrowserTimeToPrimeLocalStorage1MBTo5MB", |
309 time_to_import); | 316 time_to_import); |
310 } | 317 } |
311 } | 318 } |
312 | 319 |
313 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { | 320 DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() { |
314 DCHECK(!is_shutdown_); | 321 DCHECK(!is_shutdown_); |
315 if (!commit_batch_) { | 322 if (!commit_batch_) { |
316 commit_batch_.reset(new CommitBatch()); | 323 commit_batch_.reset(new CommitBatch()); |
317 | 324 |
318 // Start a timer to commit any changes that accrue in the batch, but only if | 325 // Start a timer to commit any changes that accrue in the batch, but only if |
319 // no commits are currently in flight. In that case the timer will be | 326 // no commits are currently in flight. In that case the timer will be |
320 // started after the commits have happened. | 327 // started after the commits have happened. |
321 if (!commit_batches_in_flight_) { | 328 if (!commit_batches_in_flight_) { |
322 task_runner_->PostDelayedTask( | 329 task_runner_->PostDelayedTask( |
323 FROM_HERE, | 330 FROM_HERE, |
324 base::Bind(&DomStorageArea::OnCommitTimer, this), | 331 base::Bind(&DOMStorageArea::OnCommitTimer, this), |
325 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 332 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
326 } | 333 } |
327 } | 334 } |
328 return commit_batch_.get(); | 335 return commit_batch_.get(); |
329 } | 336 } |
330 | 337 |
331 void DomStorageArea::OnCommitTimer() { | 338 void DOMStorageArea::OnCommitTimer() { |
332 if (is_shutdown_) | 339 if (is_shutdown_) |
333 return; | 340 return; |
334 | 341 |
335 DCHECK(backing_.get()); | 342 DCHECK(backing_.get()); |
336 | 343 |
337 // It's possible that there is nothing to commit, since a shallow copy occured | 344 // It's possible that there is nothing to commit, since a shallow copy occured |
338 // before the timer fired. | 345 // before the timer fired. |
339 if (!commit_batch_) | 346 if (!commit_batch_) |
340 return; | 347 return; |
341 | 348 |
342 // This method executes on the primary sequence, we schedule | 349 // This method executes on the primary sequence, we schedule |
343 // a task for immediate execution on the commit sequence. | 350 // a task for immediate execution on the commit sequence. |
344 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 351 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
345 bool success = task_runner_->PostShutdownBlockingTask( | 352 bool success = task_runner_->PostShutdownBlockingTask( |
346 FROM_HERE, | 353 FROM_HERE, |
347 DomStorageTaskRunner::COMMIT_SEQUENCE, | 354 DOMStorageTaskRunner::COMMIT_SEQUENCE, |
348 base::Bind(&DomStorageArea::CommitChanges, this, | 355 base::Bind(&DOMStorageArea::CommitChanges, this, |
349 base::Owned(commit_batch_.release()))); | 356 base::Owned(commit_batch_.release()))); |
350 ++commit_batches_in_flight_; | 357 ++commit_batches_in_flight_; |
351 DCHECK(success); | 358 DCHECK(success); |
352 } | 359 } |
353 | 360 |
354 void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) { | 361 void DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) { |
355 // This method executes on the commit sequence. | 362 // This method executes on the commit sequence. |
356 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 363 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
357 bool success = backing_->CommitChanges(commit_batch->clear_all_first, | 364 bool success = backing_->CommitChanges(commit_batch->clear_all_first, |
358 commit_batch->changed_values); | 365 commit_batch->changed_values); |
359 DCHECK(success); // TODO(michaeln): what if it fails? | 366 DCHECK(success); // TODO(michaeln): what if it fails? |
360 task_runner_->PostTask( | 367 task_runner_->PostTask( |
361 FROM_HERE, | 368 FROM_HERE, |
362 base::Bind(&DomStorageArea::OnCommitComplete, this)); | 369 base::Bind(&DOMStorageArea::OnCommitComplete, this)); |
363 } | 370 } |
364 | 371 |
365 void DomStorageArea::OnCommitComplete() { | 372 void DOMStorageArea::OnCommitComplete() { |
366 // We're back on the primary sequence in this method. | 373 // We're back on the primary sequence in this method. |
367 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 374 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
368 --commit_batches_in_flight_; | 375 --commit_batches_in_flight_; |
369 if (is_shutdown_) | 376 if (is_shutdown_) |
370 return; | 377 return; |
371 if (commit_batch_.get() && !commit_batches_in_flight_) { | 378 if (commit_batch_.get() && !commit_batches_in_flight_) { |
372 // More changes have accrued, restart the timer. | 379 // More changes have accrued, restart the timer. |
373 task_runner_->PostDelayedTask( | 380 task_runner_->PostDelayedTask( |
374 FROM_HERE, | 381 FROM_HERE, |
375 base::Bind(&DomStorageArea::OnCommitTimer, this), | 382 base::Bind(&DOMStorageArea::OnCommitTimer, this), |
376 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 383 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
377 } | 384 } |
378 } | 385 } |
379 | 386 |
380 void DomStorageArea::ShutdownInCommitSequence() { | 387 void DOMStorageArea::ShutdownInCommitSequence() { |
381 // This method executes on the commit sequence. | 388 // This method executes on the commit sequence. |
382 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 389 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
383 DCHECK(backing_.get()); | 390 DCHECK(backing_.get()); |
384 if (commit_batch_) { | 391 if (commit_batch_) { |
385 // Commit any changes that accrued prior to the timer firing. | 392 // Commit any changes that accrued prior to the timer firing. |
386 bool success = backing_->CommitChanges( | 393 bool success = backing_->CommitChanges( |
387 commit_batch_->clear_all_first, | 394 commit_batch_->clear_all_first, |
388 commit_batch_->changed_values); | 395 commit_batch_->changed_values); |
389 DCHECK(success); | 396 DCHECK(success); |
390 } | 397 } |
391 commit_batch_.reset(); | 398 commit_batch_.reset(); |
392 backing_.reset(); | 399 backing_.reset(); |
393 session_storage_backing_ = NULL; | 400 session_storage_backing_ = NULL; |
394 } | 401 } |
395 | 402 |
396 } // namespace dom_storage | 403 } // namespace content |
OLD | NEW |