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

Side by Side Diff: webkit/dom_storage/dom_storage_context.cc

Issue 9963107: Persist sessionStorage on disk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: regression test Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "webkit/dom_storage/dom_storage_context.h" 5 #include "webkit/dom_storage/dom_storage_context.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/file_util.h" 9 #include "base/file_util.h"
10 #include "base/guid.h" 10 #include "base/guid.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 #include "webkit/dom_storage/dom_storage_area.h" 13 #include "webkit/dom_storage/dom_storage_area.h"
14 #include "webkit/dom_storage/dom_storage_database.h" 14 #include "webkit/dom_storage/dom_storage_database.h"
15 #include "webkit/dom_storage/dom_storage_namespace.h" 15 #include "webkit/dom_storage/dom_storage_namespace.h"
16 #include "webkit/dom_storage/dom_storage_task_runner.h" 16 #include "webkit/dom_storage/dom_storage_task_runner.h"
17 #include "webkit/dom_storage/dom_storage_types.h" 17 #include "webkit/dom_storage/dom_storage_types.h"
18 #include "webkit/dom_storage/session_storage_database.h"
18 #include "webkit/quota/special_storage_policy.h" 19 #include "webkit/quota/special_storage_policy.h"
19 20
20 using file_util::FileEnumerator; 21 using file_util::FileEnumerator;
21 22
22 namespace dom_storage { 23 namespace dom_storage {
23 24
25 static const int kSessionStoraceScavengingSeconds = 60;
26
24 DomStorageContext::UsageInfo::UsageInfo() : data_size(0) {} 27 DomStorageContext::UsageInfo::UsageInfo() : data_size(0) {}
25 DomStorageContext::UsageInfo::~UsageInfo() {} 28 DomStorageContext::UsageInfo::~UsageInfo() {}
26 29
27 DomStorageContext::DomStorageContext( 30 DomStorageContext::DomStorageContext(
28 const FilePath& localstorage_directory, 31 const FilePath& localstorage_directory,
29 const FilePath& sessionstorage_directory, 32 const FilePath& sessionstorage_directory,
30 quota::SpecialStoragePolicy* special_storage_policy, 33 quota::SpecialStoragePolicy* special_storage_policy,
31 DomStorageTaskRunner* task_runner) 34 DomStorageTaskRunner* task_runner)
32 : localstorage_directory_(localstorage_directory), 35 : localstorage_directory_(localstorage_directory),
33 sessionstorage_directory_(sessionstorage_directory), 36 sessionstorage_directory_(sessionstorage_directory),
34 task_runner_(task_runner), 37 task_runner_(task_runner),
35 is_shutdown_(false), 38 is_shutdown_(false),
36 force_keep_session_state_(false), 39 force_keep_session_state_(false),
37 special_storage_policy_(special_storage_policy) { 40 special_storage_policy_(special_storage_policy),
41 scavenging_started_(false) {
38 // AtomicSequenceNum starts at 0 but we want to start session 42 // AtomicSequenceNum starts at 0 but we want to start session
39 // namespace ids at one since zero is reserved for the 43 // namespace ids at one since zero is reserved for the
40 // kLocalStorageNamespaceId. 44 // kLocalStorageNamespaceId.
41 session_id_sequence_.GetNext(); 45 session_id_sequence_.GetNext();
42 } 46 }
43 47
44 DomStorageContext::~DomStorageContext() { 48 DomStorageContext::~DomStorageContext() {
45 } 49 }
46 50
47 DomStorageNamespace* DomStorageContext::GetStorageNamespace( 51 DomStorageNamespace* DomStorageContext::GetStorageNamespace(
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 info.origin = DomStorageArea::OriginFromDatabaseFileName(path); 85 info.origin = DomStorageArea::OriginFromDatabaseFileName(path);
82 if (include_file_info) { 86 if (include_file_info) {
83 FileEnumerator::FindInfo find_info; 87 FileEnumerator::FindInfo find_info;
84 enumerator.GetFindInfo(&find_info); 88 enumerator.GetFindInfo(&find_info);
85 info.data_size = FileEnumerator::GetFilesize(find_info); 89 info.data_size = FileEnumerator::GetFilesize(find_info);
86 info.last_modified = FileEnumerator::GetLastModifiedTime(find_info); 90 info.last_modified = FileEnumerator::GetLastModifiedTime(find_info);
87 } 91 }
88 infos->push_back(info); 92 infos->push_back(info);
89 } 93 }
90 } 94 }
95 // TODO(marja): Get usage infos for sessionStorage (crbug.com/123599).
91 } 96 }
92 97
93 void DomStorageContext::DeleteOrigin(const GURL& origin) { 98 void DomStorageContext::DeleteOrigin(const GURL& origin) {
94 DCHECK(!is_shutdown_); 99 DCHECK(!is_shutdown_);
95 DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId); 100 DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
96 local->DeleteOrigin(origin); 101 local->DeleteOrigin(origin);
97 } 102 }
98 103
99 void DomStorageContext::PurgeMemory() { 104 void DomStorageContext::PurgeMemory() {
100 // We can only purge memory from the local storage namespace 105 // We can only purge memory from the local storage namespace
101 // which is backed by disk. 106 // which is backed by disk.
102 StorageNamespaceMap::iterator found = 107 StorageNamespaceMap::iterator found =
103 namespaces_.find(kLocalStorageNamespaceId); 108 namespaces_.find(kLocalStorageNamespaceId);
104 if (found != namespaces_.end()) 109 if (found != namespaces_.end())
105 found->second->PurgeMemory(); 110 found->second->PurgeMemory();
106 } 111 }
107 112
108 void DomStorageContext::Shutdown() { 113 void DomStorageContext::Shutdown() {
109 is_shutdown_ = true; 114 is_shutdown_ = true;
110 StorageNamespaceMap::const_iterator it = namespaces_.begin(); 115 StorageNamespaceMap::const_iterator it = namespaces_.begin();
111 for (; it != namespaces_.end(); ++it) 116 for (; it != namespaces_.end(); ++it)
112 it->second->Shutdown(); 117 it->second->Shutdown();
113 118
114 if (localstorage_directory_.empty()) 119 if (localstorage_directory_.empty() && !session_storage_database_.get())
115 return; 120 return;
116 121
117 // Respect the content policy settings about what to 122 // Respect the content policy settings about what to
118 // keep and what to discard. 123 // keep and what to discard.
119 if (force_keep_session_state_) 124 if (force_keep_session_state_)
120 return; // Keep everything. 125 return; // Keep everything.
121 126
122 bool has_session_only_origins = 127 bool has_session_only_origins =
123 special_storage_policy_.get() && 128 special_storage_policy_.get() &&
124 special_storage_policy_->HasSessionOnlyOrigins(); 129 special_storage_policy_->HasSessionOnlyOrigins();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 } 184 }
180 185
181 void DomStorageContext::CreateSessionNamespace( 186 void DomStorageContext::CreateSessionNamespace(
182 int64 namespace_id, 187 int64 namespace_id,
183 const std::string& persistent_namespace_id) { 188 const std::string& persistent_namespace_id) {
184 if (is_shutdown_) 189 if (is_shutdown_)
185 return; 190 return;
186 DCHECK(namespace_id != kLocalStorageNamespaceId); 191 DCHECK(namespace_id != kLocalStorageNamespaceId);
187 DCHECK(namespaces_.find(namespace_id) == namespaces_.end()); 192 DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
188 namespaces_[namespace_id] = new DomStorageNamespace( 193 namespaces_[namespace_id] = new DomStorageNamespace(
189 namespace_id, persistent_namespace_id, task_runner_); 194 namespace_id, persistent_namespace_id, session_storage_database_.get(),
195 task_runner_);
190 } 196 }
191 197
192 void DomStorageContext::DeleteSessionNamespace( 198 void DomStorageContext::DeleteSessionNamespace(
193 int64 namespace_id, bool should_persist_data) { 199 int64 namespace_id, bool should_persist_data) {
194 DCHECK_NE(kLocalStorageNamespaceId, namespace_id); 200 DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
195 // TODO(marja): Protect the sessionStorage data (once it's written on disk). 201 StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
202 if (it == namespaces_.end())
203 return;
204 if (session_storage_database_.get()) {
205 std::string persistent_namespace_id = it->second->persistent_namespace_id();
206 if (!should_persist_data) {
207 bool success = task_runner_->PostShutdownBlockingTask(
208 FROM_HERE,
209 DomStorageTaskRunner::COMMIT_SEQUENCE,
210 base::Bind(
211 base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
212 session_storage_database_,
213 persistent_namespace_id));
214 DCHECK(success);
215 } else if (!scavenging_started_) {
216 // Protect the persistent namespace ID from scavenging.
217 protected_persistent_session_ids_.insert(persistent_namespace_id);
218 }
219 }
196 namespaces_.erase(namespace_id); 220 namespaces_.erase(namespace_id);
197 } 221 }
198 222
199 void DomStorageContext::CloneSessionNamespace( 223 void DomStorageContext::CloneSessionNamespace(
200 int64 existing_id, int64 new_id, 224 int64 existing_id, int64 new_id,
201 const std::string& new_persistent_id) { 225 const std::string& new_persistent_id) {
202 if (is_shutdown_) 226 if (is_shutdown_)
203 return; 227 return;
204 DCHECK_NE(kLocalStorageNamespaceId, existing_id); 228 DCHECK_NE(kLocalStorageNamespaceId, existing_id);
205 DCHECK_NE(kLocalStorageNamespaceId, new_id); 229 DCHECK_NE(kLocalStorageNamespaceId, new_id);
206 StorageNamespaceMap::iterator found = namespaces_.find(existing_id); 230 StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
207 if (found != namespaces_.end()) 231 if (found != namespaces_.end())
208 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id); 232 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id);
209 else 233 else
210 CreateSessionNamespace(new_id, new_persistent_id); 234 CreateSessionNamespace(new_id, new_persistent_id);
211 } 235 }
212 236
213 void DomStorageContext::ClearSessionOnlyOrigins() { 237 void DomStorageContext::ClearSessionOnlyOrigins() {
214 std::vector<UsageInfo> infos; 238 if (!localstorage_directory_.empty()) {
215 const bool kDontIncludeFileInfo = false; 239 std::vector<UsageInfo> infos;
216 GetUsageInfo(&infos, kDontIncludeFileInfo); 240 const bool kDontIncludeFileInfo = false;
217 for (size_t i = 0; i < infos.size(); ++i) { 241 GetUsageInfo(&infos, kDontIncludeFileInfo);
218 const GURL& origin = infos[i].origin; 242 for (size_t i = 0; i < infos.size(); ++i) {
219 if (special_storage_policy_->IsStorageProtected(origin)) 243 const GURL& origin = infos[i].origin;
220 continue; 244 if (special_storage_policy_->IsStorageProtected(origin))
221 if (!special_storage_policy_->IsStorageSessionOnly(origin)) 245 continue;
222 continue; 246 if (!special_storage_policy_->IsStorageSessionOnly(origin))
247 continue;
223 248
224 const bool kNotRecursive = false; 249 const bool kNotRecursive = false;
225 FilePath database_file_path = localstorage_directory_.Append( 250 FilePath database_file_path = localstorage_directory_.Append(
226 DomStorageArea::DatabaseFileNameFromOrigin(origin)); 251 DomStorageArea::DatabaseFileNameFromOrigin(origin));
227 file_util::Delete(database_file_path, kNotRecursive); 252 file_util::Delete(database_file_path, kNotRecursive);
228 file_util::Delete( 253 file_util::Delete(
229 DomStorageDatabase::GetJournalFilePath(database_file_path), 254 DomStorageDatabase::GetJournalFilePath(database_file_path),
230 kNotRecursive); 255 kNotRecursive);
256 }
257 }
258 if (session_storage_database_.get()) {
259 std::vector<std::string> namespace_ids;
260 session_storage_database_->ReadNamespaceIds(&namespace_ids);
261 for (std::vector<std::string>::const_iterator it = namespace_ids.begin();
262 it != namespace_ids.end(); ++it) {
263 std::vector<GURL> origins;
264 session_storage_database_->ReadOriginsInNamespace(*it, &origins);
265
266 for (std::vector<GURL>::const_iterator origin_it = origins.begin();
267 origin_it != origins.end(); ++origin_it) {
268 if (special_storage_policy_->IsStorageProtected(*origin_it))
269 continue;
270 if (!special_storage_policy_->IsStorageSessionOnly(*origin_it))
271 continue;
272 session_storage_database_->DeleteArea(*it, *origin_it);
273 }
274 }
231 } 275 }
232 } 276 }
233 277
278 void DomStorageContext::SetSaveSessionStorageOnDisk() {
279 DCHECK(namespaces_.empty());
280 if (!sessionstorage_directory_.empty()) {
281 session_storage_database_ = new SessionStorageDatabase(
282 sessionstorage_directory_);
283 }
284 }
285
286 void DomStorageContext::StartScavengingUnusedSessionStorage() {
287 if (session_storage_database_.get()) {
288 bool success = task_runner_->PostDelayedTask(
289 FROM_HERE, base::Bind(&DomStorageContext::FindUnusedNamespaces, this),
290 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
291 DCHECK(success);
jam 2012/07/12 18:27:38 nit: i would remove all the DCHECK's on the result
marja 2012/07/13 09:05:17 Deleted the ones added by this CL, didn't touch th
292 }
293 }
294
295 void DomStorageContext::FindUnusedNamespaces() {
296 DCHECK(session_storage_database_.get());
297 DCHECK(!scavenging_started_);
298 scavenging_started_ = true;
299 std::set<std::string> namespace_ids_in_use;
300 for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
301 it != namespaces_.end(); ++it)
302 namespace_ids_in_use.insert(it->second->persistent_namespace_id());
303 std::set<std::string> protected_persistent_session_ids;
304 protected_persistent_session_ids.swap(protected_persistent_session_ids_);
305 bool success = task_runner_->PostShutdownBlockingTask(
306 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
307 base::Bind(
308 &DomStorageContext::FindUnusedNamespacesInCommitSequence,
309 this, namespace_ids_in_use, protected_persistent_session_ids));
310 DCHECK(success);
311 }
312
313 void DomStorageContext::FindUnusedNamespacesInCommitSequence(
314 const std::set<std::string>& namespace_ids_in_use,
315 const std::set<std::string>& protected_persistent_session_ids) {
316 DCHECK(session_storage_database_.get());
317 // Delete all namespaces which don't have an associated DomStorageNamespace
318 // alive.
319 std::vector<std::string> namespace_ids;
320 session_storage_database_->ReadNamespaceIds(&namespace_ids);
321 for (std::vector<std::string>::const_iterator it = namespace_ids.begin();
322 it != namespace_ids.end(); ++it) {
323 if (namespace_ids_in_use.find(*it) == namespace_ids_in_use.end() &&
324 protected_persistent_session_ids.find(*it) ==
325 protected_persistent_session_ids.end()) {
326 deletable_persistent_namespace_ids_.push_back(*it);
327 }
328 }
329 if (!deletable_persistent_namespace_ids_.empty()) {
330 bool success = task_runner_->PostDelayedTask(
331 FROM_HERE, base::Bind(
332 &DomStorageContext::DeleteNextUnusedNamespace,
333 this),
334 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
335 DCHECK(success);
336 }
337 }
338
339 void DomStorageContext::DeleteNextUnusedNamespace() {
340 if (is_shutdown_)
341 return;
342 bool success = task_runner_->PostShutdownBlockingTask(
343 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
344 base::Bind(
345 &DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence,
346 this));
347 DCHECK(success);
348 }
349
350 void DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence() {
351 const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
352 session_storage_database_->DeleteNamespace(persistent_id);
353 deletable_persistent_namespace_ids_.pop_back();
354 if (!deletable_persistent_namespace_ids_.empty()) {
355 bool success = task_runner_->PostDelayedTask(
356 FROM_HERE, base::Bind(
357 &DomStorageContext::DeleteNextUnusedNamespace,
358 this),
359 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
360 DCHECK(success);
361 }
362 }
363
234 } // namespace dom_storage 364 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698