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

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: Rebased. 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() {
michaeln 2012/07/10 01:16:58 any chance this can be called more than once? mayb
marja 2012/07/10 13:40:52 I moved reading the atm-in-use namespaces forward
283 if (session_storage_database_.get()) {
284 std::set<std::string> namespace_ids_in_use;
285 for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
286 it != namespaces_.end(); ++it)
287 namespace_ids_in_use.insert(it->second->persistent_namespace_id());
288 std::set<std::string> protected_persistent_session_ids;
289 protected_persistent_session_ids.swap(protected_persistent_session_ids_);
290 bool success = task_runner_->PostDelayedTask(
291 FROM_HERE, base::Bind(
292 &DomStorageContext::FindUnusedSessionStorage,
293 this, namespace_ids_in_use, protected_persistent_session_ids_),
michaeln 2012/07/10 01:16:58 you'll need to nix the _ on the protected_persiste
marja 2012/07/10 13:40:52 Done.
294 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
295 DCHECK(success);
296 scavenging_started_ = true;
297 }
298 }
299
300 void DomStorageContext::FindUnusedSessionStorage(
301 const std::set<std::string>& namespace_ids_in_use,
302 const std::set<std::string>& protected_persistent_session_ids) {
303 if (session_storage_database_.get()) {
304 bool success = task_runner_->PostShutdownBlockingTask(
305 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
306 base::Bind(
307 &DomStorageContext::FindUnusedSessionStorageInCommitSequence,
michaeln 2012/07/10 01:16:58 Is there a window of time between StartScavenging
marja 2012/07/10 13:40:52 This problem should be solved now, pls see above.
308 this, namespace_ids_in_use, protected_persistent_session_ids));
309 DCHECK(success);
310 }
311 }
312
313 void DomStorageContext::FindUnusedSessionStorageInCommitSequence(
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::DeleteNextUnunsedNamespace,
333 this),
334 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
335 DCHECK(success);
336 }
337 }
338
339 void DomStorageContext::DeleteNextUnunsedNamespace() {
340 if (is_shutdown_)
341 return;
342 bool success = task_runner_->PostShutdownBlockingTask(
343 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
344 base::Bind(&DomStorageContext::DeleteNextUnunsedNamespace,
345 this));
346 DCHECK(success);
347 }
348
349 void DomStorageContext::DeleteNextUnunsedNamespaceInCommitSequence() {
350 const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
351 session_storage_database_->DeleteNamespace(persistent_id);
352 deletable_persistent_namespace_ids_.pop_back();
353 if (!deletable_persistent_namespace_ids_.empty()) {
354 bool success = task_runner_->PostDelayedTask(
355 FROM_HERE, base::Bind(
356 &DomStorageContext::DeleteNextUnunsedNamespace,
357 this),
358 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
359 DCHECK(success);
360 }
361 }
362
234 } // namespace dom_storage 363 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698