Chromium Code Reviews| 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..076664b41c0bf073da2aa342e09d4b9bea1c1395 100644 |
| --- a/content/browser/dom_storage/dom_storage_context_impl.cc |
| +++ b/content/browser/dom_storage/dom_storage_context_impl.cc |
| @@ -6,171 +6,414 @@ |
| #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 "webkit/browser/quota/special_storage_policy.h" |
|
michaeln
2013/08/06 22:44:59
i see, it's computing the diff against the wrong t
|
| 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 |