diff options
author | benm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-27 16:26:00 +0000 |
---|---|---|
committer | benm@chromium.org <benm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-27 16:26:00 +0000 |
commit | 2e99afd1570da29165b52f69c8d2b29069767ac0 (patch) | |
tree | d16fbc74e5618a967d0da7f82abd5a45d953f994 /webkit/dom_storage/dom_storage_area.cc | |
parent | e395632a2e7caef7c1113306b1cdf6961452e1ae (diff) | |
download | chromium_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.cc | 124 |
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 |