summaryrefslogtreecommitdiffstats
path: root/webkit/dom_storage/dom_storage_area.cc
diff options
context:
space:
mode:
authorbenm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-27 16:26:00 +0000
committerbenm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-27 16:26:00 +0000
commit2e99afd1570da29165b52f69c8d2b29069767ac0 (patch)
treed16fbc74e5618a967d0da7f82abd5a45d953f994 /webkit/dom_storage/dom_storage_area.cc
parente395632a2e7caef7c1113306b1cdf6961452e1ae (diff)
downloadchromium_src-2e99afd1570da29165b52f69c8d2b29069767ac0.zip
chromium_src-2e99afd1570da29165b52f69c8d2b29069767ac0.tar.gz
chromium_src-2e99afd1570da29165b52f69c8d2b29069767ac0.tar.bz2
Hook up DomStorageArea with a DomStorageDatabase. Uses DomStorageTaskRunner to asynchronously write to the database.
BUG=106763 Review URL: http://codereview.chromium.org/9389009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123744 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/dom_storage/dom_storage_area.cc')
-rw-r--r--webkit/dom_storage/dom_storage_area.cc124
1 files changed, 113 insertions, 11 deletions
diff --git a/webkit/dom_storage/dom_storage_area.cc b/webkit/dom_storage/dom_storage_area.cc
index e394f64..3eb195c 100644
--- a/webkit/dom_storage/dom_storage_area.cc
+++ b/webkit/dom_storage/dom_storage_area.cc
@@ -3,57 +3,113 @@
// found in the LICENSE file.
#include "webkit/dom_storage/dom_storage_area.h"
+
+#include "base/bind.h"
+#include "base/time.h"
#include "webkit/dom_storage/dom_storage_map.h"
#include "webkit/dom_storage/dom_storage_namespace.h"
+#include "webkit/dom_storage/dom_storage_task_runner.h"
#include "webkit/dom_storage/dom_storage_types.h"
+#include "webkit/fileapi/file_system_util.h"
namespace dom_storage {
DomStorageArea::DomStorageArea(
int64 namespace_id, const GURL& origin,
const FilePath& directory, DomStorageTaskRunner* task_runner)
- : namespace_id_(namespace_id),
- origin_(origin),
+ : namespace_id_(namespace_id), origin_(origin),
directory_(directory),
task_runner_(task_runner),
- map_(new DomStorageMap(kPerAreaQuota)) {
+ map_(new DomStorageMap(kPerAreaQuota)),
+ backing_(NULL),
+ initial_import_done_(false),
+ clear_all_next_commit_(false),
+ commit_in_flight_(false) {
+
+ if (namespace_id == kLocalStorageNamespaceId && !directory.empty()) {
+ FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
+ backing_.reset(new DomStorageDatabase(path));
+ } else {
+ // Not a local storage area or no directory specified for backing
+ // database, (i.e. it's an incognito profile).
+ initial_import_done_ = true;
+ }
}
DomStorageArea::~DomStorageArea() {
+ if (clear_all_next_commit_ || !changed_values_.empty()) {
+ // Still some data left that was not committed to disk, try now.
+ // We do this regardless of whether we think a commit is in flight
+ // as there is no guarantee that that commit will actually get
+ // processed. For example the task_runner_'s message loop could
+ // unexpectedly quit before the delayed task is fired and leave the
+ // commit_in_flight_ flag set. But there's no way for us to determine
+ // that has happened so force a commit now.
+
+ CommitChanges();
+
+ // TODO(benm): It's possible that the commit failed, and in
+ // that case we're going to lose data. Integrate with UMA
+ // to gather stats about how often this actually happens,
+ // so that we can figure out a contingency plan.
+ }
}
unsigned DomStorageArea::Length() {
+ InitialImportIfNeeded();
return map_->Length();
}
NullableString16 DomStorageArea::Key(unsigned index) {
+ InitialImportIfNeeded();
return map_->Key(index);
}
NullableString16 DomStorageArea::GetItem(const string16& key) {
+ InitialImportIfNeeded();
return map_->GetItem(key);
}
-bool DomStorageArea::SetItem(
- const string16& key, const string16& value,
- NullableString16* old_value) {
+bool DomStorageArea::SetItem(const string16& key,
+ const string16& value,
+ NullableString16* old_value) {
+ InitialImportIfNeeded();
+
if (!map_->HasOneRef())
map_ = map_->DeepCopy();
- return map_->SetItem(key, value, old_value);
+ bool success = map_->SetItem(key, value, old_value);
+ if (success && backing_.get()) {
+ changed_values_[key] = NullableString16(value, false);
+ ScheduleCommitChanges();
+ }
+ return success;
}
-bool DomStorageArea::RemoveItem(
- const string16& key,
- string16* old_value) {
+bool DomStorageArea::RemoveItem(const string16& key, string16* old_value) {
+ InitialImportIfNeeded();
if (!map_->HasOneRef())
map_ = map_->DeepCopy();
- return map_->RemoveItem(key, old_value);
+ bool success = map_->RemoveItem(key, old_value);
+ if (success && backing_.get()) {
+ changed_values_[key] = NullableString16(true);
+ ScheduleCommitChanges();
+ }
+ return success;
}
bool DomStorageArea::Clear() {
+ InitialImportIfNeeded();
if (map_->Length() == 0)
return false;
+
map_ = new DomStorageMap(kPerAreaQuota);
+
+ if (backing_.get()) {
+ changed_values_.clear();
+ clear_all_next_commit_ = true;
+ ScheduleCommitChanges();
+ }
+
return true;
}
@@ -61,10 +117,56 @@ DomStorageArea* DomStorageArea::ShallowCopy(int64 destination_namespace_id) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
// SessionNamespaces aren't backed by files on disk.
+ DCHECK(!backing_.get());
+
DomStorageArea* copy = new DomStorageArea(destination_namespace_id, origin_,
FilePath(), task_runner_);
copy->map_ = map_;
return copy;
}
+void DomStorageArea::InitialImportIfNeeded() {
+ if (initial_import_done_)
+ return;
+
+ DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
+ DCHECK(backing_.get());
+
+ ValuesMap initial_values;
+ backing_->ReadAllValues(&initial_values);
+ map_->SwapValues(&initial_values);
+ initial_import_done_ = true;
+}
+
+void DomStorageArea::ScheduleCommitChanges() {
+ DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
+ DCHECK(backing_.get());
+ DCHECK(clear_all_next_commit_ || !changed_values_.empty());
+ DCHECK(task_runner_.get());
+
+ if (commit_in_flight_)
+ return;
+
+ commit_in_flight_ = task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&DomStorageArea::CommitChanges, this),
+ base::TimeDelta::FromSeconds(1));
+ DCHECK(commit_in_flight_);
+}
+
+void DomStorageArea::CommitChanges() {
+ DCHECK(backing_.get());
+ if (backing_->CommitChanges(clear_all_next_commit_, changed_values_)) {
+ clear_all_next_commit_ = false;
+ changed_values_.clear();
+ }
+ commit_in_flight_ = false;
+}
+
+// static
+FilePath DomStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) {
+ std::string filename = fileapi::GetOriginIdentifierFromURL(origin)
+ + ".localstorage";
+ return FilePath().AppendASCII(filename);
+}
+
} // namespace dom_storage