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 |