summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/dom_storage/dom_storage_namespace.cc
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2014-03-18 13:16:26 +0100
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-03-20 15:55:39 +0100
commit3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch)
tree92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/content/browser/dom_storage/dom_storage_namespace.cc
parente90d7c4b152c56919d963987e2503f9909a666d2 (diff)
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies needed on Windows. Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42 Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu> Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/content/browser/dom_storage/dom_storage_namespace.cc')
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.cc261
1 files changed, 259 insertions, 2 deletions
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.cc b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
index 75bfdaacb71..ac1e2f89cd0 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
@@ -4,23 +4,40 @@
#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include <set>
+#include <utility>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#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"
#include "content/common/dom_storage/dom_storage_types.h"
namespace content {
+namespace {
+
+static const unsigned int kMaxTransactionLogEntries = 8 * 1024;
+
+} // namespace
+
DOMStorageNamespace::DOMStorageNamespace(
const base::FilePath& directory,
DOMStorageTaskRunner* task_runner)
: namespace_id_(kLocalStorageNamespaceId),
directory_(directory),
- task_runner_(task_runner) {
+ task_runner_(task_runner),
+ num_aliases_(0),
+ old_master_for_close_area_(NULL),
+ master_alias_count_decremented_(false),
+ ready_for_deletion_pending_aliases_(false),
+ must_persist_at_shutdown_(false) {
}
DOMStorageNamespace::DOMStorageNamespace(
@@ -31,14 +48,23 @@ 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),
+ old_master_for_close_area_(NULL),
+ 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();
@@ -57,6 +83,14 @@ DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
AreaHolder* holder = GetAreaHolder(area->origin());
+ if (alias_master_namespace_) {
+ DCHECK(!holder);
+ if (old_master_for_close_area_)
+ old_master_for_close_area_->CloseStorageArea(area);
+ else
+ alias_master_namespace_->CloseStorageArea(area);
+ return;
+ }
DCHECK(holder);
DCHECK_EQ(holder->area_.get(), area);
--(holder->open_count_);
@@ -65,6 +99,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();
@@ -74,6 +110,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(
@@ -98,8 +138,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();
@@ -113,12 +179,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();
@@ -154,6 +228,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())
@@ -170,6 +246,187 @@ DOMStorageNamespace::GetAreaHolder(const GURL& origin) {
return &(found->second);
}
+void DOMStorageNamespace::AddTransactionLogProcessId(int process_id) {
+ DCHECK(process_id != ChildProcessHostImpl::kInvalidChildProcessId);
+ DCHECK(transactions_.count(process_id) == 0);
+ TransactionData* transaction_data = new TransactionData;
+ transactions_[process_id] = transaction_data;
+}
+
+void DOMStorageNamespace::RemoveTransactionLogProcessId(int process_id) {
+ DCHECK(process_id != ChildProcessHostImpl::kInvalidChildProcessId);
+ DCHECK(transactions_.count(process_id) == 1);
+ delete transactions_[process_id];
+ transactions_.erase(process_id);
+}
+
+SessionStorageNamespace::MergeResult DOMStorageNamespace::Merge(
+ bool actually_merge,
+ int process_id,
+ 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 (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
+ // them will not change the result of the hypothetical merge.
+ std::set<GURL> skip_areas;
+ typedef std::pair<GURL, base::string16> OriginKey;
+ std::set<OriginKey> skip_keys;
+ // Indicates whether we could still merge the namespaces preserving all
+ // individual transactions.
+ for (unsigned int i = 0; i < data->log.size(); i++) {
+ TransactionRecord& transaction = data->log[i];
+ if (transaction.transaction_type == TRANSACTION_CLEAR) {
+ skip_areas.insert(transaction.origin);
+ continue;
+ }
+ if (skip_areas.find(transaction.origin) != skip_areas.end())
+ continue;
+ if (skip_keys.find(OriginKey(transaction.origin, transaction.key))
+ != skip_keys.end()) {
+ continue;
+ }
+ if (transaction.transaction_type == TRANSACTION_REMOVE ||
+ transaction.transaction_type == TRANSACTION_WRITE) {
+ skip_keys.insert(OriginKey(transaction.origin, transaction.key));
+ continue;
+ }
+ if (transaction.transaction_type == TRANSACTION_READ) {
+ DOMStorageArea* area = other->OpenStorageArea(transaction.origin);
+ base::NullableString16 other_value = area->GetItem(transaction.key);
+ other->CloseStorageArea(area);
+ if (transaction.value != other_value)
+ return SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE;
+ continue;
+ }
+ 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;
+}
+
+bool DOMStorageNamespace::IsLoggingRenderer(int process_id) {
+ DCHECK(process_id != ChildProcessHostImpl::kInvalidChildProcessId);
+ if (transactions_.count(process_id) < 1)
+ return false;
+ return !transactions_[process_id]->max_log_size_exceeded;
+}
+
+void DOMStorageNamespace::AddTransaction(
+ int process_id, const TransactionRecord& transaction) {
+ if (!IsLoggingRenderer(process_id))
+ return;
+ TransactionData* transaction_data = transactions_[process_id];
+ DCHECK(transaction_data);
+ if (transaction_data->max_log_size_exceeded)
+ return;
+ transaction_data->log.push_back(transaction);
+ if (transaction_data->log.size() > kMaxTransactionLogEntries) {
+ transaction_data->max_log_size_exceeded = true;
+ transaction_data->log.clear();
+ }
+}
+
+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.
+ // During this call, open areas will be closed & reopened, so that they now
+ // come from the correct new master. Therefore, we must send close operations
+ // to the old master.
+ old_master_for_close_area_ = old_master.get();
+ if (context)
+ context->NotifyAliasSessionMerged(namespace_id(), old_master.get());
+ old_master_for_close_area_ = NULL;
+}
+
+DOMStorageNamespace::TransactionData::TransactionData()
+ : max_log_size_exceeded(false) {
+}
+
+DOMStorageNamespace::TransactionData::~TransactionData() {
+}
+
+DOMStorageNamespace::TransactionRecord::TransactionRecord() {
+}
+
+DOMStorageNamespace::TransactionRecord::~TransactionRecord() {
+}
+
// AreaHolder
DOMStorageNamespace::AreaHolder::AreaHolder()