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

Unified Diff: content/browser/dom_storage/dom_storage_area.cc

Issue 896643002: [DOMStorage] Rate limiting writes to disk. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/dom_storage/dom_storage_area.cc
diff --git a/content/browser/dom_storage/dom_storage_area.cc b/content/browser/dom_storage/dom_storage_area.cc
index 90a55a0ed8bddbfc261ee5386c2ba89e698f8da5..ae47f71aefff8594ce42b9b4b9d7c7ce0ef1c41c 100644
--- a/content/browser/dom_storage/dom_storage_area.cc
+++ b/content/browser/dom_storage/dom_storage_area.cc
@@ -4,6 +4,8 @@
#include "content/browser/dom_storage/dom_storage_area.h"
+#include <algorithm>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
@@ -25,13 +27,27 @@ using storage::DatabaseUtil;
namespace content {
-static const int kCommitTimerSeconds = 1;
+// Delay for a moment after a value is set in anticipation
+// of other values being set, so changes are batched.
+static const int kCommitTimerDefaultDelay = 5;
+
+// Avoid committing too frequently regardless of the amount of data
+// being written.
+static const int kMaxCommitsPerHour = 6;
+
+// A data rate limit applies to the size of the key/value pairs being written.
+// A rate of 500k per hour is enough to fully populate an origins area two
+// times over.
+static const int kMaxDataPerHour = 500 * 1024;;
cmumford 2015/02/03 00:45:24 double semicolon
michaeln 2015/02/03 19:59:14 Done. Also made this a function of the constant pe
DOMStorageArea::CommitBatch::CommitBatch()
: clear_all_first(false) {
}
DOMStorageArea::CommitBatch::~CommitBatch() {}
+size_t DOMStorageArea::CommitBatch::GetDataSize() {
+ return DOMStorageMap::CountBytes(changed_values);
+}
// static
const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
@@ -65,7 +81,10 @@ DOMStorageArea::DOMStorageArea(
kPerStorageAreaOverQuotaAllowance)),
is_initial_import_done_(true),
is_shutdown_(false),
- commit_batches_in_flight_(0) {
+ commit_batches_in_flight_(0),
+ start_time_(base::Time::Now()),
+ data_rate_limiter_(kMaxDataPerHour, base::TimeDelta::FromHours(1)),
+ commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
if (!directory.empty()) {
base::FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
backing_.reset(new LocalStorageDatabaseAdapter(path));
@@ -88,7 +107,10 @@ DOMStorageArea::DOMStorageArea(
session_storage_backing_(session_storage_backing),
is_initial_import_done_(true),
is_shutdown_(false),
- commit_batches_in_flight_(0) {
+ commit_batches_in_flight_(0),
+ start_time_(base::Time::Now()),
+ data_rate_limiter_(kMaxDataPerHour, base::TimeDelta::FromHours(1)),
+ commit_rate_limiter_(kMaxCommitsPerHour, base::TimeDelta::FromHours(1)) {
DCHECK(namespace_id != kLocalStorageNamespaceId);
if (session_storage_backing) {
backing_.reset(new SessionStorageDatabaseAdapter(
@@ -137,7 +159,8 @@ bool DOMStorageArea::SetItem(const base::string16& key,
if (!map_->HasOneRef())
map_ = map_->DeepCopy();
bool success = map_->SetItem(key, value, old_value);
- if (success && backing_) {
+ if (success && backing_ &&
+ (old_value->is_null() || old_value->string() != value)) {
CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
commit_batch->changed_values[key] = base::NullableString16(value, false);
}
@@ -329,12 +352,20 @@ DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() {
task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&DOMStorageArea::OnCommitTimer, this),
- base::TimeDelta::FromSeconds(kCommitTimerSeconds));
+ ComputeCommitDelay());
}
}
return commit_batch_.get();
}
+base::TimeDelta DOMStorageArea::ComputeCommitDelay() {
+ base::TimeDelta elapsed_time = base::Time::Now() - start_time_;
+ return std::max(
+ base::TimeDelta::FromSeconds(kCommitTimerDefaultDelay),
+ std::max(commit_rate_limiter_.ComputeDelayNeeded(elapsed_time),
+ data_rate_limiter_.ComputeDelayNeeded(elapsed_time)));
+}
+
void DOMStorageArea::OnCommitTimer() {
if (is_shutdown_)
return;
@@ -346,6 +377,9 @@ void DOMStorageArea::OnCommitTimer() {
if (!commit_batch_)
return;
+ commit_rate_limiter_.AddSamples(1);
+ data_rate_limiter_.AddSamples(commit_batch_->GetDataSize());
+
// This method executes on the primary sequence, we schedule
// a task for immediate execution on the commit sequence.
DCHECK(task_runner_->IsRunningOnPrimarySequence());
@@ -381,7 +415,7 @@ void DOMStorageArea::OnCommitComplete() {
task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&DOMStorageArea::OnCommitTimer, this),
- base::TimeDelta::FromSeconds(kCommitTimerSeconds));
+ ComputeCommitDelay());
}
}

Powered by Google App Engine
This is Rietveld 408576698