Chromium Code Reviews| 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/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 } | 53 } |
| 54 | 54 |
| 55 DomStorageArea::DomStorageArea( | 55 DomStorageArea::DomStorageArea( |
| 56 int64 namespace_id, const GURL& origin, | 56 int64 namespace_id, const GURL& origin, |
| 57 const FilePath& directory, DomStorageTaskRunner* task_runner) | 57 const FilePath& directory, DomStorageTaskRunner* task_runner) |
| 58 : namespace_id_(namespace_id), origin_(origin), | 58 : namespace_id_(namespace_id), origin_(origin), |
| 59 directory_(directory), | 59 directory_(directory), |
| 60 task_runner_(task_runner), | 60 task_runner_(task_runner), |
| 61 map_(new DomStorageMap(kPerAreaQuota)), | 61 map_(new DomStorageMap(kPerAreaQuota)), |
| 62 is_initial_import_done_(true), | 62 is_initial_import_done_(true), |
| 63 is_shutdown_(false) { | 63 is_shutdown_(false), |
| 64 commit_batches_in_flight_(0) { | |
| 64 if (namespace_id == kLocalStorageNamespaceId && !directory.empty()) { | 65 if (namespace_id == kLocalStorageNamespaceId && !directory.empty()) { |
| 65 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); | 66 FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); |
| 66 backing_.reset(new DomStorageDatabase(path)); | 67 backing_.reset(new DomStorageDatabase(path)); |
| 67 is_initial_import_done_ = false; | 68 is_initial_import_done_ = false; |
| 68 } | 69 } |
| 69 } | 70 } |
| 70 | 71 |
| 71 DomStorageArea::~DomStorageArea() { | 72 DomStorageArea::~DomStorageArea() { |
| 72 } | 73 } |
| 73 | 74 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 | 155 |
| 155 DomStorageArea* copy = new DomStorageArea(destination_namespace_id, origin_, | 156 DomStorageArea* copy = new DomStorageArea(destination_namespace_id, origin_, |
| 156 FilePath(), task_runner_); | 157 FilePath(), task_runner_); |
| 157 copy->map_ = map_; | 158 copy->map_ = map_; |
| 158 copy->is_shutdown_ = is_shutdown_; | 159 copy->is_shutdown_ = is_shutdown_; |
| 159 return copy; | 160 return copy; |
| 160 } | 161 } |
| 161 | 162 |
| 162 bool DomStorageArea::HasUncommittedChanges() const { | 163 bool DomStorageArea::HasUncommittedChanges() const { |
| 163 DCHECK(!is_shutdown_); | 164 DCHECK(!is_shutdown_); |
| 164 return commit_batch_.get() || in_flight_commit_batch_.get(); | 165 return commit_batch_.get() || commit_batches_in_flight_; |
| 165 } | 166 } |
| 166 | 167 |
| 167 void DomStorageArea::DeleteOrigin() { | 168 void DomStorageArea::DeleteOrigin() { |
| 168 DCHECK(!is_shutdown_); | 169 DCHECK(!is_shutdown_); |
| 169 if (HasUncommittedChanges()) { | 170 if (HasUncommittedChanges()) { |
| 170 // TODO(michaeln): This logically deletes the data immediately, | 171 // TODO(michaeln): This logically deletes the data immediately, |
| 171 // and in a matter of a second, deletes the rows from the backing | 172 // and in a matter of a second, deletes the rows from the backing |
| 172 // database file, but the file itself will linger until shutdown | 173 // database file, but the file itself will linger until shutdown |
| 173 // or purge time. Ideally, this should delete the file more | 174 // or purge time. Ideally, this should delete the file more |
| 174 // quickly. | 175 // quickly. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 226 backing_->ReadAllValues(&initial_values); | 227 backing_->ReadAllValues(&initial_values); |
| 227 map_->SwapValues(&initial_values); | 228 map_->SwapValues(&initial_values); |
| 228 is_initial_import_done_ = true; | 229 is_initial_import_done_ = true; |
| 229 } | 230 } |
| 230 | 231 |
| 231 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { | 232 DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() { |
| 232 DCHECK(!is_shutdown_); | 233 DCHECK(!is_shutdown_); |
| 233 if (!commit_batch_.get()) { | 234 if (!commit_batch_.get()) { |
| 234 commit_batch_.reset(new CommitBatch()); | 235 commit_batch_.reset(new CommitBatch()); |
| 235 | 236 |
| 236 // Start a timer to commit any changes that accrue in the batch, | 237 // Start a timer to commit any changes that accrue in the batch, but only if |
| 237 // but only if a commit is not currently in flight. In that case | 238 // no commits are currently in flight. In that case the timer will be |
| 238 // the timer will be started after the current commit has happened. | 239 // started after the commits have happened. |
| 239 if (!in_flight_commit_batch_.get()) { | 240 if (!commit_batches_in_flight_) { |
| 240 task_runner_->PostDelayedTask( | 241 task_runner_->PostDelayedTask( |
| 241 FROM_HERE, | 242 FROM_HERE, |
| 242 base::Bind(&DomStorageArea::OnCommitTimer, this), | 243 base::Bind(&DomStorageArea::OnCommitTimer, this), |
| 243 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 244 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
| 244 } | 245 } |
| 245 } | 246 } |
| 246 return commit_batch_.get(); | 247 return commit_batch_.get(); |
| 247 } | 248 } |
| 248 | 249 |
| 249 void DomStorageArea::OnCommitTimer() { | 250 void DomStorageArea::OnCommitTimer() { |
| 250 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_); | 251 DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_); |
| 251 if (is_shutdown_) | 252 if (is_shutdown_) |
| 252 return; | 253 return; |
| 253 | 254 |
| 254 DCHECK(backing_.get()); | 255 DCHECK(backing_.get()); |
| 255 DCHECK(commit_batch_.get()); | 256 DCHECK(commit_batch_.get()); |
| 256 DCHECK(!in_flight_commit_batch_.get()); | 257 DCHECK(!commit_batches_in_flight_); |
| 257 | 258 |
| 258 // This method executes on the primary sequence, we schedule | 259 // This method executes on the primary sequence, we schedule |
| 259 // a task for immediate execution on the commit sequence. | 260 // a task for immediate execution on the commit sequence. |
| 260 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 261 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
| 261 in_flight_commit_batch_ = commit_batch_.Pass(); | 262 CommitBatch* in_flight_commit_batch = commit_batch_.release(); |
| 262 bool success = task_runner_->PostShutdownBlockingTask( | 263 bool success = task_runner_->PostShutdownBlockingTask( |
| 263 FROM_HERE, | 264 FROM_HERE, |
| 264 DomStorageTaskRunner::COMMIT_SEQUENCE, | 265 DomStorageTaskRunner::COMMIT_SEQUENCE, |
| 265 base::Bind(&DomStorageArea::CommitChanges, this)); | 266 base::Bind(&DomStorageArea::CommitChanges, this, |
| 267 *in_flight_commit_batch)); | |
|
michaeln
2012/05/10 16:19:22
Please use base::Owned<> here to pass ownership of
marja
2012/05/11 07:50:05
Done.
| |
| 268 ++commit_batches_in_flight_; | |
| 266 DCHECK(success); | 269 DCHECK(success); |
| 267 } | 270 } |
| 268 | 271 |
| 269 void DomStorageArea::CommitChanges() { | 272 void DomStorageArea::CommitChanges(const CommitBatch& commit_batch) { |
|
michaeln
2012/05/10 16:19:22
When using base::Owned<>, this method would take a
marja
2012/05/11 07:50:05
Done.
| |
| 270 // This method executes on the commit sequence. | 273 // This method executes on the commit sequence. |
| 271 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 274 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
| 272 DCHECK(in_flight_commit_batch_.get()); | 275 bool success = backing_->CommitChanges(commit_batch.clear_all_first, |
| 273 bool success = backing_->CommitChanges( | 276 commit_batch.changed_values); |
| 274 in_flight_commit_batch_->clear_all_first, | |
| 275 in_flight_commit_batch_->changed_values); | |
| 276 DCHECK(success); // TODO(michaeln): what if it fails? | 277 DCHECK(success); // TODO(michaeln): what if it fails? |
| 277 task_runner_->PostTask( | 278 task_runner_->PostTask( |
| 278 FROM_HERE, | 279 FROM_HERE, |
| 279 base::Bind(&DomStorageArea::OnCommitComplete, this)); | 280 base::Bind(&DomStorageArea::OnCommitComplete, this)); |
| 280 } | 281 } |
| 281 | 282 |
| 282 void DomStorageArea::OnCommitComplete() { | 283 void DomStorageArea::OnCommitComplete() { |
| 283 // We're back on the primary sequence in this method. | 284 // We're back on the primary sequence in this method. |
| 284 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 285 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
| 285 if (is_shutdown_) | 286 if (is_shutdown_) |
| 286 return; | 287 return; |
| 287 in_flight_commit_batch_.reset(); | 288 --commit_batches_in_flight_; |
| 288 if (commit_batch_.get()) { | 289 if (commit_batch_.get() && !commit_batches_in_flight_) { |
| 289 // More changes have accrued, restart the timer. | 290 // More changes have accrued, restart the timer. |
| 290 task_runner_->PostDelayedTask( | 291 task_runner_->PostDelayedTask( |
| 291 FROM_HERE, | 292 FROM_HERE, |
| 292 base::Bind(&DomStorageArea::OnCommitTimer, this), | 293 base::Bind(&DomStorageArea::OnCommitTimer, this), |
| 293 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | 294 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); |
| 294 } | 295 } |
| 295 } | 296 } |
| 296 | 297 |
| 297 void DomStorageArea::ShutdownInCommitSequence() { | 298 void DomStorageArea::ShutdownInCommitSequence() { |
| 298 // This method executes on the commit sequence. | 299 // This method executes on the commit sequence. |
| 299 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 300 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
| 300 DCHECK(backing_.get()); | 301 DCHECK(backing_.get()); |
| 301 if (commit_batch_.get()) { | 302 if (commit_batch_.get()) { |
| 302 // Commit any changes that accrued prior to the timer firing. | 303 // Commit any changes that accrued prior to the timer firing. |
| 303 bool success = backing_->CommitChanges( | 304 bool success = backing_->CommitChanges( |
| 304 commit_batch_->clear_all_first, | 305 commit_batch_->clear_all_first, |
| 305 commit_batch_->changed_values); | 306 commit_batch_->changed_values); |
| 306 DCHECK(success); | 307 DCHECK(success); |
| 307 } | 308 } |
| 308 commit_batch_.reset(); | 309 commit_batch_.reset(); |
| 309 in_flight_commit_batch_.reset(); | |
| 310 backing_.reset(); | 310 backing_.reset(); |
| 311 } | 311 } |
| 312 | 312 |
| 313 } // namespace dom_storage | 313 } // namespace dom_storage |
| OLD | NEW |