Chromium Code Reviews| OLD | NEW |
|---|---|
| 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_area.h" | 5 #include "content/browser/dom_storage/dom_storage_area.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" |
| 10 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/sys_info.h" | |
| 12 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 13 #include "content/browser/dom_storage/dom_storage_namespace.h" | 16 #include "content/browser/dom_storage/dom_storage_namespace.h" |
| 14 #include "content/browser/dom_storage/dom_storage_task_runner.h" | 17 #include "content/browser/dom_storage/dom_storage_task_runner.h" |
| 15 #include "content/browser/dom_storage/local_storage_database_adapter.h" | 18 #include "content/browser/dom_storage/local_storage_database_adapter.h" |
| 16 #include "content/browser/dom_storage/session_storage_database.h" | 19 #include "content/browser/dom_storage/session_storage_database.h" |
| 17 #include "content/browser/dom_storage/session_storage_database_adapter.h" | 20 #include "content/browser/dom_storage/session_storage_database_adapter.h" |
| 18 #include "content/common/dom_storage/dom_storage_map.h" | 21 #include "content/common/dom_storage/dom_storage_map.h" |
| 19 #include "content/common/dom_storage/dom_storage_types.h" | 22 #include "content/common/dom_storage/dom_storage_types.h" |
| 20 #include "storage/browser/database/database_util.h" | 23 #include "storage/browser/database/database_util.h" |
| 21 #include "storage/common/database/database_identifier.h" | 24 #include "storage/common/database/database_identifier.h" |
| 22 #include "storage/common/fileapi/file_system_util.h" | 25 #include "storage/common/fileapi/file_system_util.h" |
| 23 | 26 |
| 24 using storage::DatabaseUtil; | 27 using storage::DatabaseUtil; |
| 25 | 28 |
| 26 namespace content { | 29 namespace content { |
| 27 | 30 |
| 28 static const int kCommitTimerSeconds = 1; | 31 // Delay for a moment after a value is set in anticipation |
| 32 // of other values being set, so changes are batched. | |
| 33 static const int kCommitDefaultDelaySecs = 5; | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
Nit: Move these constants to the anonymous namespa
michaeln
2015/02/19 01:19:20
Done.
| |
| 29 | 34 |
| 30 DOMStorageArea::CommitBatch::CommitBatch() | 35 // The delay used if a commit is scheduled during startup, also the |
| 31 : clear_all_first(false) { | 36 // process uptime duration used as a proxy for 'during startup'. |
| 37 static const int kCommitDuringStartupDelaySecs = 60; | |
| 38 | |
| 39 // To avoid excessive IO we apply limits to the amount of data being written | |
| 40 // and the frequency of writes. The specific values used are somewhat arbitrary. | |
| 41 static const int kMaxBytesPerDay = kPerStorageAreaQuota * 2; | |
| 42 static const int kMaxCommitsPerHour = 6; | |
| 43 | |
| 44 namespace { | |
| 45 | |
| 46 // TODO(michaeln): Put this somewhere appropiate for reuse. | |
| 47 bool IsBrowserStartingUp() { | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
Nit: It seems like this function should instead be
michaeln
2015/02/17 19:36:51
Oh! Thank you for this comment. I mistakenly thoug
michaeln
2015/02/19 01:20:03
Done.
| |
| 48 return base::SysInfo::Uptime() < kCommitDuringStartupDelaySecs * 1000; | |
| 49 } | |
| 50 | |
| 51 } | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
Nit: add " // namespace"
michaeln
2015/02/19 01:19:20
Done.
| |
| 52 | |
| 53 DOMStorageArea::RateLimiter::RateLimiter(size_t desired_rate, | |
| 54 base::TimeDelta time_quantum) | |
| 55 : rate_(desired_rate), samples_(0), time_quantum_(time_quantum) { | |
| 56 DCHECK_GT(desired_rate, 0ul); | |
| 57 } | |
| 58 | |
| 59 void DOMStorageArea::RateLimiter::add_samples(size_t samples) { | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
Nit: Either inline this into the header or name it
michaeln
2015/02/19 01:19:20
Done.
| |
| 60 samples_ += samples; | |
| 61 } | |
| 62 | |
| 63 // Computes the total time needed to process the total samples seen | |
| 64 // at the desired rate. | |
| 65 base::TimeDelta DOMStorageArea::RateLimiter::ComputeTimeNeeded() const { | |
| 66 return base::TimeDelta::FromInternalValue((samples_ / rate_) * | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
The comment from time.h says this about ToInternal
michaeln
2015/02/17 19:36:51
Nice idea. There isn't an operator that takes floa
| |
| 67 time_quantum_.ToInternalValue()); | |
| 68 } | |
| 69 | |
| 70 // Given the elapsed time since the start of the rate limiting session, | |
| 71 // computes the delay needed to mimic having processed the total samples | |
| 72 // seen at the desired rate. | |
|
Alexei Svitkine (slow)
2015/02/17 01:05:20
Nit: Comments should be in the header file. Same a
michaeln
2015/02/19 01:19:20
Done.
| |
| 73 base::TimeDelta DOMStorageArea::RateLimiter::ComputeDelayNeeded( | |
| 74 const base::TimeDelta elapsed_time) const { | |
| 75 base::TimeDelta time_needed = ComputeTimeNeeded(); | |
| 76 if (time_needed > elapsed_time) | |
| 77 return time_needed - elapsed_time; | |
| 78 return base::TimeDelta(); | |
| 79 } | |
| 80 | |
| 81 DOMStorageArea::CommitBatch::CommitBatch() : clear_all_first(false) { | |
| 32 } | 82 } |
| 33 DOMStorageArea::CommitBatch::~CommitBatch() {} | 83 DOMStorageArea::CommitBatch::~CommitBatch() {} |
| 34 | 84 |
| 85 size_t DOMStorageArea::CommitBatch::GetDataSize() const { | |
| 86 return DOMStorageMap::CountBytes(changed_values); | |
| 87 } | |
| 35 | 88 |
| 36 // static | 89 // static |
| 37 const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] = | 90 const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] = |
| 38 FILE_PATH_LITERAL(".localstorage"); | 91 FILE_PATH_LITERAL(".localstorage"); |
| 39 | 92 |
| 40 // static | 93 // static |
| 41 base::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) { | 94 base::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) { |
| 42 std::string filename = storage::GetIdentifierFromOrigin(origin); | 95 std::string filename = storage::GetIdentifierFromOrigin(origin); |
| 43 // There is no base::FilePath.AppendExtension() method, so start with just the | 96 // There is no base::FilePath.AppendExtension() method, so start with just the |
| 44 // extension as the filename, and then InsertBeforeExtension the desired | 97 // extension as the filename, and then InsertBeforeExtension the desired |
| 45 // name. | 98 // name. |
| 46 return base::FilePath().Append(kDatabaseFileExtension). | 99 return base::FilePath().Append(kDatabaseFileExtension). |
| 47 InsertBeforeExtensionASCII(filename); | 100 InsertBeforeExtensionASCII(filename); |
| 48 } | 101 } |
| 49 | 102 |
| 50 // static | 103 // static |
| 51 GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) { | 104 GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) { |
| 52 DCHECK(name.MatchesExtension(kDatabaseFileExtension)); | 105 DCHECK(name.MatchesExtension(kDatabaseFileExtension)); |
| 53 std::string origin_id = | 106 std::string origin_id = |
| 54 name.BaseName().RemoveExtension().MaybeAsASCII(); | 107 name.BaseName().RemoveExtension().MaybeAsASCII(); |
| 55 return storage::GetOriginFromIdentifier(origin_id); | 108 return storage::GetOriginFromIdentifier(origin_id); |
| 56 } | 109 } |
| 57 | 110 |
| 58 DOMStorageArea::DOMStorageArea( | 111 DOMStorageArea::DOMStorageArea(const GURL& origin, |
| 59 const GURL& origin, const base::FilePath& directory, | 112 const base::FilePath& directory, |
| 60 DOMStorageTaskRunner* task_runner) | 113 DOMStorageTaskRunner* task_runner) |
| 61 : namespace_id_(kLocalStorageNamespaceId), origin_(origin), | 114 : namespace_id_(kLocalStorageNamespaceId), |
| 115 origin_(origin), | |
| 62 directory_(directory), | 116 directory_(directory), |
| 63 task_runner_(task_runner), | 117 task_runner_(task_runner), |
| 64 map_(new DOMStorageMap(kPerStorageAreaQuota + | 118 map_(new DOMStorageMap(kPerStorageAreaQuota + |
| 65 kPerStorageAreaOverQuotaAllowance)), | 119 kPerStorageAreaOverQuotaAllowance)), |
| 66 is_initial_import_done_(true), | 120 is_initial_import_done_(true), |
| 67 is_shutdown_(false), | 121 is_shutdown_(false), |
| 68 commit_batches_in_flight_(0) { | 122 commit_batches_in_flight_(0), |
| 123 start_time_(base::TimeTicks::Now()), | |
| 124 data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)), | |
| 125 commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) { | |
| 69 if (!directory.empty()) { | 126 if (!directory.empty()) { |
| 70 base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); | 127 base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_)); |
| 71 backing_.reset(new LocalStorageDatabaseAdapter(path)); | 128 backing_.reset(new LocalStorageDatabaseAdapter(path)); |
| 72 is_initial_import_done_ = false; | 129 is_initial_import_done_ = false; |
| 73 } | 130 } |
| 74 } | 131 } |
| 75 | 132 |
| 76 DOMStorageArea::DOMStorageArea( | 133 DOMStorageArea::DOMStorageArea(int64 namespace_id, |
| 77 int64 namespace_id, | 134 const std::string& persistent_namespace_id, |
| 78 const std::string& persistent_namespace_id, | 135 const GURL& origin, |
| 79 const GURL& origin, | 136 SessionStorageDatabase* session_storage_backing, |
| 80 SessionStorageDatabase* session_storage_backing, | 137 DOMStorageTaskRunner* task_runner) |
| 81 DOMStorageTaskRunner* task_runner) | |
| 82 : namespace_id_(namespace_id), | 138 : namespace_id_(namespace_id), |
| 83 persistent_namespace_id_(persistent_namespace_id), | 139 persistent_namespace_id_(persistent_namespace_id), |
| 84 origin_(origin), | 140 origin_(origin), |
| 85 task_runner_(task_runner), | 141 task_runner_(task_runner), |
| 86 map_(new DOMStorageMap(kPerStorageAreaQuota + | 142 map_(new DOMStorageMap(kPerStorageAreaQuota + |
| 87 kPerStorageAreaOverQuotaAllowance)), | 143 kPerStorageAreaOverQuotaAllowance)), |
| 88 session_storage_backing_(session_storage_backing), | 144 session_storage_backing_(session_storage_backing), |
| 89 is_initial_import_done_(true), | 145 is_initial_import_done_(true), |
| 90 is_shutdown_(false), | 146 is_shutdown_(false), |
| 91 commit_batches_in_flight_(0) { | 147 commit_batches_in_flight_(0), |
| 148 start_time_(base::TimeTicks::Now()), | |
| 149 data_rate_limiter_(kMaxBytesPerDay, base::TimeDelta::FromHours(24)), | |
| 150 commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) { | |
| 92 DCHECK(namespace_id != kLocalStorageNamespaceId); | 151 DCHECK(namespace_id != kLocalStorageNamespaceId); |
| 93 if (session_storage_backing) { | 152 if (session_storage_backing) { |
| 94 backing_.reset(new SessionStorageDatabaseAdapter( | 153 backing_.reset(new SessionStorageDatabaseAdapter( |
| 95 session_storage_backing, persistent_namespace_id, origin)); | 154 session_storage_backing, persistent_namespace_id, origin)); |
| 96 is_initial_import_done_ = false; | 155 is_initial_import_done_ = false; |
| 97 } | 156 } |
| 98 } | 157 } |
| 99 | 158 |
| 100 DOMStorageArea::~DOMStorageArea() { | 159 DOMStorageArea::~DOMStorageArea() { |
| 101 } | 160 } |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 130 | 189 |
| 131 bool DOMStorageArea::SetItem(const base::string16& key, | 190 bool DOMStorageArea::SetItem(const base::string16& key, |
| 132 const base::string16& value, | 191 const base::string16& value, |
| 133 base::NullableString16* old_value) { | 192 base::NullableString16* old_value) { |
| 134 if (is_shutdown_) | 193 if (is_shutdown_) |
| 135 return false; | 194 return false; |
| 136 InitialImportIfNeeded(); | 195 InitialImportIfNeeded(); |
| 137 if (!map_->HasOneRef()) | 196 if (!map_->HasOneRef()) |
| 138 map_ = map_->DeepCopy(); | 197 map_ = map_->DeepCopy(); |
| 139 bool success = map_->SetItem(key, value, old_value); | 198 bool success = map_->SetItem(key, value, old_value); |
| 140 if (success && backing_) { | 199 if (success && backing_ && |
| 200 (old_value->is_null() || old_value->string() != value)) { | |
| 141 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); | 201 CommitBatch* commit_batch = CreateCommitBatchIfNeeded(); |
| 142 commit_batch->changed_values[key] = base::NullableString16(value, false); | 202 commit_batch->changed_values[key] = base::NullableString16(value, false); |
| 143 } | 203 } |
| 144 return success; | 204 return success; |
| 145 } | 205 } |
| 146 | 206 |
| 147 bool DOMStorageArea::RemoveItem(const base::string16& key, | 207 bool DOMStorageArea::RemoveItem(const base::string16& key, |
| 148 base::string16* old_value) { | 208 base::string16* old_value) { |
| 149 if (is_shutdown_) | 209 if (is_shutdown_) |
| 150 return false; | 210 return false; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); | 265 DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id); |
| 206 | 266 |
| 207 DOMStorageArea* copy = new DOMStorageArea( | 267 DOMStorageArea* copy = new DOMStorageArea( |
| 208 destination_namespace_id, destination_persistent_namespace_id, origin_, | 268 destination_namespace_id, destination_persistent_namespace_id, origin_, |
| 209 session_storage_backing_.get(), task_runner_.get()); | 269 session_storage_backing_.get(), task_runner_.get()); |
| 210 copy->map_ = map_; | 270 copy->map_ = map_; |
| 211 copy->is_shutdown_ = is_shutdown_; | 271 copy->is_shutdown_ = is_shutdown_; |
| 212 copy->is_initial_import_done_ = true; | 272 copy->is_initial_import_done_ = true; |
| 213 | 273 |
| 214 // All the uncommitted changes to this area need to happen before the actual | 274 // All the uncommitted changes to this area need to happen before the actual |
| 215 // shallow copy is made (scheduled by the upper layer). Another OnCommitTimer | 275 // shallow copy is made (scheduled by the upper layer sometime after return). |
| 216 // call might be in the event queue at this point, but it's handled gracefully | |
| 217 // when it fires. | |
| 218 if (commit_batch_) | 276 if (commit_batch_) |
| 219 OnCommitTimer(); | 277 ScheduleImmediateCommit(); |
| 220 return copy; | 278 return copy; |
| 221 } | 279 } |
| 222 | 280 |
| 223 bool DOMStorageArea::HasUncommittedChanges() const { | 281 bool DOMStorageArea::HasUncommittedChanges() const { |
| 224 DCHECK(!is_shutdown_); | |
| 225 return commit_batch_.get() || commit_batches_in_flight_; | 282 return commit_batch_.get() || commit_batches_in_flight_; |
| 226 } | 283 } |
| 227 | 284 |
| 285 void DOMStorageArea::ScheduleImmediateCommit() { | |
| 286 DCHECK(HasUncommittedChanges()); | |
| 287 PostCommitTask(); | |
| 288 } | |
| 289 | |
| 228 void DOMStorageArea::DeleteOrigin() { | 290 void DOMStorageArea::DeleteOrigin() { |
| 229 DCHECK(!is_shutdown_); | 291 DCHECK(!is_shutdown_); |
| 230 // This function shouldn't be called for sessionStorage. | 292 // This function shouldn't be called for sessionStorage. |
| 231 DCHECK(!session_storage_backing_.get()); | 293 DCHECK(!session_storage_backing_.get()); |
| 232 if (HasUncommittedChanges()) { | 294 if (HasUncommittedChanges()) { |
| 233 // TODO(michaeln): This logically deletes the data immediately, | 295 // TODO(michaeln): This logically deletes the data immediately, |
| 234 // and in a matter of a second, deletes the rows from the backing | 296 // and in a matter of a second, deletes the rows from the backing |
| 235 // database file, but the file itself will linger until shutdown | 297 // database file, but the file itself will linger until shutdown |
| 236 // or purge time. Ideally, this should delete the file more | 298 // or purge time. Ideally, this should delete the file more |
| 237 // quickly. | 299 // quickly. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() { | 382 DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() { |
| 321 DCHECK(!is_shutdown_); | 383 DCHECK(!is_shutdown_); |
| 322 if (!commit_batch_) { | 384 if (!commit_batch_) { |
| 323 commit_batch_.reset(new CommitBatch()); | 385 commit_batch_.reset(new CommitBatch()); |
| 324 | 386 |
| 325 // Start a timer to commit any changes that accrue in the batch, but only if | 387 // Start a timer to commit any changes that accrue in the batch, but only if |
| 326 // no commits are currently in flight. In that case the timer will be | 388 // no commits are currently in flight. In that case the timer will be |
| 327 // started after the commits have happened. | 389 // started after the commits have happened. |
| 328 if (!commit_batches_in_flight_) { | 390 if (!commit_batches_in_flight_) { |
| 329 task_runner_->PostDelayedTask( | 391 task_runner_->PostDelayedTask( |
| 330 FROM_HERE, | 392 FROM_HERE, base::Bind(&DOMStorageArea::OnCommitTimer, this), |
| 331 base::Bind(&DOMStorageArea::OnCommitTimer, this), | 393 ComputeCommitDelay()); |
| 332 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | |
| 333 } | 394 } |
| 334 } | 395 } |
| 335 return commit_batch_.get(); | 396 return commit_batch_.get(); |
| 336 } | 397 } |
| 337 | 398 |
| 399 base::TimeDelta DOMStorageArea::ComputeCommitDelay() const { | |
| 400 base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time_; | |
| 401 base::TimeDelta delay = std::max( | |
| 402 base::TimeDelta::FromSeconds(kCommitDefaultDelaySecs), | |
| 403 std::max(commit_rate_limiter_.ComputeDelayNeeded(elapsed_time), | |
| 404 data_rate_limiter_.ComputeDelayNeeded(elapsed_time))); | |
| 405 UMA_HISTOGRAM_LONG_TIMES("LocalStorage.CommitDelay", delay); | |
| 406 return delay; | |
| 407 } | |
| 408 | |
| 338 void DOMStorageArea::OnCommitTimer() { | 409 void DOMStorageArea::OnCommitTimer() { |
| 339 if (is_shutdown_) | 410 if (is_shutdown_) |
| 340 return; | 411 return; |
| 341 | 412 |
| 413 // It's possible that there is nothing to commit if an immediate | |
| 414 // commit occured after the timer was scheduled but before it fired. | |
| 415 if (!commit_batch_) | |
| 416 return; | |
| 417 | |
| 418 // Don't mind the double counting of the few that are deferred compared | |
| 419 // to the masses that aren't. | |
| 420 bool defer_commit = IsBrowserStartingUp(); | |
| 421 UMA_HISTOGRAM_BOOLEAN("LocalStorage.Commit", !defer_commit); | |
| 422 if (defer_commit) { | |
| 423 task_runner_->PostDelayedTask( | |
| 424 FROM_HERE, base::Bind(&DOMStorageArea::OnCommitTimer, this), | |
| 425 base::TimeDelta::FromSeconds(kCommitDuringStartupDelaySecs)); | |
| 426 return; | |
| 427 } | |
| 428 | |
| 429 PostCommitTask(); | |
| 430 } | |
| 431 | |
| 432 void DOMStorageArea::PostCommitTask() { | |
| 433 if (is_shutdown_ || !commit_batch_) | |
| 434 return; | |
| 435 | |
| 342 DCHECK(backing_.get()); | 436 DCHECK(backing_.get()); |
| 343 | 437 |
| 344 // It's possible that there is nothing to commit, since a shallow copy occured | 438 commit_rate_limiter_.add_samples(1); |
| 345 // before the timer fired. | 439 data_rate_limiter_.add_samples(commit_batch_->GetDataSize()); |
| 346 if (!commit_batch_) | |
| 347 return; | |
| 348 | 440 |
| 349 // This method executes on the primary sequence, we schedule | 441 // This method executes on the primary sequence, we schedule |
| 350 // a task for immediate execution on the commit sequence. | 442 // a task for immediate execution on the commit sequence. |
| 351 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 443 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
| 352 bool success = task_runner_->PostShutdownBlockingTask( | 444 bool success = task_runner_->PostShutdownBlockingTask( |
| 353 FROM_HERE, | 445 FROM_HERE, |
| 354 DOMStorageTaskRunner::COMMIT_SEQUENCE, | 446 DOMStorageTaskRunner::COMMIT_SEQUENCE, |
| 355 base::Bind(&DOMStorageArea::CommitChanges, this, | 447 base::Bind(&DOMStorageArea::CommitChanges, this, |
| 356 base::Owned(commit_batch_.release()))); | 448 base::Owned(commit_batch_.release()))); |
| 357 ++commit_batches_in_flight_; | 449 ++commit_batches_in_flight_; |
| 358 DCHECK(success); | 450 DCHECK(success); |
| 359 } | 451 } |
| 360 | 452 |
| 361 void DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) { | 453 void DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) { |
| 362 // This method executes on the commit sequence. | 454 // This method executes on the commit sequence. |
| 363 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 455 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
| 364 backing_->CommitChanges(commit_batch->clear_all_first, | 456 backing_->CommitChanges(commit_batch->clear_all_first, |
| 365 commit_batch->changed_values); | 457 commit_batch->changed_values); |
| 366 // TODO(michaeln): what if CommitChanges returns false (e.g., we're trying to | 458 // TODO(michaeln): what if CommitChanges returns false (e.g., we're trying to |
| 367 // commit to a DB which is in an inconsistent state?) | 459 // commit to a DB which is in an inconsistent state?) |
| 368 task_runner_->PostTask( | 460 task_runner_->PostTask( |
| 369 FROM_HERE, | 461 FROM_HERE, |
| 370 base::Bind(&DOMStorageArea::OnCommitComplete, this)); | 462 base::Bind(&DOMStorageArea::OnCommitComplete, this)); |
| 371 } | 463 } |
| 372 | 464 |
| 373 void DOMStorageArea::OnCommitComplete() { | 465 void DOMStorageArea::OnCommitComplete() { |
| 374 // We're back on the primary sequence in this method. | 466 // We're back on the primary sequence in this method. |
| 375 DCHECK(task_runner_->IsRunningOnPrimarySequence()); | 467 DCHECK(task_runner_->IsRunningOnPrimarySequence()); |
| 376 --commit_batches_in_flight_; | 468 --commit_batches_in_flight_; |
| 377 if (is_shutdown_) | 469 if (is_shutdown_) |
| 378 return; | 470 return; |
| 379 if (commit_batch_.get() && !commit_batches_in_flight_) { | 471 if (commit_batch_.get() && !commit_batches_in_flight_) { |
| 380 // More changes have accrued, restart the timer. | 472 // More changes have accrued, restart the timer. |
| 381 task_runner_->PostDelayedTask( | 473 task_runner_->PostDelayedTask( |
| 382 FROM_HERE, | 474 FROM_HERE, base::Bind(&DOMStorageArea::OnCommitTimer, this), |
| 383 base::Bind(&DOMStorageArea::OnCommitTimer, this), | 475 ComputeCommitDelay()); |
| 384 base::TimeDelta::FromSeconds(kCommitTimerSeconds)); | |
| 385 } | 476 } |
| 386 } | 477 } |
| 387 | 478 |
| 388 void DOMStorageArea::ShutdownInCommitSequence() { | 479 void DOMStorageArea::ShutdownInCommitSequence() { |
| 389 // This method executes on the commit sequence. | 480 // This method executes on the commit sequence. |
| 390 DCHECK(task_runner_->IsRunningOnCommitSequence()); | 481 DCHECK(task_runner_->IsRunningOnCommitSequence()); |
| 391 DCHECK(backing_.get()); | 482 DCHECK(backing_.get()); |
| 392 if (commit_batch_) { | 483 if (commit_batch_) { |
| 393 // Commit any changes that accrued prior to the timer firing. | 484 // Commit any changes that accrued prior to the timer firing. |
| 394 bool success = backing_->CommitChanges( | 485 bool success = backing_->CommitChanges( |
| 395 commit_batch_->clear_all_first, | 486 commit_batch_->clear_all_first, |
| 396 commit_batch_->changed_values); | 487 commit_batch_->changed_values); |
| 397 DCHECK(success); | 488 DCHECK(success); |
| 398 } | 489 } |
| 399 commit_batch_.reset(); | 490 commit_batch_.reset(); |
| 400 backing_.reset(); | 491 backing_.reset(); |
| 401 session_storage_backing_ = NULL; | 492 session_storage_backing_ = NULL; |
| 402 } | 493 } |
| 403 | 494 |
| 404 } // namespace content | 495 } // namespace content |
| OLD | NEW |