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/dom_storage/dom_storage_area.h" | 5 #include "webkit/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/time.h" | 10 #include "base/time.h" |
11 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" | 11 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" |
12 #include "webkit/database/database_util.h" | 12 #include "webkit/database/database_util.h" |
13 #include "webkit/dom_storage/dom_storage_map.h" | 13 #include "webkit/dom_storage/dom_storage_map.h" |
14 #include "webkit/dom_storage/dom_storage_namespace.h" | 14 #include "webkit/dom_storage/dom_storage_namespace.h" |
15 #include "webkit/dom_storage/dom_storage_task_runner.h" | 15 #include "webkit/dom_storage/dom_storage_task_runner.h" |
16 #include "webkit/dom_storage/dom_storage_types.h" | 16 #include "webkit/dom_storage/dom_storage_types.h" |
17 #include "webkit/dom_storage/local_storage_database_adapter.h" | 17 #include "webkit/dom_storage/local_storage_database_adapter.h" |
18 #include "webkit/dom_storage/session_storage_database.h" | |
19 #include "webkit/dom_storage/session_storage_database_adapter.h" | |
18 #include "webkit/fileapi/file_system_util.h" | 20 #include "webkit/fileapi/file_system_util.h" |
19 #include "webkit/glue/webkit_glue.h" | 21 #include "webkit/glue/webkit_glue.h" |
20 | 22 |
21 using webkit_database::DatabaseUtil; | 23 using webkit_database::DatabaseUtil; |
22 | 24 |
23 namespace dom_storage { | 25 namespace dom_storage { |
24 | 26 |
25 static const int kCommitTimerSeconds = 1; | 27 static const int kCommitTimerSeconds = 1; |
26 | 28 |
27 DomStorageArea::CommitBatch::CommitBatch() | 29 DomStorageArea::CommitBatch::CommitBatch() |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
65 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); | 67 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); |
66 backing_.reset(new LocalStorageDatabaseAdapter(path)); | 68 backing_.reset(new LocalStorageDatabaseAdapter(path)); |
67 is_initial_import_done_ = false; | 69 is_initial_import_done_ = false; |
68 } | 70 } |
69 } | 71 } |
70 | 72 |
71 DomStorageArea::DomStorageArea( | 73 DomStorageArea::DomStorageArea( |
72 int64 namespace_id, | 74 int64 namespace_id, |
73 const std::string& persistent_namespace_id, | 75 const std::string& persistent_namespace_id, |
74 const GURL& origin, | 76 const GURL& origin, |
77 SessionStorageDatabase* session_storage_backing, | |
75 DomStorageTaskRunner* task_runner) | 78 DomStorageTaskRunner* task_runner) |
76 : namespace_id_(namespace_id), | 79 : namespace_id_(namespace_id), |
77 persistent_namespace_id_(persistent_namespace_id), | 80 persistent_namespace_id_(persistent_namespace_id), |
78 origin_(origin), | 81 origin_(origin), |
79 task_runner_(task_runner), | 82 task_runner_(task_runner), |
80 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)), | 83 map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)), |
84 session_storage_backing_(session_storage_backing), | |
81 is_initial_import_done_(true), | 85 is_initial_import_done_(true), |
82 is_shutdown_(false), | 86 is_shutdown_(false), |
83 commit_batches_in_flight_(0) { | 87 commit_batches_in_flight_(0) { |
84 DCHECK(namespace_id != kLocalStorageNamespaceId); | 88 DCHECK(namespace_id != kLocalStorageNamespaceId); |
89 if (session_storage_backing) { | |
90 backing_.reset(new SessionStorageDatabaseAdapter( | |
91 session_storage_backing, persistent_namespace_id, origin)); | |
92 is_initial_import_done_ = false; | |
93 } | |
85 } | 94 } |
86 | 95 |
87 DomStorageArea::~DomStorageArea() { | 96 DomStorageArea::~DomStorageArea() { |
88 } | 97 } |
89 | 98 |
90 void DomStorageArea::ExtractValues(ValuesMap* map) { | 99 void DomStorageArea::ExtractValues(ValuesMap* map) { |
91 if (is_shutdown_) | 100 if (is_shutdown_) |
92 return; | 101 return; |
93 InitialImportIfNeeded(); | 102 InitialImportIfNeeded(); |
94 map_->ExtractValues(map); | 103 map_->ExtractValues(map); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
161 } | 170 } |
162 | 171 |
163 return true; | 172 return true; |
164 } | 173 } |
165 | 174 |
166 DomStorageArea* DomStorageArea::ShallowCopy( | 175 DomStorageArea* DomStorageArea::ShallowCopy( |
167 int64 destination_namespace_id, | 176 int64 destination_namespace_id, |
168 const std::string& destination_persistent_namespace_id) { | 177 const std::string& destination_persistent_namespace_id) { |
169 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_); | 178 DCHECK_NE(kLocalStorageNamespaceId, namespace_id_); |
170 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); | 179 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); |
171 DCHECK(!backing_.get()); // SessionNamespaces aren't stored on disk. | |
172 | 180 |
173 DomStorageArea* copy = new DomStorageArea( | 181 DomStorageArea* copy = new DomStorageArea( |
174 destination_namespace_id, destination_persistent_namespace_id, origin_, | 182 destination_namespace_id, destination_persistent_namespace_id, origin_, |
175 task_runner_); | 183 session_storage_backing_, task_runner_); |
176 copy->map_ = map_; | 184 copy->map_ = map_; |
177 copy->is_shutdown_ = is_shutdown_; | 185 copy->is_shutdown_ = is_shutdown_; |
michaeln
2012/06/26 06:15:12
since map_ is populated, should we set is_initial_
marja
2012/06/26 14:18:05
Done.
| |
186 | |
187 // All the uncommitted changes to this area need to happen before the actual | |
188 // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer | |
189 // call might be in the event queue at this point, but it's handled gracefully | |
190 // when it fires. | |
191 if (commit_batch_.get()) | |
192 OnCommitTimer(); | |
178 return copy; | 193 return copy; |
179 } | 194 } |
180 | 195 |
181 bool DomStorageArea::HasUncommittedChanges() const { | 196 bool DomStorageArea::HasUncommittedChanges() const { |
182 DCHECK(!is_shutdown_); | 197 DCHECK(!is_shutdown_); |
183 return commit_batch_.get() || commit_batches_in_flight_; | 198 return commit_batch_.get() || commit_batches_in_flight_; |
184 } | 199 } |
185 | 200 |
186 void DomStorageArea::DeleteOrigin() { | 201 void DomStorageArea::DeleteOrigin() { |
187 DCHECK(!is_shutdown_); | 202 DCHECK(!is_shutdown_); |
188 if (HasUncommittedChanges()) { | 203 if (HasUncommittedChanges()) { |
189 // TODO(michaeln): This logically deletes the data immediately, | 204 // TODO(michaeln): This logically deletes the data immediately, |
190 // and in a matter of a second, deletes the rows from the backing | 205 // and in a matter of a second, deletes the rows from the backing |
191 // database file, but the file itself will linger until shutdown | 206 // database file, but the file itself will linger until shutdown |
192 // or purge time. Ideally, this should delete the file more | 207 // or purge time. Ideally, this should delete the file more |
193 // quickly. | 208 // quickly. |
194 Clear(); | 209 Clear(); |
195 return; | 210 return; |
196 } | 211 } |
197 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); | 212 map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance); |
198 if (backing_.get()) { | 213 if (backing_.get() && !session_storage_backing_.get()) { |
214 // This is localStorage. | |
199 is_initial_import_done_ = false; | 215 is_initial_import_done_ = false; |
200 backing_->Reset(); | 216 backing_->Reset(); |
201 backing_->DeleteFiles(); | 217 backing_->DeleteFiles(); |
218 } else if (session_storage_backing_.get()) { | |
219 // No need to read the data (there will be no data), also, the | |
220 // PRIMARY_SEQUENCE thread shouldn't try to read the data while | |
221 // SessionStorageDatabase::DeleteArea is in progress. | |
222 is_initial_import_done_ = true; | |
223 task_runner_->PostShutdownBlockingTask( | |
224 FROM_HERE, | |
225 DomStorageTaskRunner::COMMIT_SEQUENCE, | |
226 base::Bind(base::IgnoreResult(&SessionStorageDatabase::DeleteArea), | |
227 session_storage_backing_.get(), | |
228 persistent_namespace_id_, origin_)); | |
202 } | 229 } |
203 } | 230 } |
204 | 231 |
205 void DomStorageArea::PurgeMemory() { | 232 void DomStorageArea::PurgeMemory() { |
206 DCHECK(!is_shutdown_); | 233 DCHECK(!is_shutdown_); |
207 if (!is_initial_import_done_ || // We're not using any memory. | 234 if (!is_initial_import_done_ || // We're not using any memory. |
208 !backing_.get() || // We can't purge anything. | 235 !backing_.get() || // We can't purge anything. |
209 HasUncommittedChanges()) // We leave things alone with changes pending. | 236 HasUncommittedChanges()) // We leave things alone with changes pending. |
210 return; | 237 return; |
211 | 238 |
(...skipping 17 matching lines...) Expand all Loading... | |
229 FROM_HERE, | 256 FROM_HERE, |
230 DomStorageTaskRunner::COMMIT_SEQUENCE, | 257 DomStorageTaskRunner::COMMIT_SEQUENCE, |
231 base::Bind(&DomStorageArea::ShutdownInCommitSequence, this)); | 258 base::Bind(&DomStorageArea::ShutdownInCommitSequence, this)); |
232 DCHECK(success); | 259 DCHECK(success); |
233 } | 260 } |
234 | 261 |
235 void DomStorageArea::InitialImportIfNeeded() { | 262 void DomStorageArea::InitialImportIfNeeded() { |
236 if (is_initial_import_done_) | 263 if (is_initial_import_done_) |
237 return; | 264 return; |
238 | 265 |
239 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_); | |
240 DCHECK(backing_.get()); | 266 DCHECK(backing_.get()); |
241 | 267 |
242 ValuesMap initial_values; | 268 ValuesMap initial_values; |
243 backing_->ReadAllValues(&initial_values); | 269 backing_->ReadAllValues(&initial_values); |
244 map_->SwapValues(&initial_values); | 270 map_->SwapValues(&initial_values); |
245 is_initial_import_done_ = true; | 271 is_initial_import_done_ = true; |
246 } | 272 } |
247 | 273 |
248 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { | 274 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { |
249 DCHECK(!is_shutdown_); | 275 DCHECK(!is_shutdown_); |
250 if (!commit_batch_.get()) { | 276 if (!commit_batch_.get()) { |
251 commit_batch_.reset(new CommitBatch()); | 277 commit_batch_.reset(new CommitBatch()); |
252 | 278 |
253 // Start a timer to commit any changes that accrue in the batch, but only if | 279 // Start a timer to commit any changes that accrue in the batch, but only if |
254 // no commits are currently in flight. In that case the timer will be | 280 // no commits are currently in flight. In that case the timer will be |
255 // started after the commits have happened. | 281 // started after the commits have happened. |
256 if (!commit_batches_in_flight_) { | 282 if (!commit_batches_in_flight_) { |
257 task_runner_->PostDelayedTask( | 283 task_runner_->PostDelayedTask( |
258 FROM_HERE, | 284 FROM_HERE, |
259 base::Bind(&DomStorageArea::OnCommitTimer, this), | 285 base::Bind(&DomStorageArea::OnCommitTimer, this), |
260 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 286 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
261 } | 287 } |
262 } | 288 } |
263 return commit_batch_.get(); | 289 return commit_batch_.get(); |
264 } | 290 } |
265 | 291 |
266 void DomStorageArea::OnCommitTimer() { | 292 void DomStorageArea::OnCommitTimer() { |
267 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_); | |
268 if (is_shutdown_) | 293 if (is_shutdown_) |
269 return; | 294 return; |
270 | 295 |
271 DCHECK(backing_.get()); | 296 DCHECK(backing_.get()); |
272 DCHECK(commit_batch_.get()); | 297 |
273 DCHECK(!commit_batches_in_flight_); | 298 // It's possible that there is nothing to commit, since a shallow copy occured |
299 // before the timer fired. | |
300 if (!commit_batch_.get()) | |
301 return; | |
274 | 302 |
275 // This method executes on the primary sequence, we schedule | 303 // This method executes on the primary sequence, we schedule |
276 // a task for immediate execution on the commit sequence. | 304 // a task for immediate execution on the commit sequence. |
277 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 305 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
278 bool success = task_runner_->PostShutdownBlockingTask( | 306 bool success = task_runner_->PostShutdownBlockingTask( |
279 FROM_HERE, | 307 FROM_HERE, |
280 DomStorageTaskRunner::COMMIT_SEQUENCE, | 308 DomStorageTaskRunner::COMMIT_SEQUENCE, |
281 base::Bind(&DomStorageArea::CommitChanges, this, | 309 base::Bind(&DomStorageArea::CommitChanges, this, |
282 base::Owned(commit_batch_.release()))); | 310 base::Owned(commit_batch_.release()))); |
283 ++commit_batches_in_flight_; | 311 ++commit_batches_in_flight_; |
284 DCHECK(success); | 312 DCHECK(success); |
285 } | 313 } |
286 | 314 |
287 void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) { | 315 void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) { |
288 // This method executes on the commit sequence. | 316 // This method executes on the commit sequence. |
289 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 317 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
290 bool success = backing_->CommitChanges(commit_batch->clear_all_first, | 318 bool success = backing_->CommitChanges(commit_batch->clear_all_first, |
291 commit_batch->changed_values); | 319 commit_batch->changed_values); |
292 DCHECK(success); // TODO(michaeln): what if it fails? | 320 DCHECK(success); // TODO(michaeln): what if it fails? |
293 task_runner_->PostTask( | 321 task_runner_->PostTask( |
294 FROM_HERE, | 322 FROM_HERE, |
295 base::Bind(&DomStorageArea::OnCommitComplete, this)); | 323 base::Bind(&DomStorageArea::OnCommitComplete, this)); |
296 } | 324 } |
297 | 325 |
298 void DomStorageArea::OnCommitComplete() { | 326 void DomStorageArea::OnCommitComplete() { |
299 // We're back on the primary sequence in this method. | 327 // We're back on the primary sequence in this method. |
300 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 328 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
329 --commit_batches_in_flight_; | |
301 if (is_shutdown_) | 330 if (is_shutdown_) |
302 return; | 331 return; |
303 --commit_batches_in_flight_; | |
304 if (commit_batch_.get() && !commit_batches_in_flight_) { | 332 if (commit_batch_.get() && !commit_batches_in_flight_) { |
305 // More changes have accrued, restart the timer. | 333 // More changes have accrued, restart the timer. |
306 task_runner_->PostDelayedTask( | 334 task_runner_->PostDelayedTask( |
307 FROM_HERE, | 335 FROM_HERE, |
308 base::Bind(&DomStorageArea::OnCommitTimer, this), | 336 base::Bind(&DomStorageArea::OnCommitTimer, this), |
309 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 337 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
310 } | 338 } |
311 } | 339 } |
312 | 340 |
313 void DomStorageArea::ShutdownInCommitSequence() { | 341 void DomStorageArea::ShutdownInCommitSequence() { |
314 // This method executes on the commit sequence. | 342 // This method executes on the commit sequence. |
315 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 343 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
316 DCHECK(backing_.get()); | 344 DCHECK(backing_.get()); |
317 if (commit_batch_.get()) { | 345 if (commit_batch_.get()) { |
318 // Commit any changes that accrued prior to the timer firing. | 346 // Commit any changes that accrued prior to the timer firing. |
319 bool success = backing_->CommitChanges( | 347 bool success = backing_->CommitChanges( |
320 commit_batch_->clear_all_first, | 348 commit_batch_->clear_all_first, |
321 commit_batch_->changed_values); | 349 commit_batch_->changed_values); |
322 DCHECK(success); | 350 DCHECK(success); |
323 } | 351 } |
324 commit_batch_.reset(); | 352 commit_batch_.reset(); |
325 backing_.reset(); | 353 backing_.reset(); |
354 session_storage_backing_ = NULL; | |
326 } | 355 } |
327 | 356 |
328 } // namespace dom_storage | 357 } // namespace dom_storage |
OLD | NEW |