diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/content/browser/dom_storage/dom_storage_namespace.cc | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (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.cc | 261 |
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() |