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 "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 Loading... |
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 Loading... |
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 if (session_storage_database_.get()) { |
| 209 std::string persistent_namespace_id = it->second->persistent_namespace_id(); |
| 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()); |
| 293 DCHECK(!scavenging_started_); |
| 294 scavenging_started_ = true; |
| 295 std::set<std::string> namespace_ids_in_use; |
| 296 for (StorageNamespaceMap::const_iterator it = namespaces_.begin(); |
| 297 it != namespaces_.end(); ++it) |
| 298 namespace_ids_in_use.insert(it->second->persistent_namespace_id()); |
| 299 std::set<std::string> protected_persistent_session_ids; |
| 300 protected_persistent_session_ids.swap(protected_persistent_session_ids_); |
| 301 bool success = task_runner_->PostShutdownBlockingTask( |
| 302 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE, |
| 303 base::Bind( |
| 304 &DomStorageContext::FindUnusedNamespacesInCommitSequence, |
| 305 this, namespace_ids_in_use, protected_persistent_session_ids)); |
| 306 DCHECK(success); |
| 307 } |
| 308 |
| 309 void DomStorageContext::FindUnusedNamespacesInCommitSequence( |
| 310 const std::set<std::string>& namespace_ids_in_use, |
| 311 const std::set<std::string>& protected_persistent_session_ids) { |
| 312 DCHECK(session_storage_database_.get()); |
| 313 // Delete all namespaces which don't have an associated DomStorageNamespace |
| 314 // alive. |
| 315 std::vector<std::string> namespace_ids; |
| 316 session_storage_database_->ReadNamespaceIds(&namespace_ids); |
| 317 for (std::vector<std::string>::const_iterator it = namespace_ids.begin(); |
| 318 it != namespace_ids.end(); ++it) { |
| 319 if (namespace_ids_in_use.find(*it) == namespace_ids_in_use.end() && |
| 320 protected_persistent_session_ids.find(*it) == |
| 321 protected_persistent_session_ids.end()) { |
| 322 deletable_persistent_namespace_ids_.push_back(*it); |
| 323 } |
| 324 } |
| 325 if (!deletable_persistent_namespace_ids_.empty()) { |
| 326 bool success = task_runner_->PostDelayedTask( |
| 327 FROM_HERE, base::Bind( |
| 328 &DomStorageContext::DeleteNextUnusedNamespace, |
| 329 this), |
| 330 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds)); |
| 331 DCHECK(success); |
| 332 } |
| 333 } |
| 334 |
| 335 void DomStorageContext::DeleteNextUnusedNamespace() { |
| 336 if (is_shutdown_) |
| 337 return; |
| 338 bool success = task_runner_->PostShutdownBlockingTask( |
| 339 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE, |
| 340 base::Bind( |
| 341 &DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence, |
| 342 this)); |
| 343 DCHECK(success); |
| 344 } |
| 345 |
| 346 void DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence() { |
| 347 const std::string& persistent_id = deletable_persistent_namespace_ids_.back(); |
| 348 session_storage_database_->DeleteNamespace(persistent_id); |
| 349 deletable_persistent_namespace_ids_.pop_back(); |
| 350 if (!deletable_persistent_namespace_ids_.empty()) { |
| 351 bool success = task_runner_->PostDelayedTask( |
| 352 FROM_HERE, base::Bind( |
| 353 &DomStorageContext::DeleteNextUnusedNamespace, |
| 354 this), |
| 355 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds)); |
| 356 DCHECK(success); |
| 357 } |
| 358 } |
| 359 |
234 } // namespace dom_storage | 360 } // namespace dom_storage |
OLD | NEW |