Chromium Code Reviews| 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) { |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |