summaryrefslogtreecommitdiffstats
path: root/content/browser/dom_storage
diff options
context:
space:
mode:
authortburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-11 23:30:25 +0000
committertburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-11 23:30:25 +0000
commit458061b6c2e1d299689264922b7a274c3963677b (patch)
tree6f9e1f9274140cd1e2c298c5c027d36b66ab3cbe /content/browser/dom_storage
parent85181aab0f6d85c4f79b82872a2f6eb4bbd63aea (diff)
downloadchromium_src-458061b6c2e1d299689264922b7a274c3963677b.zip
chromium_src-458061b6c2e1d299689264922b7a274c3963677b.tar.gz
chromium_src-458061b6c2e1d299689264922b7a274c3963677b.tar.bz2
Allow aliasing and merging of session storage namespaces.
R=jam@chromium.org, marja@chromium.org, michaeln@chromium.org Review URL: https://codereview.chromium.org/62923003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234317 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/dom_storage')
-rw-r--r--content/browser/dom_storage/dom_storage_context_impl.cc67
-rw-r--r--content/browser/dom_storage/dom_storage_context_impl.h20
-rw-r--r--content/browser/dom_storage/dom_storage_context_impl_unittest.cc112
-rw-r--r--content/browser/dom_storage/dom_storage_host.cc29
-rw-r--r--content/browser/dom_storage/dom_storage_host.h7
-rw-r--r--content/browser/dom_storage/dom_storage_message_filter.cc13
-rw-r--r--content/browser/dom_storage/dom_storage_message_filter.h1
-rw-r--r--content/browser/dom_storage/dom_storage_namespace.cc147
-rw-r--r--content/browser/dom_storage/dom_storage_namespace.h48
-rw-r--r--content/browser/dom_storage/dom_storage_session.cc52
-rw-r--r--content/browser/dom_storage/dom_storage_session.h17
-rw-r--r--content/browser/dom_storage/session_storage_namespace_impl.cc16
-rw-r--r--content/browser/dom_storage/session_storage_namespace_impl.h13
13 files changed, 496 insertions, 46 deletions
diff --git a/content/browser/dom_storage/dom_storage_context_impl.cc b/content/browser/dom_storage/dom_storage_context_impl.cc
index 98eab63..44c4242 100644
--- a/content/browser/dom_storage/dom_storage_context_impl.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl.cc
@@ -238,6 +238,16 @@ void DOMStorageContextImpl::NotifyAreaCleared(
OnDOMStorageAreaCleared(area, page_url));
}
+void DOMStorageContextImpl::NotifyAliasSessionMerged(
+ int64 namespace_id,
+ DOMStorageNamespace* old_alias_master_namespace) {
+ FOR_EACH_OBSERVER(
+ EventObserver, event_observers_,
+ OnDOMSessionStorageReset(namespace_id));
+ if (old_alias_master_namespace)
+ MaybeShutdownSessionNamespace(old_alias_master_namespace);
+}
+
std::string DOMStorageContextImpl::AllocatePersistentSessionId() {
std::string guid = base::GenerateGUID();
std::replace(guid.begin(), guid.end(), '-', '_');
@@ -262,11 +272,36 @@ void DOMStorageContextImpl::DeleteSessionNamespace(
int64 namespace_id, bool should_persist_data) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
- if (it == namespaces_.end())
+ if (it == namespaces_.end() ||
+ it->second->ready_for_deletion_pending_aliases()) {
+ return;
+ }
+ it->second->set_ready_for_deletion_pending_aliases(true);
+ DOMStorageNamespace* alias_master = it->second->alias_master_namespace();
+ if (alias_master) {
+ DCHECK(it->second->num_aliases() == 0);
+ DCHECK(alias_master->alias_master_namespace() == NULL);
+ if (should_persist_data)
+ alias_master->set_must_persist_at_shutdown(true);
+ if (it->second->DecrementMasterAliasCount())
+ MaybeShutdownSessionNamespace(alias_master);
+ namespaces_.erase(namespace_id);
+ } else {
+ if (should_persist_data)
+ it->second->set_must_persist_at_shutdown(true);
+ MaybeShutdownSessionNamespace(it->second);
+ }
+}
+
+void DOMStorageContextImpl::MaybeShutdownSessionNamespace(
+ DOMStorageNamespace* ns) {
+ if (ns->num_aliases() > 0 || !ns->ready_for_deletion_pending_aliases())
return;
- std::string persistent_namespace_id = it->second->persistent_namespace_id();
+ DCHECK_EQ(ns->num_aliases(), 0);
+ DCHECK(ns->alias_master_namespace() == NULL);
+ std::string persistent_namespace_id = ns->persistent_namespace_id();
if (session_storage_database_.get()) {
- if (!should_persist_data) {
+ if (!ns->must_persist_at_shutdown()) {
task_runner_->PostShutdownBlockingTask(
FROM_HERE,
DOMStorageTaskRunner::COMMIT_SEQUENCE,
@@ -276,7 +311,7 @@ void DOMStorageContextImpl::DeleteSessionNamespace(
persistent_namespace_id));
} else {
// Ensure that the data gets committed before we shut down.
- it->second->Shutdown();
+ ns->Shutdown();
if (!scavenging_started_) {
// Protect the persistent namespace ID from scavenging.
protected_persistent_session_ids_.insert(persistent_namespace_id);
@@ -284,7 +319,7 @@ void DOMStorageContextImpl::DeleteSessionNamespace(
}
}
persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
- namespaces_.erase(namespace_id);
+ namespaces_.erase(ns->namespace_id());
}
void DOMStorageContextImpl::CloneSessionNamespace(
@@ -301,6 +336,21 @@ void DOMStorageContextImpl::CloneSessionNamespace(
CreateSessionNamespace(new_id, new_persistent_id);
}
+void DOMStorageContextImpl::CreateAliasSessionNamespace(
+ int64 existing_id, int64 new_id,
+ const std::string& persistent_id) {
+ if (is_shutdown_)
+ return;
+ DCHECK_NE(kLocalStorageNamespaceId, existing_id);
+ DCHECK_NE(kLocalStorageNamespaceId, new_id);
+ StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
+ if (found != namespaces_.end()) {
+ namespaces_[new_id] = found->second->CreateAlias(new_id);
+ } else {
+ CreateSessionNamespace(new_id, persistent_id);
+ }
+}
+
void DOMStorageContextImpl::ClearSessionOnlyOrigins() {
if (!localstorage_directory_.empty()) {
std::vector<LocalStorageUsageInfo> infos;
@@ -438,8 +488,9 @@ void DOMStorageContextImpl::RemoveTransactionLogProcessId(int64 namespace_id,
}
SessionStorageNamespace::MergeResult
-DOMStorageContextImpl::CanMergeSessionStorage(
- int64 namespace1_id, int process_id, int64 namespace2_id) {
+DOMStorageContextImpl::MergeSessionStorage(
+ int64 namespace1_id, bool actually_merge, int process_id,
+ int64 namespace2_id) {
DCHECK_NE(kLocalStorageNamespaceId, namespace1_id);
DCHECK_NE(kLocalStorageNamespaceId, namespace2_id);
StorageNamespaceMap::const_iterator it = namespaces_.find(namespace1_id);
@@ -450,7 +501,7 @@ DOMStorageContextImpl::CanMergeSessionStorage(
if (it == namespaces_.end())
return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND;
DOMStorageNamespace* ns2 = it->second;
- return ns1->CanMerge(process_id, ns2);
+ return ns1->Merge(actually_merge, process_id, ns2, this);
}
} // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_impl.h b/content/browser/dom_storage/dom_storage_context_impl.h
index c56024b..a9400fb 100644
--- a/content/browser/dom_storage/dom_storage_context_impl.h
+++ b/content/browser/dom_storage/dom_storage_context_impl.h
@@ -16,6 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
#include "content/common/content_export.h"
#include "content/public/browser/session_storage_namespace.h"
#include "url/gurl.h"
@@ -33,7 +34,6 @@ class SpecialStoragePolicy;
namespace content {
class DOMStorageArea;
-class DOMStorageNamespace;
class DOMStorageSession;
class DOMStorageTaskRunner;
class SessionStorageDatabase;
@@ -81,6 +81,9 @@ class CONTENT_EXPORT DOMStorageContextImpl
virtual void OnDOMStorageAreaCleared(
const DOMStorageArea* area,
const GURL& page_url) = 0;
+ // Indicates that cached values of the DOM Storage provided must be
+ // cleared and retrieved again.
+ virtual void OnDOMSessionStorageReset(int64 namespace_id) = 0;
protected:
virtual ~EventObserver() {}
@@ -134,6 +137,7 @@ class CONTENT_EXPORT DOMStorageContextImpl
// Methods to add, remove, and notify EventObservers.
void AddEventObserver(EventObserver* observer);
void RemoveEventObserver(EventObserver* observer);
+
void NotifyItemSet(
const DOMStorageArea* area,
const base::string16& key,
@@ -148,6 +152,9 @@ class CONTENT_EXPORT DOMStorageContextImpl
void NotifyAreaCleared(
const DOMStorageArea* area,
const GURL& page_url);
+ void NotifyAliasSessionMerged(
+ int64 namespace_id,
+ DOMStorageNamespace* old_alias_master_namespace);
// May be called on any thread.
int64 AllocateSessionId() {
@@ -162,6 +169,8 @@ class CONTENT_EXPORT DOMStorageContextImpl
void DeleteSessionNamespace(int64 namespace_id, bool should_persist_data);
void CloneSessionNamespace(int64 existing_id, int64 new_id,
const std::string& new_persistent_id);
+ void CreateAliasSessionNamespace(int64 existing_id, int64 new_id,
+ const std::string& persistent_id);
// Starts backing sessionStorage on disk. This function must be called right
// after DOMStorageContextImpl is created, before it's used.
@@ -175,8 +184,9 @@ class CONTENT_EXPORT DOMStorageContextImpl
void AddTransactionLogProcessId(int64 namespace_id, int process_id);
void RemoveTransactionLogProcessId(int64 namespace_id, int process_id);
- SessionStorageNamespace::MergeResult CanMergeSessionStorage(
- int64 namespace1_id, int process_id, int64 namespace2_id);
+ SessionStorageNamespace::MergeResult MergeSessionStorage(
+ int64 namespace1_id, bool actually_merge, int process_id,
+ int64 namespace2_id);
private:
friend class DOMStorageContextImplTest;
@@ -185,10 +195,12 @@ class CONTENT_EXPORT DOMStorageContextImpl
typedef std::map<int64, scoped_refptr<DOMStorageNamespace> >
StorageNamespaceMap;
- ~DOMStorageContextImpl();
+ virtual ~DOMStorageContextImpl();
void ClearSessionOnlyOrigins();
+ void MaybeShutdownSessionNamespace(DOMStorageNamespace* ns);
+
// For scavenging unused sessionStorages.
void FindUnusedNamespaces();
void FindUnusedNamespacesInCommitSequence(
diff --git a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
index 27aaefb2..ba8d8e9 100644
--- a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "content/browser/dom_storage/dom_storage_namespace.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_namespace.h"
#include "content/public/browser/session_storage_usage_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/quota/mock_special_storage_policy.h"
@@ -260,4 +261,115 @@ TEST_F(DOMStorageContextImplTest, DeleteSessionStorage) {
base::MessageLoop::current()->RunUntilIdle();
}
+TEST_F(DOMStorageContextImplTest, SessionStorageAlias) {
+ const int kFirstSessionStorageNamespaceId = 1;
+ const std::string kPersistentId = "persistent";
+ context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
+ kPersistentId);
+ DOMStorageNamespace* dom_namespace1 =
+ context_->GetStorageNamespace(kFirstSessionStorageNamespaceId);
+ ASSERT_TRUE(dom_namespace1);
+ DOMStorageArea* area1 = dom_namespace1->OpenStorageArea(kOrigin);
+ base::NullableString16 old_value;
+ area1->SetItem(kKey, kValue, &old_value);
+ EXPECT_TRUE(old_value.is_null());
+ base::NullableString16 read_value = area1->GetItem(kKey);
+ EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
+
+ // Create an alias.
+ const int kAliasSessionStorageNamespaceId = 2;
+ context_->CreateAliasSessionNamespace(kFirstSessionStorageNamespaceId,
+ kAliasSessionStorageNamespaceId,
+ kPersistentId);
+ DOMStorageNamespace* dom_namespace2 =
+ context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
+ ASSERT_TRUE(dom_namespace2);
+ ASSERT_TRUE(dom_namespace2->alias_master_namespace() == dom_namespace1);
+
+ // Verify that read values are identical.
+ DOMStorageArea* area2 = dom_namespace2->OpenStorageArea(kOrigin);
+ read_value = area2->GetItem(kKey);
+ EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
+
+ // Verify that writes are reflected in both namespaces.
+ const base::string16 kValue2(ASCIIToUTF16("value2"));
+ area2->SetItem(kKey, kValue2, &old_value);
+ read_value = area1->GetItem(kKey);
+ EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
+ dom_namespace1->CloseStorageArea(area1);
+ dom_namespace2->CloseStorageArea(area2);
+
+ // When creating an alias of an alias, ensure that the master relationship
+ // is collapsed.
+ const int kAlias2SessionStorageNamespaceId = 3;
+ context_->CreateAliasSessionNamespace(kAliasSessionStorageNamespaceId,
+ kAlias2SessionStorageNamespaceId,
+ kPersistentId);
+ DOMStorageNamespace* dom_namespace3 =
+ context_->GetStorageNamespace(kAlias2SessionStorageNamespaceId);
+ ASSERT_TRUE(dom_namespace3);
+ ASSERT_TRUE(dom_namespace3->alias_master_namespace() == dom_namespace1);
+}
+
+TEST_F(DOMStorageContextImplTest, SessionStorageMerge) {
+ // Create a target namespace that we will merge into.
+ const int kTargetSessionStorageNamespaceId = 1;
+ const std::string kTargetPersistentId = "persistent";
+ context_->CreateSessionNamespace(kTargetSessionStorageNamespaceId,
+ kTargetPersistentId);
+ DOMStorageNamespace* target_ns =
+ context_->GetStorageNamespace(kTargetSessionStorageNamespaceId);
+ ASSERT_TRUE(target_ns);
+ DOMStorageArea* target_ns_area = target_ns->OpenStorageArea(kOrigin);
+ base::NullableString16 old_value;
+ const base::string16 kKey2(ASCIIToUTF16("key2"));
+ const base::string16 kKey2Value(ASCIIToUTF16("key2value"));
+ target_ns_area->SetItem(kKey, kValue, &old_value);
+ target_ns_area->SetItem(kKey2, kKey2Value, &old_value);
+
+ // Create a source namespace & its alias.
+ const int kSourceSessionStorageNamespaceId = 2;
+ const int kAliasSessionStorageNamespaceId = 3;
+ const std::string kSourcePersistentId = "persistent_source";
+ context_->CreateSessionNamespace(kSourceSessionStorageNamespaceId,
+ kSourcePersistentId);
+ context_->CreateAliasSessionNamespace(kSourceSessionStorageNamespaceId,
+ kAliasSessionStorageNamespaceId,
+ kSourcePersistentId);
+ DOMStorageNamespace* alias_ns =
+ context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
+ ASSERT_TRUE(alias_ns);
+
+ // Create a transaction log that can't be merged.
+ const int kPid1 = 10;
+ ASSERT_FALSE(alias_ns->IsLoggingRenderer(kPid1));
+ alias_ns->AddTransactionLogProcessId(kPid1);
+ ASSERT_TRUE(alias_ns->IsLoggingRenderer(kPid1));
+ const base::string16 kValue2(ASCIIToUTF16("value2"));
+ DOMStorageNamespace::TransactionRecord txn;
+ txn.origin = kOrigin;
+ txn.key = kKey;
+ txn.value = base::NullableString16(kValue2, false);
+ txn.transaction_type = DOMStorageNamespace::TRANSACTION_READ;
+ alias_ns->AddTransaction(kPid1, txn);
+ ASSERT_TRUE(alias_ns->Merge(false, kPid1, target_ns, NULL) ==
+ SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE);
+
+ // Create a transaction log that can be merged.
+ const int kPid2 = 20;
+ alias_ns->AddTransactionLogProcessId(kPid2);
+ txn.transaction_type = DOMStorageNamespace::TRANSACTION_WRITE;
+ alias_ns->AddTransaction(kPid2, txn);
+ ASSERT_TRUE(alias_ns->Merge(true, kPid2, target_ns, NULL) ==
+ SessionStorageNamespace::MERGE_RESULT_MERGEABLE);
+
+ // Verify that the merge was successful.
+ ASSERT_TRUE(alias_ns->alias_master_namespace() == target_ns);
+ base::NullableString16 read_value = target_ns_area->GetItem(kKey);
+ EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
+ DOMStorageArea* alias_ns_area = alias_ns->OpenStorageArea(kOrigin);
+ read_value = alias_ns_area->GetItem(kKey2);
+ EXPECT_TRUE(!read_value.is_null() && read_value.string() == kKey2Value);
+}
+
} // namespace content
diff --git a/content/browser/dom_storage/dom_storage_host.cc b/content/browser/dom_storage/dom_storage_host.cc
index de57be2..556f76d 100644
--- a/content/browser/dom_storage/dom_storage_host.cc
+++ b/content/browser/dom_storage/dom_storage_host.cc
@@ -107,7 +107,7 @@ bool DOMStorageHost::SetAreaItem(
context_->NotifyItemSet(area, key, value, *old_value, page_url);
MaybeLogTransaction(connection_id,
DOMStorageNamespace::TRANSACTION_WRITE,
- area->origin(), key,
+ area->origin(), page_url, key,
base::NullableString16(value, false));
return true;
}
@@ -120,7 +120,7 @@ void DOMStorageHost::LogGetAreaItem(
return;
MaybeLogTransaction(connection_id,
DOMStorageNamespace::TRANSACTION_READ,
- area->origin(), key, value);
+ area->origin(), GURL(), key, value);
}
bool DOMStorageHost::RemoveAreaItem(
@@ -134,7 +134,7 @@ bool DOMStorageHost::RemoveAreaItem(
context_->NotifyItemRemoved(area, key, *old_value, page_url);
MaybeLogTransaction(connection_id,
DOMStorageNamespace::TRANSACTION_REMOVE,
- area->origin(), key, base::NullableString16());
+ area->origin(), page_url, key, base::NullableString16());
return true;
}
@@ -147,23 +147,38 @@ bool DOMStorageHost::ClearArea(int connection_id, const GURL& page_url) {
context_->NotifyAreaCleared(area, page_url);
MaybeLogTransaction(connection_id,
DOMStorageNamespace::TRANSACTION_CLEAR,
- area->origin(), base::string16(),
+ area->origin(), page_url, base::string16(),
base::NullableString16());
return true;
}
bool DOMStorageHost::HasAreaOpen(
- int namespace_id, const GURL& origin) const {
+ int64 namespace_id, const GURL& origin, int64* alias_namespace_id) const {
AreaMap::const_iterator it = connections_.begin();
for (; it != connections_.end(); ++it) {
- if (namespace_id == it->second.namespace_->namespace_id() &&
+ if (namespace_id == it->second.area_->namespace_id() &&
origin == it->second.area_->origin()) {
+ *alias_namespace_id = it->second.namespace_->namespace_id();
return true;
}
}
return false;
}
+bool DOMStorageHost::ResetOpenAreasForNamespace(int64 namespace_id) {
+ bool result = false;
+ AreaMap::iterator it = connections_.begin();
+ for (; it != connections_.end(); ++it) {
+ if (namespace_id == it->second.namespace_->namespace_id()) {
+ GURL origin = it->second.area_->origin();
+ it->second.namespace_->CloseStorageArea(it->second.area_.get());
+ it->second.area_ = it->second.namespace_->OpenStorageArea(origin);
+ result = true;
+ }
+ }
+ return result;
+}
+
DOMStorageArea* DOMStorageHost::GetOpenArea(int connection_id) {
AreaMap::iterator found = connections_.find(connection_id);
if (found == connections_.end())
@@ -182,6 +197,7 @@ void DOMStorageHost::MaybeLogTransaction(
int connection_id,
DOMStorageNamespace::LogType transaction_type,
const GURL& origin,
+ const GURL& page_url,
const base::string16& key,
const base::NullableString16& value) {
DOMStorageNamespace* ns = GetNamespace(connection_id);
@@ -191,6 +207,7 @@ void DOMStorageHost::MaybeLogTransaction(
DOMStorageNamespace::TransactionRecord transaction;
transaction.transaction_type = transaction_type;
transaction.origin = origin;
+ transaction.page_url = page_url;
transaction.key = key;
transaction.value = value;
ns->AddTransaction(render_process_id_, transaction);
diff --git a/content/browser/dom_storage/dom_storage_host.h b/content/browser/dom_storage/dom_storage_host.h
index f10bb29..f4ca784 100644
--- a/content/browser/dom_storage/dom_storage_host.h
+++ b/content/browser/dom_storage/dom_storage_host.h
@@ -51,7 +51,11 @@ class CONTENT_EXPORT DOMStorageHost {
const GURL& page_url,
base::string16* old_value);
bool ClearArea(int connection_id, const GURL& page_url);
- bool HasAreaOpen(int namespace_id, const GURL& origin) const;
+ bool HasAreaOpen(int64 namespace_id, const GURL& origin,
+ int64* alias_namespace_id) const;
+ // Resets all open areas for the namespace provided. Returns true
+ // iff there were any areas to reset.
+ bool ResetOpenAreasForNamespace(int64 namespace_id);
private:
// Struct to hold references needed for areas that are open
@@ -70,6 +74,7 @@ class CONTENT_EXPORT DOMStorageHost {
int connection_id,
DOMStorageNamespace::LogType transaction_type,
const GURL& origin,
+ const GURL& page_url,
const base::string16& key,
const base::NullableString16& value);
diff --git a/content/browser/dom_storage/dom_storage_message_filter.cc b/content/browser/dom_storage/dom_storage_message_filter.cc
index ce5a8c1..3ab972c 100644
--- a/content/browser/dom_storage/dom_storage_message_filter.cc
+++ b/content/browser/dom_storage/dom_storage_message_filter.cc
@@ -193,6 +193,11 @@ void DOMStorageMessageFilter::OnDOMStorageAreaCleared(
base::NullableString16());
}
+void DOMStorageMessageFilter::OnDOMSessionStorageReset(int64 namespace_id) {
+ if (host_->ResetOpenAreasForNamespace(namespace_id))
+ Send(new DOMStorageMsg_ResetCachedValues(namespace_id));
+}
+
void DOMStorageMessageFilter::SendDOMStorageEvent(
const DOMStorageArea* area,
const GURL& page_url,
@@ -202,8 +207,10 @@ void DOMStorageMessageFilter::SendDOMStorageEvent(
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
// Only send mutation events to processes which have the area open.
bool originated_in_process = connection_dispatching_message_for_ != 0;
- if (originated_in_process ||
- host_->HasAreaOpen(area->namespace_id(), area->origin())) {
+ int64 alias_namespace_id = area->namespace_id();
+ if (host_->HasAreaOpen(area->namespace_id(), area->origin(),
+ &alias_namespace_id) ||
+ originated_in_process) {
DOMStorageMsg_Event_Params params;
params.origin = area->origin();
params.page_url = page_url;
@@ -211,7 +218,7 @@ void DOMStorageMessageFilter::SendDOMStorageEvent(
params.key = key;
params.new_value = new_value;
params.old_value = old_value;
- params.namespace_id = area->namespace_id();
+ params.namespace_id = alias_namespace_id;
Send(new DOMStorageMsg_Event(params));
}
}
diff --git a/content/browser/dom_storage/dom_storage_message_filter.h b/content/browser/dom_storage/dom_storage_message_filter.h
index 7856d91..a2670ef 100644
--- a/content/browser/dom_storage/dom_storage_message_filter.h
+++ b/content/browser/dom_storage/dom_storage_message_filter.h
@@ -78,6 +78,7 @@ class DOMStorageMessageFilter
virtual void OnDOMStorageAreaCleared(
const DOMStorageArea* area,
const GURL& page_url) OVERRIDE;
+ virtual void OnDOMSessionStorageReset(int64 namespace_id) OVERRIDE;
void SendDOMStorageEvent(
const DOMStorageArea* area,
diff --git a/content/browser/dom_storage/dom_storage_namespace.cc b/content/browser/dom_storage/dom_storage_namespace.cc
index 56cdb69..5672930 100644
--- a/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/content/browser/dom_storage/dom_storage_namespace.cc
@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
#include "content/browser/dom_storage/dom_storage_task_runner.h"
#include "content/browser/dom_storage/session_storage_database.h"
#include "content/common/child_process_host_impl.h"
@@ -31,7 +32,11 @@ DOMStorageNamespace::DOMStorageNamespace(
DOMStorageTaskRunner* task_runner)
: namespace_id_(kLocalStorageNamespaceId),
directory_(directory),
- task_runner_(task_runner) {
+ task_runner_(task_runner),
+ num_aliases_(0),
+ master_alias_count_decremented_(false),
+ ready_for_deletion_pending_aliases_(false),
+ must_persist_at_shutdown_(false) {
}
DOMStorageNamespace::DOMStorageNamespace(
@@ -42,15 +47,22 @@ DOMStorageNamespace::DOMStorageNamespace(
: namespace_id_(namespace_id),
persistent_namespace_id_(persistent_namespace_id),
task_runner_(task_runner),
- session_storage_database_(session_storage_database) {
+ session_storage_database_(session_storage_database),
+ num_aliases_(0),
+ master_alias_count_decremented_(false),
+ ready_for_deletion_pending_aliases_(false),
+ must_persist_at_shutdown_(false) {
DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
}
DOMStorageNamespace::~DOMStorageNamespace() {
STLDeleteValues(&transactions_);
+ DecrementMasterAliasCount();
}
DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
+ if (alias_master_namespace_)
+ return alias_master_namespace_->OpenStorageArea(origin);
if (AreaHolder* holder = GetAreaHolder(origin)) {
++(holder->open_count_);
return holder->area_.get();
@@ -69,6 +81,11 @@ DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
AreaHolder* holder = GetAreaHolder(area->origin());
+ if (alias_master_namespace_) {
+ DCHECK(!holder);
+ alias_master_namespace_->CloseStorageArea(area);
+ return;
+ }
DCHECK(holder);
DCHECK_EQ(holder->area_.get(), area);
--(holder->open_count_);
@@ -77,6 +94,8 @@ void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
}
DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
+ if (alias_master_namespace_)
+ return alias_master_namespace_->GetOpenStorageArea(origin);
AreaHolder* holder = GetAreaHolder(origin);
if (holder && holder->open_count_)
return holder->area_.get();
@@ -86,6 +105,10 @@ DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
DOMStorageNamespace* DOMStorageNamespace::Clone(
int64 clone_namespace_id,
const std::string& clone_persistent_namespace_id) {
+ if (alias_master_namespace_) {
+ return alias_master_namespace_->Clone(clone_namespace_id,
+ clone_persistent_namespace_id);
+ }
DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
DCHECK_NE(kLocalStorageNamespaceId, clone_namespace_id);
DOMStorageNamespace* clone = new DOMStorageNamespace(
@@ -110,8 +133,34 @@ DOMStorageNamespace* DOMStorageNamespace::Clone(
return clone;
}
+DOMStorageNamespace* DOMStorageNamespace::CreateAlias(
+ int64 alias_namespace_id) {
+ // Creates an alias of the current DOMStorageNamespace.
+ // The alias will have a reference to this namespace (called the master),
+ // and all operations will be redirected to the master (in particular,
+ // the alias will never open any areas of its own, but always redirect
+ // to the master). Accordingly, an alias will also never undergo the shutdown
+ // procedure which initiates persisting to disk, since there is never any data
+ // of its own to persist to disk. DOMStorageContextImpl is the place where
+ // shutdowns are initiated, but only for non-alias DOMStorageNamespaces.
+ DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
+ DCHECK_NE(kLocalStorageNamespaceId, alias_namespace_id);
+ DOMStorageNamespace* alias = new DOMStorageNamespace(
+ alias_namespace_id, persistent_namespace_id_,
+ session_storage_database_.get(), task_runner_.get());
+ if (alias_master_namespace_ != NULL) {
+ DCHECK(alias_master_namespace_->alias_master_namespace_ == NULL);
+ alias->alias_master_namespace_ = alias_master_namespace_;
+ } else {
+ alias->alias_master_namespace_ = this;
+ }
+ alias->alias_master_namespace_->num_aliases_++;
+ return alias;
+}
+
void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
DCHECK(!session_storage_database_.get());
+ DCHECK(!alias_master_namespace_.get());
AreaHolder* holder = GetAreaHolder(origin);
if (holder) {
holder->area_->DeleteOrigin();
@@ -125,12 +174,20 @@ void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
}
void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
+ if (alias_master_namespace_) {
+ alias_master_namespace_->DeleteSessionStorageOrigin(origin);
+ return;
+ }
DOMStorageArea* area = OpenStorageArea(origin);
area->FastClear();
CloseStorageArea(area);
}
void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
+ if (alias_master_namespace_) {
+ alias_master_namespace_->PurgeMemory(option);
+ return;
+ }
if (directory_.empty())
return; // We can't purge w/o backing on disk.
AreaMap::iterator it = areas_.begin();
@@ -166,6 +223,8 @@ void DOMStorageNamespace::Shutdown() {
}
unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
+ if (alias_master_namespace_)
+ return alias_master_namespace_->CountInMemoryAreas();
unsigned int area_count = 0;
for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
if (it->second.area_->IsLoadedInMemory())
@@ -196,16 +255,23 @@ void DOMStorageNamespace::RemoveTransactionLogProcessId(int process_id) {
transactions_.erase(process_id);
}
-SessionStorageNamespace::MergeResult DOMStorageNamespace::CanMerge(
+SessionStorageNamespace::MergeResult DOMStorageNamespace::Merge(
+ bool actually_merge,
int process_id,
- DOMStorageNamespace* other) {
+ DOMStorageNamespace* other,
+ DOMStorageContextImpl* context) {
+ if (!alias_master_namespace())
+ return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS;
if (transactions_.count(process_id) < 1)
return SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING;
TransactionData* data = transactions_[process_id];
if (data->max_log_size_exceeded)
return SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS;
- if (data->log.size() < 1)
+ if (data->log.size() < 1) {
+ if (actually_merge)
+ SwitchToNewAliasMaster(other, context);
return SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS;
+ }
// skip_areas and skip_keys store areas and (area, key) pairs, respectively,
// that have already been handled previously. Any further modifications to
@@ -242,6 +308,42 @@ SessionStorageNamespace::MergeResult DOMStorageNamespace::CanMerge(
}
NOTREACHED();
}
+ if (!actually_merge)
+ return SessionStorageNamespace::MERGE_RESULT_MERGEABLE;
+
+ // Actually perform the merge.
+
+ for (unsigned int i = 0; i < data->log.size(); i++) {
+ TransactionRecord& transaction = data->log[i];
+ if (transaction.transaction_type == TRANSACTION_READ)
+ continue;
+ DOMStorageArea* area = other->OpenStorageArea(transaction.origin);
+ if (transaction.transaction_type == TRANSACTION_CLEAR) {
+ area->Clear();
+ if (context)
+ context->NotifyAreaCleared(area, transaction.page_url);
+ }
+ if (transaction.transaction_type == TRANSACTION_REMOVE) {
+ base::string16 old_value;
+ area->RemoveItem(transaction.key, &old_value);
+ if (context) {
+ context->NotifyItemRemoved(area, transaction.key, old_value,
+ transaction.page_url);
+ }
+ }
+ if (transaction.transaction_type == TRANSACTION_WRITE) {
+ base::NullableString16 old_value;
+ area->SetItem(transaction.key, base::string16(transaction.value.string()),
+ &old_value);
+ if (context) {
+ context->NotifyItemSet(area, transaction.key,transaction.value.string(),
+ old_value, transaction.page_url);
+ }
+ }
+ other->CloseStorageArea(area);
+ }
+
+ SwitchToNewAliasMaster(other, context);
return SessionStorageNamespace::MERGE_RESULT_MERGEABLE;
}
@@ -267,6 +369,41 @@ void DOMStorageNamespace::AddTransaction(
}
}
+bool DOMStorageNamespace::DecrementMasterAliasCount() {
+ if (!alias_master_namespace_ || master_alias_count_decremented_)
+ return false;
+ DCHECK_GT(alias_master_namespace_->num_aliases_, 0);
+ alias_master_namespace_->num_aliases_--;
+ master_alias_count_decremented_ = true;
+ return (alias_master_namespace_->num_aliases_ == 0);
+}
+
+void DOMStorageNamespace::SwitchToNewAliasMaster(
+ DOMStorageNamespace* new_master,
+ DOMStorageContextImpl* context) {
+ DCHECK(alias_master_namespace());
+ scoped_refptr<DOMStorageNamespace> old_master = alias_master_namespace();
+ if (new_master->alias_master_namespace())
+ new_master = new_master->alias_master_namespace();
+ DCHECK(!new_master->alias_master_namespace());
+ DCHECK(old_master != this);
+ DCHECK(old_master != new_master);
+ DecrementMasterAliasCount();
+ alias_master_namespace_ = new_master;
+ alias_master_namespace_->num_aliases_++;
+ master_alias_count_decremented_ = false;
+ // There are three things that we need to clean up:
+ // -- the old master may ready for shutdown, if its last alias has disappeared
+ // -- The dom_storage hosts need to close and reopen their areas, so that
+ // they point to the correct new areas.
+ // -- The renderers will need to reset their local caches.
+ // All three of these things are accomplished with the following call below.
+ // |context| will be NULL in unit tests, which is when this will
+ // not apply, of course.
+ if (context)
+ context->NotifyAliasSessionMerged(namespace_id(), old_master.get());
+}
+
DOMStorageNamespace::TransactionData::TransactionData()
: max_log_size_exceeded(false) {
}
diff --git a/content/browser/dom_storage/dom_storage_namespace.h b/content/browser/dom_storage/dom_storage_namespace.h
index 11a47bf..929669c 100644
--- a/content/browser/dom_storage/dom_storage_namespace.h
+++ b/content/browser/dom_storage/dom_storage_namespace.h
@@ -19,6 +19,7 @@
namespace content {
class DOMStorageArea;
+class DOMStorageContextImpl;
class DOMStorageTaskRunner;
class SessionStorageDatabase;
@@ -69,6 +70,10 @@ class CONTENT_EXPORT DOMStorageNamespace
DOMStorageNamespace* Clone(int64 clone_namespace_id,
const std::string& clone_persistent_namespace_id);
+ // Creates an alias of |this| namespace.
+ // Should only be called for session storage namespaces.
+ DOMStorageNamespace* CreateAlias(int64 alias_namespace_id);
+
void DeleteLocalStorageOrigin(const GURL& origin);
void DeleteSessionStorageOrigin(const GURL& origin);
void PurgeMemory(PurgeOption purge);
@@ -78,8 +83,24 @@ class CONTENT_EXPORT DOMStorageNamespace
void AddTransactionLogProcessId(int process_id);
void RemoveTransactionLogProcessId(int process_id);
- SessionStorageNamespace::MergeResult CanMerge(int process_id,
- DOMStorageNamespace* other);
+ SessionStorageNamespace::MergeResult Merge(
+ bool actually_merge,
+ int process_id,
+ DOMStorageNamespace* other,
+ DOMStorageContextImpl* context);
+ DOMStorageNamespace* alias_master_namespace() {
+ return alias_master_namespace_.get();
+ }
+ int num_aliases() const { return num_aliases_; }
+ bool ready_for_deletion_pending_aliases() const {
+ return ready_for_deletion_pending_aliases_; }
+ void set_ready_for_deletion_pending_aliases(bool value) {
+ ready_for_deletion_pending_aliases_ = value;
+ }
+ bool must_persist_at_shutdown() const { return must_persist_at_shutdown_; }
+ void set_must_persist_at_shutdown(bool value) {
+ must_persist_at_shutdown_ = value;
+ }
enum LogType {
TRANSACTION_READ,
@@ -88,9 +109,10 @@ class CONTENT_EXPORT DOMStorageNamespace
TRANSACTION_CLEAR
};
- struct TransactionRecord {
+ struct CONTENT_EXPORT TransactionRecord {
LogType transaction_type;
GURL origin;
+ GURL page_url;
base::string16 key;
base::NullableString16 value;
TransactionRecord();
@@ -99,6 +121,9 @@ class CONTENT_EXPORT DOMStorageNamespace
void AddTransaction(int process_id, const TransactionRecord& transaction);
bool IsLoggingRenderer(int process_id);
+ // Decrements the count of aliases owned by the master, and returns true
+ // if the new count is 0.
+ bool DecrementMasterAliasCount();
private:
friend class base::RefCountedThreadSafe<DOMStorageNamespace>;
@@ -126,6 +151,10 @@ class CONTENT_EXPORT DOMStorageNamespace
// Returns a pointer to the area holder in our map or NULL.
AreaHolder* GetAreaHolder(const GURL& origin);
+ // Switches the current alias DOM storage namespace to a new alias master.
+ void SwitchToNewAliasMaster(DOMStorageNamespace* new_master,
+ DOMStorageContextImpl* context);
+
int64 namespace_id_;
std::string persistent_namespace_id_;
base::FilePath directory_;
@@ -133,6 +162,19 @@ class CONTENT_EXPORT DOMStorageNamespace
scoped_refptr<DOMStorageTaskRunner> task_runner_;
scoped_refptr<SessionStorageDatabase> session_storage_database_;
std::map<int, TransactionData*> transactions_;
+ int num_aliases_;
+ scoped_refptr<DOMStorageNamespace> alias_master_namespace_;
+ // Indicates whether we have already decremented |num_aliases_| for this
+ // namespace in its alias master. We may only decrement it once, and around
+ // deletion, this instance will stick around a bit longer until its refcount
+ // drops to 0. Therefore, we want to make sure we don't decrement the master's
+ // alias count a second time.
+ bool master_alias_count_decremented_;
+ // This indicates, for an alias master, that the master itself is ready
+ // for deletion, but there are aliases outstanding that we have to wait for
+ // before we can start cleaning up the master.
+ bool ready_for_deletion_pending_aliases_;
+ bool must_persist_at_shutdown_;
};
} // namespace content
diff --git a/content/browser/dom_storage/dom_storage_session.cc b/content/browser/dom_storage/dom_storage_session.cc
index 398aade..c3b7a9e 100644
--- a/content/browser/dom_storage/dom_storage_session.cc
+++ b/content/browser/dom_storage/dom_storage_session.cc
@@ -17,19 +17,19 @@ namespace content {
namespace {
-void PostCanMergeTaskResult(
+void PostMergeTaskResult(
const SessionStorageNamespace::MergeResultCallback& callback,
SessionStorageNamespace::MergeResult result) {
callback.Run(result);
}
-void RunCanMergeTaskAndPostResult(
+void RunMergeTaskAndPostResult(
const base::Callback<SessionStorageNamespace::MergeResult(void)>& task,
scoped_refptr<base::SingleThreadTaskRunner> result_loop,
const SessionStorageNamespace::MergeResultCallback& callback) {
SessionStorageNamespace::MergeResult result = task.Run();
result_loop->PostTask(
- FROM_HERE, base::Bind(&PostCanMergeTaskResult, callback, result));
+ FROM_HERE, base::Bind(&PostMergeTaskResult, callback, result));
}
} // namespace
@@ -57,6 +57,22 @@ DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context,
context_, namespace_id_, persistent_namespace_id_));
}
+DOMStorageSession::DOMStorageSession(
+ DOMStorageSession* master_dom_storage_session)
+ : context_(master_dom_storage_session->context_),
+ namespace_id_(master_dom_storage_session->context_->AllocateSessionId()),
+ persistent_namespace_id_(
+ master_dom_storage_session->persistent_namespace_id()),
+ should_persist_(false) {
+ context_->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&DOMStorageContextImpl::CreateAliasSessionNamespace,
+ context_,
+ master_dom_storage_session->namespace_id(),
+ namespace_id_,
+ persistent_namespace_id_));
+}
+
void DOMStorageSession::SetShouldPersist(bool should_persist) {
should_persist_ = should_persist;
}
@@ -116,20 +132,40 @@ void DOMStorageSession::RemoveTransactionLogProcessId(int process_id) {
context_, namespace_id_, process_id));
}
-void DOMStorageSession::CanMerge(
+void DOMStorageSession::Merge(
+ bool actually_merge,
int process_id,
DOMStorageSession* other,
const SessionStorageNamespace::MergeResultCallback& callback) {
scoped_refptr<base::SingleThreadTaskRunner> current_loop(
base::ThreadTaskRunnerHandle::Get());
+ SessionStorageNamespace::MergeResultCallback cb =
+ base::Bind(&DOMStorageSession::ProcessMergeResult,
+ this,
+ actually_merge,
+ callback,
+ other->persistent_namespace_id());
context_->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&RunCanMergeTaskAndPostResult,
- base::Bind(&DOMStorageContextImpl::CanMergeSessionStorage,
- context_, namespace_id_, process_id,
+ base::Bind(&RunMergeTaskAndPostResult,
+ base::Bind(&DOMStorageContextImpl::MergeSessionStorage,
+ context_, namespace_id_, actually_merge, process_id,
other->namespace_id_),
current_loop,
- callback));
+ cb));
+}
+
+void DOMStorageSession::ProcessMergeResult(
+ bool actually_merge,
+ const SessionStorageNamespace::MergeResultCallback& callback,
+ const std::string& new_persistent_namespace_id,
+ SessionStorageNamespace::MergeResult result) {
+ if (actually_merge &&
+ (result == SessionStorageNamespace::MERGE_RESULT_MERGEABLE ||
+ result == SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS)) {
+ persistent_namespace_id_ = new_persistent_namespace_id;
+ }
+ callback.Run(result);
}
} // namespace content
diff --git a/content/browser/dom_storage/dom_storage_session.h b/content/browser/dom_storage/dom_storage_session.h
index 5cc180a..5e12621 100644
--- a/content/browser/dom_storage/dom_storage_session.h
+++ b/content/browser/dom_storage/dom_storage_session.h
@@ -31,6 +31,10 @@ class CONTENT_EXPORT DOMStorageSession
DOMStorageSession(DOMStorageContextImpl* context,
const std::string& persistent_namespace_id);
+ // Constructs a |DOMStorageSession| as an alias of
+ // |master_dom_storage_session|. Allocates a new non-persistent ID.
+ explicit DOMStorageSession(DOMStorageSession* master_dom_storage_session);
+
int64 namespace_id() const { return namespace_id_; }
const std::string& persistent_namespace_id() const {
return persistent_namespace_id_;
@@ -47,9 +51,10 @@ class CONTENT_EXPORT DOMStorageSession
void AddTransactionLogProcessId(int process_id);
void RemoveTransactionLogProcessId(int process_id);
- void CanMerge(int process_id,
- DOMStorageSession* other,
- const SessionStorageNamespace::MergeResultCallback& callback);
+ void Merge(bool actually_merge,
+ int process_id,
+ DOMStorageSession* other,
+ const SessionStorageNamespace::MergeResultCallback& callback);
private:
friend class base::RefCountedThreadSafe<DOMStorageSession>;
@@ -59,6 +64,12 @@ class CONTENT_EXPORT DOMStorageSession
const std::string& persistent_namespace_id);
~DOMStorageSession();
+ void ProcessMergeResult(
+ bool actually_merge,
+ const SessionStorageNamespace::MergeResultCallback& callback,
+ const std::string& new_persistent_namespace_id,
+ SessionStorageNamespace::MergeResult result);
+
scoped_refptr<DOMStorageContextImpl> context_;
int64 namespace_id_;
std::string persistent_namespace_id_;
diff --git a/content/browser/dom_storage/session_storage_namespace_impl.cc b/content/browser/dom_storage/session_storage_namespace_impl.cc
index ea04c63..e01472a 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl.cc
@@ -25,6 +25,13 @@ SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
: session_(new DOMStorageSession(context->context(), persistent_id)) {
}
+SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
+ SessionStorageNamespaceImpl* master_session_storage_namespace)
+ : session_(new DOMStorageSession(
+ master_session_storage_namespace->session_)) {
+}
+
+
int64 SessionStorageNamespaceImpl::id() const {
return session_->namespace_id();
}
@@ -67,13 +74,18 @@ void SessionStorageNamespaceImpl::RemoveTransactionLogProcessId(
session_->RemoveTransactionLogProcessId(process_id);
}
-void SessionStorageNamespaceImpl::CanMerge(
+void SessionStorageNamespaceImpl::Merge(
+ bool actually_merge,
int process_id,
SessionStorageNamespace* other,
const MergeResultCallback& callback) {
SessionStorageNamespaceImpl* other_impl =
static_cast<SessionStorageNamespaceImpl*>(other);
- session_->CanMerge(process_id, other_impl->session_, callback);
+ session_->Merge(actually_merge, process_id, other_impl->session_, callback);
+}
+
+bool SessionStorageNamespaceImpl::IsAliasOf(SessionStorageNamespace* other) {
+ return persistent_id() == other->persistent_id();
}
} // namespace content
diff --git a/content/browser/dom_storage/session_storage_namespace_impl.h b/content/browser/dom_storage/session_storage_namespace_impl.h
index dbc98c2..ff6bd36 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl.h
+++ b/content/browser/dom_storage/session_storage_namespace_impl.h
@@ -34,6 +34,11 @@ class SessionStorageNamespaceImpl
SessionStorageNamespaceImpl(DOMStorageContextWrapper* context,
const std::string& persistent_id);
+ // Creates an alias of |master_session_storage_namespace|. This will allocate
+ // a new non-persistent ID.
+ explicit SessionStorageNamespaceImpl(
+ SessionStorageNamespaceImpl* master_session_storage_namespace);
+
// SessionStorageNamespace implementation.
virtual int64 id() const OVERRIDE;
virtual const std::string& persistent_id() const OVERRIDE;
@@ -45,9 +50,11 @@ class SessionStorageNamespaceImpl
virtual void AddTransactionLogProcessId(int process_id) OVERRIDE;
virtual void RemoveTransactionLogProcessId(int process_id) OVERRIDE;
- virtual void CanMerge(int process_id,
- SessionStorageNamespace* other,
- const MergeResultCallback& callback) OVERRIDE;
+ virtual void Merge(bool actually_merge,
+ int process_id,
+ SessionStorageNamespace* other,
+ const MergeResultCallback& callback) OVERRIDE;
+ virtual bool IsAliasOf(SessionStorageNamespace* other) OVERRIDE;
private:
explicit SessionStorageNamespaceImpl(DOMStorageSession* clone);