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

Unified Diff: content/browser/dom_storage/dom_storage_context_impl.cc

Issue 22297005: Move webkit/{browser,common}/dom_storage into content/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 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: content/browser/dom_storage/dom_storage_context_impl.cc
diff --git a/content/browser/dom_storage/dom_storage_context_impl.cc b/content/browser/dom_storage/dom_storage_context_impl.cc
index f790ecd8001a750bec29f8337cd165f311fd8745..dd1f33e847fb13702496061685d6f85b7863ad3c 100644
--- a/content/browser/dom_storage/dom_storage_context_impl.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl.cc
@@ -6,171 +6,417 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "content/browser/dom_storage/session_storage_namespace_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-
-using dom_storage::DomStorageArea;
-using dom_storage::DomStorageContext;
-using dom_storage::DomStorageTaskRunner;
-using dom_storage::DomStorageWorkerPoolTaskRunner;
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/guid.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/session_storage_database.h"
+#include "content/common/dom_storage/dom_storage_types.h"
+#include "content/public/browser/dom_storage_context.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_usage_info.h"
+#include "webkit/browser/quota/special_storage_policy.h"
namespace content {
-namespace {
-const char kLocalStorageDirectory[] = "Local Storage";
-const char kSessionStorageDirectory[] = "Session Storage";
+static const int kSessionStoraceScavengingSeconds = 60;
-void InvokeLocalStorageUsageCallbackHelper(
- const DOMStorageContext::GetLocalStorageUsageCallback& callback,
- const std::vector<dom_storage::LocalStorageUsageInfo>* infos) {
- callback.Run(*infos);
+DOMStorageContextImpl::DOMStorageContextImpl(
+ const base::FilePath& localstorage_directory,
+ const base::FilePath& sessionstorage_directory,
+ quota::SpecialStoragePolicy* special_storage_policy,
+ DOMStorageTaskRunner* task_runner)
+ : localstorage_directory_(localstorage_directory),
+ sessionstorage_directory_(sessionstorage_directory),
+ task_runner_(task_runner),
+ is_shutdown_(false),
+ force_keep_session_state_(false),
+ special_storage_policy_(special_storage_policy),
+ scavenging_started_(false) {
+ // AtomicSequenceNum starts at 0 but we want to start session
+ // namespace ids at one since zero is reserved for the
+ // kLocalStorageNamespaceId.
+ session_id_sequence_.GetNext();
}
-void GetLocalStorageUsageHelper(
- base::MessageLoopProxy* reply_loop,
- DomStorageContext* context,
- const DOMStorageContext::GetLocalStorageUsageCallback& callback) {
- std::vector<dom_storage::LocalStorageUsageInfo>* infos =
- new std::vector<dom_storage::LocalStorageUsageInfo>;
- context->GetLocalStorageUsage(infos, true);
- reply_loop->PostTask(
- FROM_HERE,
- base::Bind(&InvokeLocalStorageUsageCallbackHelper,
- callback, base::Owned(infos)));
+DOMStorageContextImpl::~DOMStorageContextImpl() {
+ if (session_storage_database_.get()) {
+ // SessionStorageDatabase shouldn't be deleted right away: deleting it will
+ // potentially involve waiting in leveldb::DBImpl::~DBImpl, and waiting
+ // shouldn't happen on this thread.
+ SessionStorageDatabase* to_release = session_storage_database_.get();
+ to_release->AddRef();
+ session_storage_database_ = NULL;
+ task_runner_->PostShutdownBlockingTask(
+ FROM_HERE,
+ DOMStorageTaskRunner::COMMIT_SEQUENCE,
+ base::Bind(&SessionStorageDatabase::Release,
+ base::Unretained(to_release)));
+ }
}
-void InvokeSessionStorageUsageCallbackHelper(
- const DOMStorageContext::GetSessionStorageUsageCallback& callback,
- const std::vector<dom_storage::SessionStorageUsageInfo>* infos) {
- callback.Run(*infos);
+DOMStorageNamespace* DOMStorageContextImpl::GetStorageNamespace(
+ int64 namespace_id) {
+ if (is_shutdown_)
+ return NULL;
+ StorageNamespaceMap::iterator found = namespaces_.find(namespace_id);
+ if (found == namespaces_.end()) {
+ if (namespace_id == kLocalStorageNamespaceId) {
+ if (!localstorage_directory_.empty()) {
+ if (!file_util::CreateDirectory(localstorage_directory_)) {
+ LOG(ERROR) << "Failed to create 'Local Storage' directory,"
+ " falling back to in-memory only.";
+ localstorage_directory_ = base::FilePath();
+ }
+ }
+ DOMStorageNamespace* local =
+ new DOMStorageNamespace(localstorage_directory_, task_runner_.get());
+ namespaces_[kLocalStorageNamespaceId] = local;
+ return local;
+ }
+ return NULL;
+ }
+ return found->second.get();
}
-void GetSessionStorageUsageHelper(
- base::MessageLoopProxy* reply_loop,
- DomStorageContext* context,
- const DOMStorageContext::GetSessionStorageUsageCallback& callback) {
- std::vector<dom_storage::SessionStorageUsageInfo>* infos =
- new std::vector<dom_storage::SessionStorageUsageInfo>;
- context->GetSessionStorageUsage(infos);
- reply_loop->PostTask(
- FROM_HERE,
- base::Bind(&InvokeSessionStorageUsageCallbackHelper,
- callback, base::Owned(infos)));
+void DOMStorageContextImpl::GetLocalStorageUsage(
+ std::vector<LocalStorageUsageInfo>* infos,
+ bool include_file_info) {
+ if (localstorage_directory_.empty())
+ return;
+ base::FileEnumerator enumerator(localstorage_directory_, false,
+ base::FileEnumerator::FILES);
+ for (base::FilePath path = enumerator.Next(); !path.empty();
+ path = enumerator.Next()) {
+ if (path.MatchesExtension(DOMStorageArea::kDatabaseFileExtension)) {
+ LocalStorageUsageInfo info;
+ info.origin = DOMStorageArea::OriginFromDatabaseFileName(path);
+ if (include_file_info) {
+ base::FileEnumerator::FileInfo find_info = enumerator.GetInfo();
+ info.data_size = find_info.GetSize();
+ info.last_modified = find_info.GetLastModifiedTime();
+ }
+ infos->push_back(info);
+ }
+ }
}
-} // namespace
+void DOMStorageContextImpl::GetSessionStorageUsage(
+ std::vector<SessionStorageUsageInfo>* infos) {
+ if (!session_storage_database_.get())
+ return;
+ std::map<std::string, std::vector<GURL> > namespaces_and_origins;
+ session_storage_database_->ReadNamespacesAndOrigins(
+ &namespaces_and_origins);
+ for (std::map<std::string, std::vector<GURL> >::const_iterator it =
+ namespaces_and_origins.begin();
+ it != namespaces_and_origins.end(); ++it) {
+ for (std::vector<GURL>::const_iterator origin_it = it->second.begin();
+ origin_it != it->second.end(); ++origin_it) {
+ SessionStorageUsageInfo info;
+ info.persistent_namespace_id = it->first;
+ info.origin = *origin_it;
+ infos->push_back(info);
+ }
+ }
+}
-DOMStorageContextImpl::DOMStorageContextImpl(
- const base::FilePath& data_path,
- quota::SpecialStoragePolicy* special_storage_policy) {
- base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
- context_ = new dom_storage::DomStorageContext(
- data_path.empty() ? data_path
- : data_path.AppendASCII(kLocalStorageDirectory),
- data_path.empty() ? data_path
- : data_path.AppendASCII(kSessionStorageDirectory),
- special_storage_policy,
- new DomStorageWorkerPoolTaskRunner(
- worker_pool,
- worker_pool->GetNamedSequenceToken("dom_storage_primary"),
- worker_pool->GetNamedSequenceToken("dom_storage_commit"),
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)
- .get()));
+void DOMStorageContextImpl::DeleteLocalStorage(const GURL& origin) {
+ DCHECK(!is_shutdown_);
+ DOMStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
+ local->DeleteLocalStorageOrigin(origin);
+ // Synthesize a 'cleared' event if the area is open so CachedAreas in
+ // renderers get emptied out too.
+ DOMStorageArea* area = local->GetOpenStorageArea(origin);
+ if (area)
+ NotifyAreaCleared(area, origin);
}
-DOMStorageContextImpl::~DOMStorageContextImpl() {
+void DOMStorageContextImpl::DeleteSessionStorage(
+ const SessionStorageUsageInfo& usage_info) {
+ DCHECK(!is_shutdown_);
+ DOMStorageNamespace* dom_storage_namespace = NULL;
+ std::map<std::string, int64>::const_iterator it =
+ persistent_namespace_id_to_namespace_id_.find(
+ usage_info.persistent_namespace_id);
+ if (it != persistent_namespace_id_to_namespace_id_.end()) {
+ dom_storage_namespace = GetStorageNamespace(it->second);
+ } else {
+ int64 namespace_id = AllocateSessionId();
+ CreateSessionNamespace(namespace_id, usage_info.persistent_namespace_id);
+ dom_storage_namespace = GetStorageNamespace(namespace_id);
+ }
+ dom_storage_namespace->DeleteSessionStorageOrigin(usage_info.origin);
+ // Synthesize a 'cleared' event if the area is open so CachedAreas in
+ // renderers get emptied out too.
+ DOMStorageArea* area =
+ dom_storage_namespace->GetOpenStorageArea(usage_info.origin);
+ if (area)
+ NotifyAreaCleared(area, usage_info.origin);
}
-void DOMStorageContextImpl::GetLocalStorageUsage(
- const GetLocalStorageUsageCallback& callback) {
- DCHECK(context_.get());
- context_->task_runner()
- ->PostShutdownBlockingTask(FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&GetLocalStorageUsageHelper,
- base::MessageLoopProxy::current(),
- context_,
- callback));
+void DOMStorageContextImpl::PurgeMemory() {
+ // We can only purge memory from the local storage namespace
+ // which is backed by disk.
+ // TODO(marja): Purge sessionStorage, too. (Requires changes to the FastClear
+ // functionality.)
+ StorageNamespaceMap::iterator found =
+ namespaces_.find(kLocalStorageNamespaceId);
+ if (found != namespaces_.end())
+ found->second->PurgeMemory(DOMStorageNamespace::PURGE_AGGRESSIVE);
}
-void DOMStorageContextImpl::GetSessionStorageUsage(
- const GetSessionStorageUsageCallback& callback) {
- DCHECK(context_.get());
- context_->task_runner()
- ->PostShutdownBlockingTask(FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&GetSessionStorageUsageHelper,
- base::MessageLoopProxy::current(),
- context_,
- callback));
+void DOMStorageContextImpl::Shutdown() {
+ is_shutdown_ = true;
+ StorageNamespaceMap::const_iterator it = namespaces_.begin();
+ for (; it != namespaces_.end(); ++it)
+ it->second->Shutdown();
+
+ if (localstorage_directory_.empty() && !session_storage_database_.get())
+ return;
+
+ // Respect the content policy settings about what to
+ // keep and what to discard.
+ if (force_keep_session_state_)
+ return; // Keep everything.
+
+ bool has_session_only_origins =
+ special_storage_policy_.get() &&
+ special_storage_policy_->HasSessionOnlyOrigins();
+
+ if (has_session_only_origins) {
+ // We may have to delete something. We continue on the
+ // commit sequence after area shutdown tasks have cycled
+ // thru that sequence (and closed their database files).
+ bool success = task_runner_->PostShutdownBlockingTask(
+ FROM_HERE,
+ DOMStorageTaskRunner::COMMIT_SEQUENCE,
+ base::Bind(&DOMStorageContextImpl::ClearSessionOnlyOrigins, this));
+ DCHECK(success);
+ }
}
-void DOMStorageContextImpl::DeleteLocalStorage(const GURL& origin) {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&DomStorageContext::DeleteLocalStorage, context_, origin));
+void DOMStorageContextImpl::AddEventObserver(EventObserver* observer) {
+ event_observers_.AddObserver(observer);
}
-void DOMStorageContextImpl::DeleteSessionStorage(
- const dom_storage::SessionStorageUsageInfo& usage_info) {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(
- &DomStorageContext::DeleteSessionStorage, context_, usage_info));
+void DOMStorageContextImpl::RemoveEventObserver(EventObserver* observer) {
+ event_observers_.RemoveObserver(observer);
}
-void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() {
- DCHECK(context_.get());
- context_->SetSaveSessionStorageOnDisk();
+void DOMStorageContextImpl::NotifyItemSet(
+ const DOMStorageArea* area,
+ const base::string16& key,
+ const base::string16& new_value,
+ const base::NullableString16& old_value,
+ const GURL& page_url) {
+ FOR_EACH_OBSERVER(
+ EventObserver, event_observers_,
+ OnDOMStorageItemSet(area, key, new_value, old_value, page_url));
}
-scoped_refptr<SessionStorageNamespace>
-DOMStorageContextImpl::RecreateSessionStorage(
- const std::string& persistent_id) {
- return scoped_refptr<SessionStorageNamespace>(
- new SessionStorageNamespaceImpl(this, persistent_id));
+void DOMStorageContextImpl::NotifyItemRemoved(
+ const DOMStorageArea* area,
+ const base::string16& key,
+ const base::string16& old_value,
+ const GURL& page_url) {
+ FOR_EACH_OBSERVER(
+ EventObserver, event_observers_,
+ OnDOMStorageItemRemoved(area, key, old_value, page_url));
+}
+
+void DOMStorageContextImpl::NotifyAreaCleared(
+ const DOMStorageArea* area,
+ const GURL& page_url) {
+ FOR_EACH_OBSERVER(
+ EventObserver, event_observers_,
+ OnDOMStorageAreaCleared(area, page_url));
+}
+
+std::string DOMStorageContextImpl::AllocatePersistentSessionId() {
+ std::string guid = base::GenerateGUID();
+ std::replace(guid.begin(), guid.end(), '-', '_');
+ return guid;
+}
+
+void DOMStorageContextImpl::CreateSessionNamespace(
+ int64 namespace_id,
+ const std::string& persistent_namespace_id) {
+ if (is_shutdown_)
+ return;
+ DCHECK(namespace_id != kLocalStorageNamespaceId);
+ DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
+ namespaces_[namespace_id] = new DOMStorageNamespace(
+ namespace_id, persistent_namespace_id, session_storage_database_.get(),
+ task_runner_.get());
+ persistent_namespace_id_to_namespace_id_[persistent_namespace_id] =
+ namespace_id;
+}
+
+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())
+ return;
+ std::string persistent_namespace_id = it->second->persistent_namespace_id();
+ if (session_storage_database_.get()) {
+ if (!should_persist_data) {
+ task_runner_->PostShutdownBlockingTask(
+ FROM_HERE,
+ DOMStorageTaskRunner::COMMIT_SEQUENCE,
+ base::Bind(
+ base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
+ session_storage_database_,
+ persistent_namespace_id));
+ } else {
+ // Ensure that the data gets committed before we shut down.
+ it->second->Shutdown();
+ if (!scavenging_started_) {
+ // Protect the persistent namespace ID from scavenging.
+ protected_persistent_session_ids_.insert(persistent_namespace_id);
+ }
+ }
+ }
+ persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
+ namespaces_.erase(namespace_id);
+}
+
+void DOMStorageContextImpl::CloneSessionNamespace(
+ int64 existing_id, int64 new_id,
+ const std::string& new_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->Clone(new_id, new_persistent_id);
+ else
+ CreateSessionNamespace(new_id, new_persistent_id);
+}
+
+void DOMStorageContextImpl::ClearSessionOnlyOrigins() {
+ if (!localstorage_directory_.empty()) {
+ std::vector<LocalStorageUsageInfo> infos;
+ const bool kDontIncludeFileInfo = false;
+ GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
+ for (size_t i = 0; i < infos.size(); ++i) {
+ const GURL& origin = infos[i].origin;
+ if (special_storage_policy_->IsStorageProtected(origin))
+ continue;
+ if (!special_storage_policy_->IsStorageSessionOnly(origin))
+ continue;
+
+ base::FilePath database_file_path = localstorage_directory_.Append(
+ DOMStorageArea::DatabaseFileNameFromOrigin(origin));
+ sql::Connection::Delete(database_file_path);
+ }
+ }
+ if (session_storage_database_.get()) {
+ std::vector<SessionStorageUsageInfo> infos;
+ GetSessionStorageUsage(&infos);
+ for (size_t i = 0; i < infos.size(); ++i) {
+ const GURL& origin = infos[i].origin;
+ if (special_storage_policy_->IsStorageProtected(origin))
+ continue;
+ if (!special_storage_policy_->IsStorageSessionOnly(origin))
+ continue;
+ session_storage_database_->DeleteArea(infos[i].persistent_namespace_id,
+ origin);
+ }
+ }
+}
+
+void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() {
+ DCHECK(namespaces_.empty());
+ if (!sessionstorage_directory_.empty()) {
+ session_storage_database_ = new SessionStorageDatabase(
+ sessionstorage_directory_);
+ }
}
void DOMStorageContextImpl::StartScavengingUnusedSessionStorage() {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&DomStorageContext::StartScavengingUnusedSessionStorage,
- context_));
+ if (session_storage_database_.get()) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&DOMStorageContextImpl::FindUnusedNamespaces,
+ this),
+ base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+ }
}
-void DOMStorageContextImpl::PurgeMemory() {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&DomStorageContext::PurgeMemory, context_));
+void DOMStorageContextImpl::FindUnusedNamespaces() {
+ DCHECK(session_storage_database_.get());
+ if (scavenging_started_)
+ return;
+ scavenging_started_ = true;
+ std::set<std::string> namespace_ids_in_use;
+ for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
+ it != namespaces_.end(); ++it)
+ namespace_ids_in_use.insert(it->second->persistent_namespace_id());
+ std::set<std::string> protected_persistent_session_ids;
+ protected_persistent_session_ids.swap(protected_persistent_session_ids_);
+ task_runner_->PostShutdownBlockingTask(
+ FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
+ base::Bind(
+ &DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence,
+ this, namespace_ids_in_use, protected_persistent_session_ids));
}
-void DOMStorageContextImpl::SetForceKeepSessionState() {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&DomStorageContext::SetForceKeepSessionState, context_));
+void DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence(
+ const std::set<std::string>& namespace_ids_in_use,
+ const std::set<std::string>& protected_persistent_session_ids) {
+ DCHECK(session_storage_database_.get());
+ // Delete all namespaces which don't have an associated DOMStorageNamespace
+ // alive.
+ std::map<std::string, std::vector<GURL> > namespaces_and_origins;
+ session_storage_database_->ReadNamespacesAndOrigins(&namespaces_and_origins);
+ for (std::map<std::string, std::vector<GURL> >::const_iterator it =
+ namespaces_and_origins.begin();
+ it != namespaces_and_origins.end(); ++it) {
+ if (namespace_ids_in_use.find(it->first) == namespace_ids_in_use.end() &&
+ protected_persistent_session_ids.find(it->first) ==
+ protected_persistent_session_ids.end()) {
+ deletable_persistent_namespace_ids_.push_back(it->first);
+ }
+ }
+ if (!deletable_persistent_namespace_ids_.empty()) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(
+ &DOMStorageContextImpl::DeleteNextUnusedNamespace,
+ this),
+ base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+ }
}
-void DOMStorageContextImpl::Shutdown() {
- DCHECK(context_.get());
- context_->task_runner()->PostShutdownBlockingTask(
- FROM_HERE,
- DomStorageTaskRunner::PRIMARY_SEQUENCE,
- base::Bind(&DomStorageContext::Shutdown, context_));
+void DOMStorageContextImpl::DeleteNextUnusedNamespace() {
+ if (is_shutdown_)
+ return;
+ task_runner_->PostShutdownBlockingTask(
+ FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
+ base::Bind(
+ &DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence,
+ this));
+}
+
+void DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence() {
+ if (deletable_persistent_namespace_ids_.empty())
+ return;
+ const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
+ session_storage_database_->DeleteNamespace(persistent_id);
+ deletable_persistent_namespace_ids_.pop_back();
+ if (!deletable_persistent_namespace_ids_.empty()) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(
+ &DOMStorageContextImpl::DeleteNextUnusedNamespace,
+ this),
+ base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+ }
}
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698