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

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: code review 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();
46 if (!sessionstorage_directory_.empty()) {
47 session_storage_database_ = new SessionStorageDatabase(
48 sessionstorage_directory_);
49 }
42 } 50 }
43 51
44 DomStorageContext::~DomStorageContext() { 52 DomStorageContext::~DomStorageContext() {
45 } 53 }
46 54
47 DomStorageNamespace* DomStorageContext::GetStorageNamespace( 55 DomStorageNamespace* DomStorageContext::GetStorageNamespace(
48 int64 namespace_id) { 56 int64 namespace_id) {
49 if (is_shutdown_) 57 if (is_shutdown_)
50 return NULL; 58 return NULL;
51 StorageNamespaceMap::iterator found = namespaces_.find(namespace_id); 59 StorageNamespaceMap::iterator found = namespaces_.find(namespace_id);
(...skipping 29 matching lines...) Expand all
81 info.origin = DomStorageArea::OriginFromDatabaseFileName(path); 89 info.origin = DomStorageArea::OriginFromDatabaseFileName(path);
82 if (include_file_info) { 90 if (include_file_info) {
83 FileEnumerator::FindInfo find_info; 91 FileEnumerator::FindInfo find_info;
84 enumerator.GetFindInfo(&find_info); 92 enumerator.GetFindInfo(&find_info);
85 info.data_size = FileEnumerator::GetFilesize(find_info); 93 info.data_size = FileEnumerator::GetFilesize(find_info);
86 info.last_modified = FileEnumerator::GetLastModifiedTime(find_info); 94 info.last_modified = FileEnumerator::GetLastModifiedTime(find_info);
87 } 95 }
88 infos->push_back(info); 96 infos->push_back(info);
89 } 97 }
90 } 98 }
99 // TODO(marja): Get usage infos for sessionStorage (crbug.com/123599).
91 } 100 }
92 101
93 void DomStorageContext::DeleteOrigin(const GURL& origin) { 102 void DomStorageContext::DeleteOrigin(const GURL& origin) {
94 DCHECK(!is_shutdown_); 103 DCHECK(!is_shutdown_);
95 DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId); 104 DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
96 local->DeleteOrigin(origin); 105 local->DeleteOrigin(origin);
97 } 106 }
98 107
99 void DomStorageContext::PurgeMemory() { 108 void DomStorageContext::PurgeMemory() {
100 // We can only purge memory from the local storage namespace 109 // We can only purge memory from the local storage namespace
101 // which is backed by disk. 110 // which is backed by disk.
102 StorageNamespaceMap::iterator found = 111 StorageNamespaceMap::iterator found =
103 namespaces_.find(kLocalStorageNamespaceId); 112 namespaces_.find(kLocalStorageNamespaceId);
104 if (found != namespaces_.end()) 113 if (found != namespaces_.end())
105 found->second->PurgeMemory(); 114 found->second->PurgeMemory();
106 } 115 }
107 116
108 void DomStorageContext::Shutdown() { 117 void DomStorageContext::Shutdown() {
109 is_shutdown_ = true; 118 is_shutdown_ = true;
110 StorageNamespaceMap::const_iterator it = namespaces_.begin(); 119 StorageNamespaceMap::const_iterator it = namespaces_.begin();
111 for (; it != namespaces_.end(); ++it) 120 for (; it != namespaces_.end(); ++it)
112 it->second->Shutdown(); 121 it->second->Shutdown();
113 122
114 if (localstorage_directory_.empty()) 123 if (localstorage_directory_.empty() && !session_storage_database_.get())
115 return; 124 return;
116 125
117 // Respect the content policy settings about what to 126 // Respect the content policy settings about what to
118 // keep and what to discard. 127 // keep and what to discard.
119 if (force_keep_session_state_) 128 if (force_keep_session_state_)
120 return; // Keep everything. 129 return; // Keep everything.
121 130
122 bool has_session_only_origins = 131 bool has_session_only_origins =
123 special_storage_policy_.get() && 132 special_storage_policy_.get() &&
124 special_storage_policy_->HasSessionOnlyOrigins(); 133 special_storage_policy_->HasSessionOnlyOrigins();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 } 188 }
180 189
181 void DomStorageContext::CreateSessionNamespace( 190 void DomStorageContext::CreateSessionNamespace(
182 int64 namespace_id, 191 int64 namespace_id,
183 const std::string& persistent_namespace_id) { 192 const std::string& persistent_namespace_id) {
184 if (is_shutdown_) 193 if (is_shutdown_)
185 return; 194 return;
186 DCHECK(namespace_id != kLocalStorageNamespaceId); 195 DCHECK(namespace_id != kLocalStorageNamespaceId);
187 DCHECK(namespaces_.find(namespace_id) == namespaces_.end()); 196 DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
188 namespaces_[namespace_id] = new DomStorageNamespace( 197 namespaces_[namespace_id] = new DomStorageNamespace(
189 namespace_id, persistent_namespace_id, task_runner_); 198 namespace_id, persistent_namespace_id, session_storage_database_.get(),
199 task_runner_);
190 } 200 }
191 201
192 void DomStorageContext::DeleteSessionNamespace( 202 void DomStorageContext::DeleteSessionNamespace(
193 int64 namespace_id, bool should_persist_data) { 203 int64 namespace_id, bool should_persist_data) {
194 DCHECK_NE(kLocalStorageNamespaceId, namespace_id); 204 DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
195 // TODO(marja): Protect the sessionStorage data (once it's written on disk). 205 StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
206 if (it == namespaces_.end())
207 return;
208 std::string persistent_namespace_id = it->second->persistent_namespace_id();
209 if (session_storage_database_.get()) {
210 if (!should_persist_data) {
211 bool success = task_runner_->PostShutdownBlockingTask(
212 FROM_HERE,
213 DomStorageTaskRunner::COMMIT_SEQUENCE,
214 base::Bind(
215 base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
216 session_storage_database_,
217 persistent_namespace_id));
218 DCHECK(success);
219 } else if (!scavenging_started_) {
220 // Protect the persistent namespace ID from scavenging.
221 protected_persistent_session_ids_.insert(persistent_namespace_id);
222 }
223 }
196 namespaces_.erase(namespace_id); 224 namespaces_.erase(namespace_id);
197 } 225 }
198 226
199 void DomStorageContext::CloneSessionNamespace( 227 void DomStorageContext::CloneSessionNamespace(
200 int64 existing_id, int64 new_id, 228 int64 existing_id, int64 new_id,
201 const std::string& new_persistent_id) { 229 const std::string& new_persistent_id) {
202 if (is_shutdown_) 230 if (is_shutdown_)
203 return; 231 return;
204 DCHECK_NE(kLocalStorageNamespaceId, existing_id); 232 DCHECK_NE(kLocalStorageNamespaceId, existing_id);
205 DCHECK_NE(kLocalStorageNamespaceId, new_id); 233 DCHECK_NE(kLocalStorageNamespaceId, new_id);
206 StorageNamespaceMap::iterator found = namespaces_.find(existing_id); 234 StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
207 if (found != namespaces_.end()) 235 if (found != namespaces_.end())
208 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id); 236 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id);
209 else 237 else
210 CreateSessionNamespace(new_id, new_persistent_id); 238 CreateSessionNamespace(new_id, new_persistent_id);
211 } 239 }
212 240
213 void DomStorageContext::ClearSessionOnlyOrigins() { 241 void DomStorageContext::ClearSessionOnlyOrigins() {
214 std::vector<UsageInfo> infos; 242 if (!localstorage_directory_.empty()) {
215 const bool kDontIncludeFileInfo = false; 243 std::vector<UsageInfo> infos;
216 GetUsageInfo(&infos, kDontIncludeFileInfo); 244 const bool kDontIncludeFileInfo = false;
217 for (size_t i = 0; i < infos.size(); ++i) { 245 GetUsageInfo(&infos, kDontIncludeFileInfo);
218 const GURL& origin = infos[i].origin; 246 for (size_t i = 0; i < infos.size(); ++i) {
219 if (special_storage_policy_->IsStorageProtected(origin)) 247 const GURL& origin = infos[i].origin;
220 continue; 248 if (special_storage_policy_->IsStorageProtected(origin))
221 if (!special_storage_policy_->IsStorageSessionOnly(origin)) 249 continue;
222 continue; 250 if (!special_storage_policy_->IsStorageSessionOnly(origin))
251 continue;
223 252
224 const bool kNotRecursive = false; 253 const bool kNotRecursive = false;
225 FilePath database_file_path = localstorage_directory_.Append( 254 FilePath database_file_path = localstorage_directory_.Append(
226 DomStorageArea::DatabaseFileNameFromOrigin(origin)); 255 DomStorageArea::DatabaseFileNameFromOrigin(origin));
227 file_util::Delete(database_file_path, kNotRecursive); 256 file_util::Delete(database_file_path, kNotRecursive);
228 file_util::Delete( 257 file_util::Delete(
229 DomStorageDatabase::GetJournalFilePath(database_file_path), 258 DomStorageDatabase::GetJournalFilePath(database_file_path),
230 kNotRecursive); 259 kNotRecursive);
260 }
261 }
262 if (session_storage_database_.get()) {
263 std::vector<std::string> namespace_ids;
264 session_storage_database_->ReadNamespaceIds(&namespace_ids);
265 for (std::vector<std::string>::const_iterator it = namespace_ids.begin();
266 it != namespace_ids.end(); ++it) {
267 std::vector<GURL> origins;
268 session_storage_database_->ReadOriginsInNamespace(*it, &origins);
269
270 for (std::vector<GURL>::const_iterator origin_it = origins.begin();
271 origin_it != origins.end(); ++origin_it) {
272 if (special_storage_policy_->IsStorageProtected(*origin_it))
273 continue;
274 if (!special_storage_policy_->IsStorageSessionOnly(*origin_it))
275 continue;
276 session_storage_database_->DeleteArea(*it, *origin_it);
277 }
278 }
231 } 279 }
232 } 280 }
233 281
282 void DomStorageContext::StartScavengingUnusedSessionStorage() {
283 if (session_storage_database_.get()) {
284 bool success = task_runner_->PostDelayedTask(
285 FROM_HERE, base::Bind(&DomStorageContext::FindUnusedNamespaces, this),
286 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
287 DCHECK(success);
288 }
289 }
290
291 void DomStorageContext::FindUnusedNamespaces() {
292 DCHECK(session_storage_database_.get());
michaeln 2012/07/10 19:04:13 Not quite as effective as in the Start method, but
marja 2012/07/11 12:41:31 Done.
293 scavenging_started_ = true;
294 std::set<std::string> namespace_ids_in_use;
295 for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
296 it != namespaces_.end(); ++it)
297 namespace_ids_in_use.insert(it->second->persistent_namespace_id());
298 std::set<std::string> protected_persistent_session_ids;
299 protected_persistent_session_ids.swap(protected_persistent_session_ids_);
300 bool success = task_runner_->PostShutdownBlockingTask(
301 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
302 base::Bind(
303 &DomStorageContext::FindUnusedNamespacesInCommitSequence,
304 this, namespace_ids_in_use, protected_persistent_session_ids));
305 DCHECK(success);
306 }
307
308 void DomStorageContext::FindUnusedNamespacesInCommitSequence(
309 const std::set<std::string>& namespace_ids_in_use,
310 const std::set<std::string>& protected_persistent_session_ids) {
311 DCHECK(session_storage_database_.get());
312 // Delete all namespaces which don't have an associated DomStorageNamespace
313 // alive.
314 std::vector<std::string> namespace_ids;
315 session_storage_database_->ReadNamespaceIds(&namespace_ids);
316 for (std::vector<std::string>::const_iterator it = namespace_ids.begin();
317 it != namespace_ids.end(); ++it) {
318 if (namespace_ids_in_use.find(*it) == namespace_ids_in_use.end() &&
319 protected_persistent_session_ids.find(*it) ==
320 protected_persistent_session_ids.end()) {
321 deletable_persistent_namespace_ids_.push_back(*it);
322 }
323 }
324 if (!deletable_persistent_namespace_ids_.empty()) {
325 bool success = task_runner_->PostDelayedTask(
326 FROM_HERE, base::Bind(
327 &DomStorageContext::DeleteNextUnusedNamespace,
328 this),
329 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
330 DCHECK(success);
331 }
332 }
333
334 void DomStorageContext::DeleteNextUnusedNamespace() {
335 if (is_shutdown_)
336 return;
337 bool success = task_runner_->PostShutdownBlockingTask(
338 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
339 base::Bind(
340 &DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence,
341 this));
342 DCHECK(success);
343 }
344
345 void DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence() {
346 const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
347 session_storage_database_->DeleteNamespace(persistent_id);
348 deletable_persistent_namespace_ids_.pop_back();
349 if (!deletable_persistent_namespace_ids_.empty()) {
350 bool success = task_runner_->PostDelayedTask(
351 FROM_HERE, base::Bind(
352 &DomStorageContext::DeleteNextUnusedNamespace,
353 this),
354 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
355 DCHECK(success);
356 }
357 }
358
234 } // namespace dom_storage 359 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698