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

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

Powered by Google App Engine
This is Rietveld 408576698