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

Unified Diff: webkit/dom_storage/dom_storage_area.cc

Issue 9963107: Persist sessionStorage on disk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cleanup. Created 8 years, 8 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: webkit/dom_storage/dom_storage_area.cc
diff --git a/webkit/dom_storage/dom_storage_area.cc b/webkit/dom_storage/dom_storage_area.cc
index ed4885b7b078f8e01f368fb944db7f066ff6a9df..8f87e726ff0a9c900b0e64893c75dd298ac426a0 100644
--- a/webkit/dom_storage/dom_storage_area.cc
+++ b/webkit/dom_storage/dom_storage_area.cc
@@ -5,16 +5,19 @@
#include "webkit/dom_storage/dom_storage_area.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/time.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
#include "webkit/database/database_util.h"
+#include "webkit/dom_storage/dom_storage_database.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/dom_storage/local_storage_database_adapter.h"
+#include "webkit/dom_storage/session_storage_database.h"
+#include "webkit/dom_storage/session_storage_database_adapter.h"
#include "webkit/fileapi/file_system_util.h"
#include "webkit/glue/webkit_glue.h"
@@ -25,7 +28,8 @@ namespace dom_storage {
static const int kCommitTimerSeconds = 1;
DomStorageArea::CommitBatch::CommitBatch()
- : clear_all_first(false) {
+ : clear_all_first(false),
+ clear_all_after_deep_copy(false) {
}
DomStorageArea::CommitBatch::~CommitBatch() {}
@@ -59,13 +63,40 @@ DomStorageArea::DomStorageArea(
directory_(directory),
task_runner_(task_runner),
map_(new DomStorageMap(kPerAreaQuota)),
+ is_initial_import_done_(false),
+ is_shutdown_(false),
+ is_shallow_copy_(false) {
+ DCHECK(!directory.empty());
+ DCHECK_EQ(kLocalStorageNamespaceId, namespace_id);
+ FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
+ backing_.reset(new LocalStorageDatabaseAdapter(new DomStorageDatabase(path)));
+}
+
+DomStorageArea::DomStorageArea(
+ int64 namespace_id, const GURL& origin,
+ SessionStorageDatabase* session_storage_backing,
+ DomStorageTaskRunner* task_runner)
+ : namespace_id_(namespace_id), origin_(origin),
+ task_runner_(task_runner),
+ map_(new DomStorageMap(kPerAreaQuota)),
+ session_storage_backing_(session_storage_backing),
+ is_initial_import_done_(false),
+ is_shutdown_(false),
+ is_shallow_copy_(false) {
+ DCHECK(namespace_id != kLocalStorageNamespaceId);
+ backing_.reset(new SessionStorageDatabaseAdapter(
+ session_storage_backing, namespace_id, origin));
+}
+
+DomStorageArea::DomStorageArea(int64 namespace_id,
+ const GURL& origin,
+ DomStorageTaskRunner* task_runner)
+ : namespace_id_(namespace_id), origin_(origin),
+ task_runner_(task_runner),
+ map_(new DomStorageMap(kPerAreaQuota)),
is_initial_import_done_(true),
- is_shutdown_(false) {
- if (namespace_id == kLocalStorageNamespaceId && !directory.empty()) {
- FilePath path = directory.Append(DatabaseFileNameFromOrigin(origin_));
- backing_.reset(new DomStorageDatabase(path));
- is_initial_import_done_ = false;
- }
+ is_shutdown_(false),
+ is_shallow_copy_(false) {
}
DomStorageArea::~DomStorageArea() {
@@ -98,12 +129,32 @@ bool DomStorageArea::SetItem(const string16& key,
if (is_shutdown_)
return false;
InitialImportIfNeeded();
- if (!map_->HasOneRef())
- map_ = map_->DeepCopy();
+ bool was_shallow_copy = is_shallow_copy_;
+ if (is_shallow_copy_) {
+ // It's possible that the other DomStorageAreas referring to the same map
+ // already made a deep copy. If that's the case, we don't need to do
+ // anything.
michaeln 2012/04/22 21:43:35 i'd rather depend on HasOneRef() for this and nix
marja 2012/05/11 12:18:32 Done.
+ if (!map_->HasOneRef())
+ map_ = map_->DeepCopy();
+ is_shallow_copy_ = false;
+ }
bool success = map_->SetItem(key, value, old_value);
if (success && backing_.get()) {
CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
- commit_batch->changed_values[key] = NullableString16(value, false);
+ // If this area was a shallow copy, the existing changes in the commit batch
+ // should be committed before doing a deep copy. This change, and all the
+ // changes after this, should be committed after the deep copy. The database
+ // takes care of not doing a deep copy of a map which is only referred to
+ // once.
michaeln 2012/04/22 21:43:35 It might be a simplification to flush pending chan
michaeln 2012/04/22 23:48:02 or maybe a pattern like this that factors out more
marja 2012/05/11 12:18:32 - The deep copy problem was solved by http://coder
michaeln 2012/05/16 08:10:55 sgtm!
+ if (was_shallow_copy ||
+ !commit_batch->changed_values_after_deep_copy.empty() ||
+ commit_batch->clear_all_after_deep_copy) {
+ commit_batch->changed_values_after_deep_copy[key] =
+ NullableString16(value, false);
+ }
+ else {
+ commit_batch->changed_values[key] = NullableString16(value, false);
+ }
}
return success;
}
@@ -112,12 +163,24 @@ bool DomStorageArea::RemoveItem(const string16& key, string16* old_value) {
if (is_shutdown_)
return false;
InitialImportIfNeeded();
- if (!map_->HasOneRef())
- map_ = map_->DeepCopy();
+ // See comments in SetItem.
+ bool was_shallow_copy = is_shallow_copy_;
+ if (is_shallow_copy_) {
+ if (!map_->HasOneRef())
+ map_ = map_->DeepCopy();
+ is_shallow_copy_ = false;
+ }
bool success = map_->RemoveItem(key, old_value);
if (success && backing_.get()) {
CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
- commit_batch->changed_values[key] = NullableString16(true);
+ if (was_shallow_copy ||
+ !commit_batch->changed_values_after_deep_copy.empty() ||
+ commit_batch->clear_all_after_deep_copy) {
+ commit_batch->changed_values_after_deep_copy[key] =
+ NullableString16(true);
+ } else {
+ commit_batch->changed_values[key] = NullableString16(true);
+ }
}
return success;
}
@@ -129,12 +192,22 @@ bool DomStorageArea::Clear() {
if (map_->Length() == 0)
return false;
+ // See comments in SetItem.
+ bool was_shallow_copy = is_shallow_copy_;
+ is_shallow_copy_ = false;
map_ = new DomStorageMap(kPerAreaQuota);
if (backing_.get()) {
CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
- commit_batch->clear_all_first = true;
- commit_batch->changed_values.clear();
+ if (was_shallow_copy ||
+ !commit_batch->changed_values_after_deep_copy.empty() ||
+ commit_batch->clear_all_after_deep_copy) {
+ commit_batch->clear_all_after_deep_copy = true;
+ commit_batch->changed_values_after_deep_copy.clear();
+ } else {
+ commit_batch->clear_all_first = true;
+ commit_batch->changed_values.clear();
+ }
}
return true;
@@ -143,12 +216,27 @@ bool DomStorageArea::Clear() {
DomStorageArea* DomStorageArea::ShallowCopy(int64 destination_namespace_id) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
- DCHECK(!backing_.get()); // SessionNamespaces aren't stored on disk.
+ DCHECK(session_storage_backing_.get());
- DomStorageArea* copy = new DomStorageArea(destination_namespace_id, origin_,
- FilePath(), task_runner_);
+ DomStorageArea* copy = new DomStorageArea(
+ destination_namespace_id, origin_, session_storage_backing_,
+ task_runner_);
+ copy->is_shallow_copy_ = true;
copy->map_ = map_;
copy->is_shutdown_ = is_shutdown_;
+
+ // Also this area is now a shallow copy; changes to either of these 2 areas
+ // will initiate deep copying.
+ is_shallow_copy_ = true;
+
+ if (session_storage_backing_.get()) {
+ // If this area has uncommitted changes, they need to happen before
+ // DomStorageNamespace does the shallow-copying of the database. Also, if
+ // the area is empty, we need to ensure that a placeholder for it exists in
+ // the database. An empty commit batch achieves this.
michaeln 2012/04/22 21:43:35 Does the empty placeholder really need to be there
marja 2012/05/11 12:18:32 Done. Empty placeholder is not needed any more.
+ CreateCommitBatchIfNeeded();
+ OnCommitTimer();
+ }
return copy;
}
@@ -169,12 +257,19 @@ void DomStorageArea::DeleteOrigin() {
return;
}
map_ = new DomStorageMap(kPerAreaQuota);
- if (backing_.get()) {
+ if (backing_.get() && !session_storage_backing_.get()) {
+ // This is localStorage.
is_initial_import_done_ = false;
- backing_.reset(new DomStorageDatabase(backing_->file_path()));
- file_util::Delete(backing_->file_path(), false);
- file_util::Delete(
- DomStorageDatabase::GetJournalFilePath(backing_->file_path()), false);
+ backing_->Reset();
+ backing_->DeleteFiles();
+ } else if (session_storage_backing_.get()) {
+ // Delete the origin from the session storage by creating an empty commit
+ // batch.
+ CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
+ if (is_shallow_copy_)
+ commit_batch->clear_all_after_deep_copy = true;
+ else
+ commit_batch->clear_all_first = true;
}
}
@@ -191,7 +286,7 @@ void DomStorageArea::PurgeMemory() {
// Recreate the database object, this frees up the open sqlite connection
// and its page cache.
- backing_.reset(new DomStorageDatabase(backing_->file_path()));
+ backing_->Reset();
}
void DomStorageArea::Shutdown() {
@@ -212,7 +307,6 @@ void DomStorageArea::InitialImportIfNeeded() {
if (is_initial_import_done_)
return;
- DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
DCHECK(backing_.get());
ValuesMap initial_values;
@@ -240,12 +334,15 @@ DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() {
}
void DomStorageArea::OnCommitTimer() {
- DCHECK_EQ(kLocalStorageNamespaceId, namespace_id_);
if (is_shutdown_)
return;
DCHECK(backing_.get());
- DCHECK(commit_batch_.get());
+ // It's possible that there is nothing to commit, since a shallow copy occured
+ // before the timer fired.
+ if (!commit_batch_.get())
+ return;
+
DCHECK(!in_flight_commit_batch_.get());
// This method executes on the primary sequence, we schedule
@@ -267,6 +364,23 @@ void DomStorageArea::CommitChanges() {
in_flight_commit_batch_->clear_all_first,
in_flight_commit_batch_->changed_values);
DCHECK(success); // TODO(michaeln): what if it fails?
+ if (session_storage_backing_.get() &&
+ (in_flight_commit_batch_->clear_all_after_deep_copy ||
+ !in_flight_commit_batch_->changed_values_after_deep_copy.empty())) {
+ if (in_flight_commit_batch_->clear_all_after_deep_copy) {
+ // Shortcut: If we're going to make a deep copy and clear the area, no
+ // need to create the deep copy first. We will just break the association
+ // to the existing map. A new map will be created when data is inserted
+ // into it.
+ session_storage_backing_->DisassociateMap(namespace_id_, origin_);
+ } else {
+ session_storage_backing_->DeepCopy(namespace_id_, origin_);
+ }
+ bool success = backing_->CommitChanges(
+ false, in_flight_commit_batch_->changed_values_after_deep_copy);
+ DCHECK(success); // TODO(michaeln): what if it fails?
+ }
+
task_runner_->PostTask(
FROM_HERE,
base::Bind(&DomStorageArea::OnCommitComplete, this));
@@ -301,6 +415,7 @@ void DomStorageArea::ShutdownInCommitSequence() {
commit_batch_.reset();
in_flight_commit_batch_.reset();
backing_.reset();
+ session_storage_backing_ = NULL;
}
} // namespace dom_storage

Powered by Google App Engine
This is Rietveld 408576698