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