Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/dom_storage/dom_storage_context_impl.h" | 5 #include "content/browser/dom_storage/dom_storage_context_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/files/file_path.h" | 9 #include "base/file_util.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/files/file_enumerator.h" |
| 11 #include "content/browser/dom_storage/session_storage_namespace_impl.h" | 11 #include "base/guid.h" |
| 12 #include "content/public/browser/browser_thread.h" | 12 #include "base/location.h" |
| 13 #include "webkit/browser/dom_storage/dom_storage_area.h" | 13 #include "base/time/time.h" |
| 14 #include "webkit/browser/dom_storage/dom_storage_context.h" | 14 #include "content/browser/dom_storage/dom_storage_area.h" |
| 15 #include "webkit/browser/dom_storage/dom_storage_task_runner.h" | 15 #include "content/browser/dom_storage/dom_storage_database.h" |
| 16 | 16 #include "content/browser/dom_storage/dom_storage_namespace.h" |
| 17 using dom_storage::DomStorageArea; | 17 #include "content/browser/dom_storage/dom_storage_task_runner.h" |
| 18 using dom_storage::DomStorageContext; | 18 #include "content/browser/dom_storage/session_storage_database.h" |
| 19 using dom_storage::DomStorageTaskRunner; | 19 #include "content/common/dom_storage/dom_storage_types.h" |
| 20 using dom_storage::DomStorageWorkerPoolTaskRunner; | 20 #include "content/public/browser/dom_storage_context.h" |
| 21 #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
| |
| 21 | 22 |
| 22 namespace content { | 23 namespace content { |
| 23 namespace { | 24 |
| 24 | 25 static const int kSessionStoraceScavengingSeconds = 60; |
| 25 const char kLocalStorageDirectory[] = "Local Storage"; | |
| 26 const char kSessionStorageDirectory[] = "Session Storage"; | |
| 27 | |
| 28 void InvokeLocalStorageUsageCallbackHelper( | |
| 29 const DOMStorageContext::GetLocalStorageUsageCallback& callback, | |
| 30 const std::vector<dom_storage::LocalStorageUsageInfo>* infos) { | |
| 31 callback.Run(*infos); | |
| 32 } | |
| 33 | |
| 34 void GetLocalStorageUsageHelper( | |
| 35 base::MessageLoopProxy* reply_loop, | |
| 36 DomStorageContext* context, | |
| 37 const DOMStorageContext::GetLocalStorageUsageCallback& callback) { | |
| 38 std::vector<dom_storage::LocalStorageUsageInfo>* infos = | |
| 39 new std::vector<dom_storage::LocalStorageUsageInfo>; | |
| 40 context->GetLocalStorageUsage(infos, true); | |
| 41 reply_loop->PostTask( | |
| 42 FROM_HERE, | |
| 43 base::Bind(&InvokeLocalStorageUsageCallbackHelper, | |
| 44 callback, base::Owned(infos))); | |
| 45 } | |
| 46 | |
| 47 void InvokeSessionStorageUsageCallbackHelper( | |
| 48 const DOMStorageContext::GetSessionStorageUsageCallback& callback, | |
| 49 const std::vector<dom_storage::SessionStorageUsageInfo>* infos) { | |
| 50 callback.Run(*infos); | |
| 51 } | |
| 52 | |
| 53 void GetSessionStorageUsageHelper( | |
| 54 base::MessageLoopProxy* reply_loop, | |
| 55 DomStorageContext* context, | |
| 56 const DOMStorageContext::GetSessionStorageUsageCallback& callback) { | |
| 57 std::vector<dom_storage::SessionStorageUsageInfo>* infos = | |
| 58 new std::vector<dom_storage::SessionStorageUsageInfo>; | |
| 59 context->GetSessionStorageUsage(infos); | |
| 60 reply_loop->PostTask( | |
| 61 FROM_HERE, | |
| 62 base::Bind(&InvokeSessionStorageUsageCallbackHelper, | |
| 63 callback, base::Owned(infos))); | |
| 64 } | |
| 65 | |
| 66 } // namespace | |
| 67 | 26 |
| 68 DOMStorageContextImpl::DOMStorageContextImpl( | 27 DOMStorageContextImpl::DOMStorageContextImpl( |
| 69 const base::FilePath& data_path, | 28 const base::FilePath& localstorage_directory, |
| 70 quota::SpecialStoragePolicy* special_storage_policy) { | 29 const base::FilePath& sessionstorage_directory, |
| 71 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); | 30 quota::SpecialStoragePolicy* special_storage_policy, |
| 72 context_ = new dom_storage::DomStorageContext( | 31 DOMStorageTaskRunner* task_runner) |
| 73 data_path.empty() ? data_path | 32 : localstorage_directory_(localstorage_directory), |
| 74 : data_path.AppendASCII(kLocalStorageDirectory), | 33 sessionstorage_directory_(sessionstorage_directory), |
| 75 data_path.empty() ? data_path | 34 task_runner_(task_runner), |
| 76 : data_path.AppendASCII(kSessionStorageDirectory), | 35 is_shutdown_(false), |
| 77 special_storage_policy, | 36 force_keep_session_state_(false), |
| 78 new DomStorageWorkerPoolTaskRunner( | 37 special_storage_policy_(special_storage_policy), |
| 79 worker_pool, | 38 scavenging_started_(false) { |
| 80 worker_pool->GetNamedSequenceToken("dom_storage_primary"), | 39 // AtomicSequenceNum starts at 0 but we want to start session |
| 81 worker_pool->GetNamedSequenceToken("dom_storage_commit"), | 40 // namespace ids at one since zero is reserved for the |
| 82 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO) | 41 // kLocalStorageNamespaceId. |
| 83 .get())); | 42 session_id_sequence_.GetNext(); |
| 84 } | 43 } |
| 85 | 44 |
| 86 DOMStorageContextImpl::~DOMStorageContextImpl() { | 45 DOMStorageContextImpl::~DOMStorageContextImpl() { |
| 46 if (session_storage_database_.get()) { | |
| 47 // SessionStorageDatabase shouldn't be deleted right away: deleting it will | |
| 48 // potentially involve waiting in leveldb::DBImpl::~DBImpl, and waiting | |
| 49 // shouldn't happen on this thread. | |
| 50 SessionStorageDatabase* to_release = session_storage_database_.get(); | |
| 51 to_release->AddRef(); | |
| 52 session_storage_database_ = NULL; | |
| 53 task_runner_->PostShutdownBlockingTask( | |
| 54 FROM_HERE, | |
| 55 DOMStorageTaskRunner::COMMIT_SEQUENCE, | |
| 56 base::Bind(&SessionStorageDatabase::Release, | |
| 57 base::Unretained(to_release))); | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 DOMStorageNamespace* DOMStorageContextImpl::GetStorageNamespace( | |
| 62 int64 namespace_id) { | |
| 63 if (is_shutdown_) | |
| 64 return NULL; | |
| 65 StorageNamespaceMap::iterator found = namespaces_.find(namespace_id); | |
| 66 if (found == namespaces_.end()) { | |
| 67 if (namespace_id == kLocalStorageNamespaceId) { | |
| 68 if (!localstorage_directory_.empty()) { | |
| 69 if (!file_util::CreateDirectory(localstorage_directory_)) { | |
| 70 LOG(ERROR) << "Failed to create 'Local Storage' directory," | |
| 71 " falling back to in-memory only."; | |
| 72 localstorage_directory_ = base::FilePath(); | |
| 73 } | |
| 74 } | |
| 75 DOMStorageNamespace* local = | |
| 76 new DOMStorageNamespace(localstorage_directory_, task_runner_.get()); | |
| 77 namespaces_[kLocalStorageNamespaceId] = local; | |
| 78 return local; | |
| 79 } | |
| 80 return NULL; | |
| 81 } | |
| 82 return found->second.get(); | |
| 87 } | 83 } |
| 88 | 84 |
| 89 void DOMStorageContextImpl::GetLocalStorageUsage( | 85 void DOMStorageContextImpl::GetLocalStorageUsage( |
| 90 const GetLocalStorageUsageCallback& callback) { | 86 std::vector<LocalStorageUsageInfo>* infos, |
| 91 DCHECK(context_.get()); | 87 bool include_file_info) { |
| 92 context_->task_runner() | 88 if (localstorage_directory_.empty()) |
| 93 ->PostShutdownBlockingTask(FROM_HERE, | 89 return; |
| 94 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 90 base::FileEnumerator enumerator(localstorage_directory_, false, |
| 95 base::Bind(&GetLocalStorageUsageHelper, | 91 base::FileEnumerator::FILES); |
| 96 base::MessageLoopProxy::current(), | 92 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 97 context_, | 93 path = enumerator.Next()) { |
| 98 callback)); | 94 if (path.MatchesExtension(DOMStorageArea::kDatabaseFileExtension)) { |
| 95 LocalStorageUsageInfo info; | |
| 96 info.origin = DOMStorageArea::OriginFromDatabaseFileName(path); | |
| 97 if (include_file_info) { | |
| 98 base::FileEnumerator::FileInfo find_info = enumerator.GetInfo(); | |
| 99 info.data_size = find_info.GetSize(); | |
| 100 info.last_modified = find_info.GetLastModifiedTime(); | |
| 101 } | |
| 102 infos->push_back(info); | |
| 103 } | |
| 104 } | |
| 99 } | 105 } |
| 100 | 106 |
| 101 void DOMStorageContextImpl::GetSessionStorageUsage( | 107 void DOMStorageContextImpl::GetSessionStorageUsage( |
| 102 const GetSessionStorageUsageCallback& callback) { | 108 std::vector<SessionStorageUsageInfo>* infos) { |
| 103 DCHECK(context_.get()); | 109 if (!session_storage_database_.get()) |
| 104 context_->task_runner() | 110 return; |
| 105 ->PostShutdownBlockingTask(FROM_HERE, | 111 std::map<std::string, std::vector<GURL> > namespaces_and_origins; |
| 106 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 112 session_storage_database_->ReadNamespacesAndOrigins( |
| 107 base::Bind(&GetSessionStorageUsageHelper, | 113 &namespaces_and_origins); |
| 108 base::MessageLoopProxy::current(), | 114 for (std::map<std::string, std::vector<GURL> >::const_iterator it = |
| 109 context_, | 115 namespaces_and_origins.begin(); |
| 110 callback)); | 116 it != namespaces_and_origins.end(); ++it) { |
| 117 for (std::vector<GURL>::const_iterator origin_it = it->second.begin(); | |
| 118 origin_it != it->second.end(); ++origin_it) { | |
| 119 SessionStorageUsageInfo info; | |
| 120 info.persistent_namespace_id = it->first; | |
| 121 info.origin = *origin_it; | |
| 122 infos->push_back(info); | |
| 123 } | |
| 124 } | |
| 111 } | 125 } |
| 112 | 126 |
| 113 void DOMStorageContextImpl::DeleteLocalStorage(const GURL& origin) { | 127 void DOMStorageContextImpl::DeleteLocalStorage(const GURL& origin) { |
| 114 DCHECK(context_.get()); | 128 DCHECK(!is_shutdown_); |
| 115 context_->task_runner()->PostShutdownBlockingTask( | 129 DOMStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId); |
| 116 FROM_HERE, | 130 local->DeleteLocalStorageOrigin(origin); |
| 117 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 131 // Synthesize a 'cleared' event if the area is open so CachedAreas in |
| 118 base::Bind(&DomStorageContext::DeleteLocalStorage, context_, origin)); | 132 // renderers get emptied out too. |
| 133 DOMStorageArea* area = local->GetOpenStorageArea(origin); | |
| 134 if (area) | |
| 135 NotifyAreaCleared(area, origin); | |
| 119 } | 136 } |
| 120 | 137 |
| 121 void DOMStorageContextImpl::DeleteSessionStorage( | 138 void DOMStorageContextImpl::DeleteSessionStorage( |
| 122 const dom_storage::SessionStorageUsageInfo& usage_info) { | 139 const SessionStorageUsageInfo& usage_info) { |
| 123 DCHECK(context_.get()); | 140 DCHECK(!is_shutdown_); |
| 124 context_->task_runner()->PostShutdownBlockingTask( | 141 DOMStorageNamespace* dom_storage_namespace = NULL; |
| 125 FROM_HERE, | 142 std::map<std::string, int64>::const_iterator it = |
| 126 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 143 persistent_namespace_id_to_namespace_id_.find( |
| 144 usage_info.persistent_namespace_id); | |
| 145 if (it != persistent_namespace_id_to_namespace_id_.end()) { | |
| 146 dom_storage_namespace = GetStorageNamespace(it->second); | |
| 147 } else { | |
| 148 int64 namespace_id = AllocateSessionId(); | |
| 149 CreateSessionNamespace(namespace_id, usage_info.persistent_namespace_id); | |
| 150 dom_storage_namespace = GetStorageNamespace(namespace_id); | |
| 151 } | |
| 152 dom_storage_namespace->DeleteSessionStorageOrigin(usage_info.origin); | |
| 153 // Synthesize a 'cleared' event if the area is open so CachedAreas in | |
| 154 // renderers get emptied out too. | |
| 155 DOMStorageArea* area = | |
| 156 dom_storage_namespace->GetOpenStorageArea(usage_info.origin); | |
| 157 if (area) | |
| 158 NotifyAreaCleared(area, usage_info.origin); | |
| 159 } | |
| 160 | |
| 161 void DOMStorageContextImpl::PurgeMemory() { | |
| 162 // We can only purge memory from the local storage namespace | |
| 163 // which is backed by disk. | |
| 164 // TODO(marja): Purge sessionStorage, too. (Requires changes to the FastClear | |
| 165 // functionality.) | |
| 166 StorageNamespaceMap::iterator found = | |
| 167 namespaces_.find(kLocalStorageNamespaceId); | |
| 168 if (found != namespaces_.end()) | |
| 169 found->second->PurgeMemory(DOMStorageNamespace::PURGE_AGGRESSIVE); | |
| 170 } | |
| 171 | |
| 172 void DOMStorageContextImpl::Shutdown() { | |
| 173 is_shutdown_ = true; | |
| 174 StorageNamespaceMap::const_iterator it = namespaces_.begin(); | |
| 175 for (; it != namespaces_.end(); ++it) | |
| 176 it->second->Shutdown(); | |
| 177 | |
| 178 if (localstorage_directory_.empty() && !session_storage_database_.get()) | |
| 179 return; | |
| 180 | |
| 181 // Respect the content policy settings about what to | |
| 182 // keep and what to discard. | |
| 183 if (force_keep_session_state_) | |
| 184 return; // Keep everything. | |
| 185 | |
| 186 bool has_session_only_origins = | |
| 187 special_storage_policy_.get() && | |
| 188 special_storage_policy_->HasSessionOnlyOrigins(); | |
| 189 | |
| 190 if (has_session_only_origins) { | |
| 191 // We may have to delete something. We continue on the | |
| 192 // commit sequence after area shutdown tasks have cycled | |
| 193 // thru that sequence (and closed their database files). | |
| 194 bool success = task_runner_->PostShutdownBlockingTask( | |
| 195 FROM_HERE, | |
| 196 DOMStorageTaskRunner::COMMIT_SEQUENCE, | |
| 197 base::Bind(&DOMStorageContextImpl::ClearSessionOnlyOrigins, this)); | |
| 198 DCHECK(success); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 void DOMStorageContextImpl::AddEventObserver(EventObserver* observer) { | |
| 203 event_observers_.AddObserver(observer); | |
| 204 } | |
| 205 | |
| 206 void DOMStorageContextImpl::RemoveEventObserver(EventObserver* observer) { | |
| 207 event_observers_.RemoveObserver(observer); | |
| 208 } | |
| 209 | |
| 210 void DOMStorageContextImpl::NotifyItemSet( | |
| 211 const DOMStorageArea* area, | |
| 212 const base::string16& key, | |
| 213 const base::string16& new_value, | |
| 214 const base::NullableString16& old_value, | |
| 215 const GURL& page_url) { | |
| 216 FOR_EACH_OBSERVER( | |
| 217 EventObserver, event_observers_, | |
| 218 OnDOMStorageItemSet(area, key, new_value, old_value, page_url)); | |
| 219 } | |
| 220 | |
| 221 void DOMStorageContextImpl::NotifyItemRemoved( | |
| 222 const DOMStorageArea* area, | |
| 223 const base::string16& key, | |
| 224 const base::string16& old_value, | |
| 225 const GURL& page_url) { | |
| 226 FOR_EACH_OBSERVER( | |
| 227 EventObserver, event_observers_, | |
| 228 OnDOMStorageItemRemoved(area, key, old_value, page_url)); | |
| 229 } | |
| 230 | |
| 231 void DOMStorageContextImpl::NotifyAreaCleared( | |
| 232 const DOMStorageArea* area, | |
| 233 const GURL& page_url) { | |
| 234 FOR_EACH_OBSERVER( | |
| 235 EventObserver, event_observers_, | |
| 236 OnDOMStorageAreaCleared(area, page_url)); | |
| 237 } | |
| 238 | |
| 239 std::string DOMStorageContextImpl::AllocatePersistentSessionId() { | |
| 240 std::string guid = base::GenerateGUID(); | |
| 241 std::replace(guid.begin(), guid.end(), '-', '_'); | |
| 242 return guid; | |
| 243 } | |
| 244 | |
| 245 void DOMStorageContextImpl::CreateSessionNamespace( | |
| 246 int64 namespace_id, | |
| 247 const std::string& persistent_namespace_id) { | |
| 248 if (is_shutdown_) | |
| 249 return; | |
| 250 DCHECK(namespace_id != kLocalStorageNamespaceId); | |
| 251 DCHECK(namespaces_.find(namespace_id) == namespaces_.end()); | |
| 252 namespaces_[namespace_id] = new DOMStorageNamespace( | |
| 253 namespace_id, persistent_namespace_id, session_storage_database_.get(), | |
| 254 task_runner_.get()); | |
| 255 persistent_namespace_id_to_namespace_id_[persistent_namespace_id] = | |
| 256 namespace_id; | |
| 257 } | |
| 258 | |
| 259 void DOMStorageContextImpl::DeleteSessionNamespace( | |
| 260 int64 namespace_id, bool should_persist_data) { | |
| 261 DCHECK_NE(kLocalStorageNamespaceId, namespace_id); | |
| 262 StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id); | |
| 263 if (it == namespaces_.end()) | |
| 264 return; | |
| 265 std::string persistent_namespace_id = it->second->persistent_namespace_id(); | |
| 266 if (session_storage_database_.get()) { | |
| 267 if (!should_persist_data) { | |
| 268 task_runner_->PostShutdownBlockingTask( | |
| 269 FROM_HERE, | |
| 270 DOMStorageTaskRunner::COMMIT_SEQUENCE, | |
| 271 base::Bind( | |
| 272 base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace), | |
| 273 session_storage_database_, | |
| 274 persistent_namespace_id)); | |
| 275 } else { | |
| 276 // Ensure that the data gets committed before we shut down. | |
| 277 it->second->Shutdown(); | |
| 278 if (!scavenging_started_) { | |
| 279 // Protect the persistent namespace ID from scavenging. | |
| 280 protected_persistent_session_ids_.insert(persistent_namespace_id); | |
| 281 } | |
| 282 } | |
| 283 } | |
| 284 persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id); | |
| 285 namespaces_.erase(namespace_id); | |
| 286 } | |
| 287 | |
| 288 void DOMStorageContextImpl::CloneSessionNamespace( | |
| 289 int64 existing_id, int64 new_id, | |
| 290 const std::string& new_persistent_id) { | |
| 291 if (is_shutdown_) | |
| 292 return; | |
| 293 DCHECK_NE(kLocalStorageNamespaceId, existing_id); | |
| 294 DCHECK_NE(kLocalStorageNamespaceId, new_id); | |
| 295 StorageNamespaceMap::iterator found = namespaces_.find(existing_id); | |
| 296 if (found != namespaces_.end()) | |
| 297 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id); | |
| 298 else | |
| 299 CreateSessionNamespace(new_id, new_persistent_id); | |
| 300 } | |
| 301 | |
| 302 void DOMStorageContextImpl::ClearSessionOnlyOrigins() { | |
| 303 if (!localstorage_directory_.empty()) { | |
| 304 std::vector<LocalStorageUsageInfo> infos; | |
| 305 const bool kDontIncludeFileInfo = false; | |
| 306 GetLocalStorageUsage(&infos, kDontIncludeFileInfo); | |
| 307 for (size_t i = 0; i < infos.size(); ++i) { | |
| 308 const GURL& origin = infos[i].origin; | |
| 309 if (special_storage_policy_->IsStorageProtected(origin)) | |
| 310 continue; | |
| 311 if (!special_storage_policy_->IsStorageSessionOnly(origin)) | |
| 312 continue; | |
| 313 | |
| 314 base::FilePath database_file_path = localstorage_directory_.Append( | |
| 315 DOMStorageArea::DatabaseFileNameFromOrigin(origin)); | |
| 316 sql::Connection::Delete(database_file_path); | |
| 317 } | |
| 318 } | |
| 319 if (session_storage_database_.get()) { | |
| 320 std::vector<SessionStorageUsageInfo> infos; | |
| 321 GetSessionStorageUsage(&infos); | |
| 322 for (size_t i = 0; i < infos.size(); ++i) { | |
| 323 const GURL& origin = infos[i].origin; | |
| 324 if (special_storage_policy_->IsStorageProtected(origin)) | |
| 325 continue; | |
| 326 if (!special_storage_policy_->IsStorageSessionOnly(origin)) | |
| 327 continue; | |
| 328 session_storage_database_->DeleteArea(infos[i].persistent_namespace_id, | |
| 329 origin); | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() { | |
| 335 DCHECK(namespaces_.empty()); | |
| 336 if (!sessionstorage_directory_.empty()) { | |
| 337 session_storage_database_ = new SessionStorageDatabase( | |
| 338 sessionstorage_directory_); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 void DOMStorageContextImpl::StartScavengingUnusedSessionStorage() { | |
| 343 if (session_storage_database_.get()) { | |
| 344 task_runner_->PostDelayedTask( | |
| 345 FROM_HERE, base::Bind(&DOMStorageContextImpl::FindUnusedNamespaces, this ), | |
| 346 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds)); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 void DOMStorageContextImpl::FindUnusedNamespaces() { | |
| 351 DCHECK(session_storage_database_.get()); | |
| 352 if (scavenging_started_) | |
| 353 return; | |
| 354 scavenging_started_ = true; | |
| 355 std::set<std::string> namespace_ids_in_use; | |
| 356 for (StorageNamespaceMap::const_iterator it = namespaces_.begin(); | |
| 357 it != namespaces_.end(); ++it) | |
| 358 namespace_ids_in_use.insert(it->second->persistent_namespace_id()); | |
| 359 std::set<std::string> protected_persistent_session_ids; | |
| 360 protected_persistent_session_ids.swap(protected_persistent_session_ids_); | |
| 361 task_runner_->PostShutdownBlockingTask( | |
| 362 FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE, | |
| 127 base::Bind( | 363 base::Bind( |
| 128 &DomStorageContext::DeleteSessionStorage, context_, usage_info)); | 364 &DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence, |
| 129 } | 365 this, namespace_ids_in_use, protected_persistent_session_ids)); |
| 130 | 366 } |
| 131 void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() { | 367 |
| 132 DCHECK(context_.get()); | 368 void DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence( |
| 133 context_->SetSaveSessionStorageOnDisk(); | 369 const std::set<std::string>& namespace_ids_in_use, |
| 134 } | 370 const std::set<std::string>& protected_persistent_session_ids) { |
| 135 | 371 DCHECK(session_storage_database_.get()); |
| 136 scoped_refptr<SessionStorageNamespace> | 372 // Delete all namespaces which don't have an associated DOMStorageNamespace |
| 137 DOMStorageContextImpl::RecreateSessionStorage( | 373 // alive. |
| 138 const std::string& persistent_id) { | 374 std::map<std::string, std::vector<GURL> > namespaces_and_origins; |
| 139 return scoped_refptr<SessionStorageNamespace>( | 375 session_storage_database_->ReadNamespacesAndOrigins(&namespaces_and_origins); |
| 140 new SessionStorageNamespaceImpl(this, persistent_id)); | 376 for (std::map<std::string, std::vector<GURL> >::const_iterator it = |
| 141 } | 377 namespaces_and_origins.begin(); |
| 142 | 378 it != namespaces_and_origins.end(); ++it) { |
| 143 void DOMStorageContextImpl::StartScavengingUnusedSessionStorage() { | 379 if (namespace_ids_in_use.find(it->first) == namespace_ids_in_use.end() && |
| 144 DCHECK(context_.get()); | 380 protected_persistent_session_ids.find(it->first) == |
| 145 context_->task_runner()->PostShutdownBlockingTask( | 381 protected_persistent_session_ids.end()) { |
| 146 FROM_HERE, | 382 deletable_persistent_namespace_ids_.push_back(it->first); |
| 147 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 383 } |
| 148 base::Bind(&DomStorageContext::StartScavengingUnusedSessionStorage, | 384 } |
| 149 context_)); | 385 if (!deletable_persistent_namespace_ids_.empty()) { |
| 150 } | 386 task_runner_->PostDelayedTask( |
| 151 | 387 FROM_HERE, base::Bind( |
| 152 void DOMStorageContextImpl::PurgeMemory() { | 388 &DOMStorageContextImpl::DeleteNextUnusedNamespace, |
| 153 DCHECK(context_.get()); | 389 this), |
| 154 context_->task_runner()->PostShutdownBlockingTask( | 390 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds)); |
| 155 FROM_HERE, | 391 } |
| 156 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 392 } |
| 157 base::Bind(&DomStorageContext::PurgeMemory, context_)); | 393 |
| 158 } | 394 void DOMStorageContextImpl::DeleteNextUnusedNamespace() { |
| 159 | 395 if (is_shutdown_) |
| 160 void DOMStorageContextImpl::SetForceKeepSessionState() { | 396 return; |
| 161 DCHECK(context_.get()); | 397 task_runner_->PostShutdownBlockingTask( |
| 162 context_->task_runner()->PostShutdownBlockingTask( | 398 FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE, |
| 163 FROM_HERE, | 399 base::Bind( |
| 164 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 400 &DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence, |
| 165 base::Bind(&DomStorageContext::SetForceKeepSessionState, context_)); | 401 this)); |
| 166 } | 402 } |
| 167 | 403 |
| 168 void DOMStorageContextImpl::Shutdown() { | 404 void DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence() { |
| 169 DCHECK(context_.get()); | 405 if (deletable_persistent_namespace_ids_.empty()) |
| 170 context_->task_runner()->PostShutdownBlockingTask( | 406 return; |
| 171 FROM_HERE, | 407 const std::string& persistent_id = deletable_persistent_namespace_ids_.back(); |
| 172 DomStorageTaskRunner::PRIMARY_SEQUENCE, | 408 session_storage_database_->DeleteNamespace(persistent_id); |
| 173 base::Bind(&DomStorageContext::Shutdown, context_)); | 409 deletable_persistent_namespace_ids_.pop_back(); |
| 410 if (!deletable_persistent_namespace_ids_.empty()) { | |
| 411 task_runner_->PostDelayedTask( | |
| 412 FROM_HERE, base::Bind( | |
| 413 &DOMStorageContextImpl::DeleteNextUnusedNamespace, | |
| 414 this), | |
| 415 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds)); | |
| 416 } | |
| 174 } | 417 } |
| 175 | 418 |
| 176 } // namespace content | 419 } // namespace content |
| OLD | NEW |