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

Side by Side Diff: webkit/dom_storage/dom_storage_context.cc

Issue 15990007: Move dom_storage to new locations. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "webkit/dom_storage/dom_storage_context.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/guid.h"
11 #include "base/location.h"
12 #include "base/time.h"
13 #include "webkit/browser/quota/special_storage_policy.h"
14 #include "webkit/dom_storage/dom_storage_area.h"
15 #include "webkit/dom_storage/dom_storage_database.h"
16 #include "webkit/dom_storage/dom_storage_namespace.h"
17 #include "webkit/dom_storage/dom_storage_task_runner.h"
18 #include "webkit/dom_storage/dom_storage_types.h"
19 #include "webkit/dom_storage/session_storage_database.h"
20
21 using file_util::FileEnumerator;
22
23 namespace dom_storage {
24
25 static const int kSessionStoraceScavengingSeconds = 60;
26
27 DomStorageContext::DomStorageContext(
28 const base::FilePath& localstorage_directory,
29 const base::FilePath& sessionstorage_directory,
30 quota::SpecialStoragePolicy* special_storage_policy,
31 DomStorageTaskRunner* task_runner)
32 : localstorage_directory_(localstorage_directory),
33 sessionstorage_directory_(sessionstorage_directory),
34 task_runner_(task_runner),
35 is_shutdown_(false),
36 force_keep_session_state_(false),
37 special_storage_policy_(special_storage_policy),
38 scavenging_started_(false) {
39 // AtomicSequenceNum starts at 0 but we want to start session
40 // namespace ids at one since zero is reserved for the
41 // kLocalStorageNamespaceId.
42 session_id_sequence_.GetNext();
43 }
44
45 DomStorageContext::~DomStorageContext() {
46 if (session_storage_database_.get()) {
47 // SessionStorageDatabase shouldn't be deleted right away: deleting it will
48 // potentially involve waiting in leveldb::DBImpl::~DBImpl, and waiting
49 // shouldn't happen on this thread.
50 SessionStorageDatabase* to_release = session_storage_database_.get();
51 to_release->AddRef();
52 session_storage_database_ = NULL;
53 task_runner_->PostShutdownBlockingTask(
54 FROM_HERE,
55 DomStorageTaskRunner::COMMIT_SEQUENCE,
56 base::Bind(&SessionStorageDatabase::Release,
57 base::Unretained(to_release)));
58 }
59 }
60
61 DomStorageNamespace* DomStorageContext::GetStorageNamespace(
62 int64 namespace_id) {
63 if (is_shutdown_)
64 return NULL;
65 StorageNamespaceMap::iterator found = namespaces_.find(namespace_id);
66 if (found == namespaces_.end()) {
67 if (namespace_id == kLocalStorageNamespaceId) {
68 if (!localstorage_directory_.empty()) {
69 if (!file_util::CreateDirectory(localstorage_directory_)) {
70 LOG(ERROR) << "Failed to create 'Local Storage' directory,"
71 " falling back to in-memory only.";
72 localstorage_directory_ = base::FilePath();
73 }
74 }
75 DomStorageNamespace* local =
76 new DomStorageNamespace(localstorage_directory_, task_runner_.get());
77 namespaces_[kLocalStorageNamespaceId] = local;
78 return local;
79 }
80 return NULL;
81 }
82 return found->second.get();
83 }
84
85 void DomStorageContext::GetLocalStorageUsage(
86 std::vector<LocalStorageUsageInfo>* infos,
87 bool include_file_info) {
88 if (localstorage_directory_.empty())
89 return;
90 FileEnumerator enumerator(localstorage_directory_, false,
91 FileEnumerator::FILES);
92 for (base::FilePath path = enumerator.Next(); !path.empty();
93 path = enumerator.Next()) {
94 if (path.MatchesExtension(DomStorageArea::kDatabaseFileExtension)) {
95 LocalStorageUsageInfo info;
96 info.origin = DomStorageArea::OriginFromDatabaseFileName(path);
97 if (include_file_info) {
98 FileEnumerator::FindInfo find_info;
99 enumerator.GetFindInfo(&find_info);
100 info.data_size = FileEnumerator::GetFilesize(find_info);
101 info.last_modified = FileEnumerator::GetLastModifiedTime(find_info);
102 }
103 infos->push_back(info);
104 }
105 }
106 }
107
108 void DomStorageContext::GetSessionStorageUsage(
109 std::vector<SessionStorageUsageInfo>* infos) {
110 if (!session_storage_database_.get())
111 return;
112 std::map<std::string, std::vector<GURL> > namespaces_and_origins;
113 session_storage_database_->ReadNamespacesAndOrigins(
114 &namespaces_and_origins);
115 for (std::map<std::string, std::vector<GURL> >::const_iterator it =
116 namespaces_and_origins.begin();
117 it != namespaces_and_origins.end(); ++it) {
118 for (std::vector<GURL>::const_iterator origin_it = it->second.begin();
119 origin_it != it->second.end(); ++origin_it) {
120 SessionStorageUsageInfo info;
121 info.persistent_namespace_id = it->first;
122 info.origin = *origin_it;
123 infos->push_back(info);
124 }
125 }
126 }
127
128 void DomStorageContext::DeleteLocalStorage(const GURL& origin) {
129 DCHECK(!is_shutdown_);
130 DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
131 local->DeleteLocalStorageOrigin(origin);
132 // Synthesize a 'cleared' event if the area is open so CachedAreas in
133 // renderers get emptied out too.
134 DomStorageArea* area = local->GetOpenStorageArea(origin);
135 if (area)
136 NotifyAreaCleared(area, origin);
137 }
138
139 void DomStorageContext::DeleteSessionStorage(
140 const SessionStorageUsageInfo& usage_info) {
141 DCHECK(!is_shutdown_);
142 DomStorageNamespace* dom_storage_namespace = NULL;
143 std::map<std::string, int64>::const_iterator it =
144 persistent_namespace_id_to_namespace_id_.find(
145 usage_info.persistent_namespace_id);
146 if (it != persistent_namespace_id_to_namespace_id_.end()) {
147 dom_storage_namespace = GetStorageNamespace(it->second);
148 } else {
149 int64 namespace_id = AllocateSessionId();
150 CreateSessionNamespace(namespace_id, usage_info.persistent_namespace_id);
151 dom_storage_namespace = GetStorageNamespace(namespace_id);
152 }
153 dom_storage_namespace->DeleteSessionStorageOrigin(usage_info.origin);
154 // Synthesize a 'cleared' event if the area is open so CachedAreas in
155 // renderers get emptied out too.
156 DomStorageArea* area =
157 dom_storage_namespace->GetOpenStorageArea(usage_info.origin);
158 if (area)
159 NotifyAreaCleared(area, usage_info.origin);
160 }
161
162 void DomStorageContext::PurgeMemory() {
163 // We can only purge memory from the local storage namespace
164 // which is backed by disk.
165 // TODO(marja): Purge sessionStorage, too. (Requires changes to the FastClear
166 // functionality.)
167 StorageNamespaceMap::iterator found =
168 namespaces_.find(kLocalStorageNamespaceId);
169 if (found != namespaces_.end())
170 found->second->PurgeMemory(DomStorageNamespace::PURGE_AGGRESSIVE);
171 }
172
173 void DomStorageContext::Shutdown() {
174 is_shutdown_ = true;
175 StorageNamespaceMap::const_iterator it = namespaces_.begin();
176 for (; it != namespaces_.end(); ++it)
177 it->second->Shutdown();
178
179 if (localstorage_directory_.empty() && !session_storage_database_.get())
180 return;
181
182 // Respect the content policy settings about what to
183 // keep and what to discard.
184 if (force_keep_session_state_)
185 return; // Keep everything.
186
187 bool has_session_only_origins =
188 special_storage_policy_.get() &&
189 special_storage_policy_->HasSessionOnlyOrigins();
190
191 if (has_session_only_origins) {
192 // We may have to delete something. We continue on the
193 // commit sequence after area shutdown tasks have cycled
194 // thru that sequence (and closed their database files).
195 bool success = task_runner_->PostShutdownBlockingTask(
196 FROM_HERE,
197 DomStorageTaskRunner::COMMIT_SEQUENCE,
198 base::Bind(&DomStorageContext::ClearSessionOnlyOrigins, this));
199 DCHECK(success);
200 }
201 }
202
203 void DomStorageContext::AddEventObserver(EventObserver* observer) {
204 event_observers_.AddObserver(observer);
205 }
206
207 void DomStorageContext::RemoveEventObserver(EventObserver* observer) {
208 event_observers_.RemoveObserver(observer);
209 }
210
211 void DomStorageContext::NotifyItemSet(
212 const DomStorageArea* area,
213 const base::string16& key,
214 const base::string16& new_value,
215 const NullableString16& old_value,
216 const GURL& page_url) {
217 FOR_EACH_OBSERVER(
218 EventObserver, event_observers_,
219 OnDomStorageItemSet(area, key, new_value, old_value, page_url));
220 }
221
222 void DomStorageContext::NotifyItemRemoved(
223 const DomStorageArea* area,
224 const base::string16& key,
225 const base::string16& old_value,
226 const GURL& page_url) {
227 FOR_EACH_OBSERVER(
228 EventObserver, event_observers_,
229 OnDomStorageItemRemoved(area, key, old_value, page_url));
230 }
231
232 void DomStorageContext::NotifyAreaCleared(
233 const DomStorageArea* area,
234 const GURL& page_url) {
235 FOR_EACH_OBSERVER(
236 EventObserver, event_observers_,
237 OnDomStorageAreaCleared(area, page_url));
238 }
239
240 std::string DomStorageContext::AllocatePersistentSessionId() {
241 std::string guid = base::GenerateGUID();
242 std::replace(guid.begin(), guid.end(), '-', '_');
243 return guid;
244 }
245
246 void DomStorageContext::CreateSessionNamespace(
247 int64 namespace_id,
248 const std::string& persistent_namespace_id) {
249 if (is_shutdown_)
250 return;
251 DCHECK(namespace_id != kLocalStorageNamespaceId);
252 DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
253 namespaces_[namespace_id] =
254 new DomStorageNamespace(namespace_id,
255 persistent_namespace_id,
256 session_storage_database_.get(),
257 task_runner_.get());
258 persistent_namespace_id_to_namespace_id_[persistent_namespace_id] =
259 namespace_id;
260 }
261
262 void DomStorageContext::DeleteSessionNamespace(
263 int64 namespace_id, bool should_persist_data) {
264 DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
265 StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
266 if (it == namespaces_.end())
267 return;
268 std::string persistent_namespace_id = it->second->persistent_namespace_id();
269 if (session_storage_database_.get()) {
270 if (!should_persist_data) {
271 task_runner_->PostShutdownBlockingTask(
272 FROM_HERE,
273 DomStorageTaskRunner::COMMIT_SEQUENCE,
274 base::Bind(
275 base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
276 session_storage_database_,
277 persistent_namespace_id));
278 } else {
279 // Ensure that the data gets committed before we shut down.
280 it->second->Shutdown();
281 if (!scavenging_started_) {
282 // Protect the persistent namespace ID from scavenging.
283 protected_persistent_session_ids_.insert(persistent_namespace_id);
284 }
285 }
286 }
287 persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
288 namespaces_.erase(namespace_id);
289 }
290
291 void DomStorageContext::CloneSessionNamespace(
292 int64 existing_id, int64 new_id,
293 const std::string& new_persistent_id) {
294 if (is_shutdown_)
295 return;
296 DCHECK_NE(kLocalStorageNamespaceId, existing_id);
297 DCHECK_NE(kLocalStorageNamespaceId, new_id);
298 StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
299 if (found != namespaces_.end())
300 namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id);
301 else
302 CreateSessionNamespace(new_id, new_persistent_id);
303 }
304
305 void DomStorageContext::ClearSessionOnlyOrigins() {
306 if (!localstorage_directory_.empty()) {
307 std::vector<LocalStorageUsageInfo> infos;
308 const bool kDontIncludeFileInfo = false;
309 GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
310 for (size_t i = 0; i < infos.size(); ++i) {
311 const GURL& origin = infos[i].origin;
312 if (special_storage_policy_->IsStorageProtected(origin))
313 continue;
314 if (!special_storage_policy_->IsStorageSessionOnly(origin))
315 continue;
316
317 const bool kNotRecursive = false;
318 base::FilePath database_file_path = localstorage_directory_.Append(
319 DomStorageArea::DatabaseFileNameFromOrigin(origin));
320 file_util::Delete(database_file_path, kNotRecursive);
321 file_util::Delete(
322 DomStorageDatabase::GetJournalFilePath(database_file_path),
323 kNotRecursive);
324 }
325 }
326 if (session_storage_database_.get()) {
327 std::vector<SessionStorageUsageInfo> infos;
328 GetSessionStorageUsage(&infos);
329 for (size_t i = 0; i < infos.size(); ++i) {
330 const GURL& origin = infos[i].origin;
331 if (special_storage_policy_->IsStorageProtected(origin))
332 continue;
333 if (!special_storage_policy_->IsStorageSessionOnly(origin))
334 continue;
335 session_storage_database_->DeleteArea(infos[i].persistent_namespace_id,
336 origin);
337 }
338 }
339 }
340
341 void DomStorageContext::SetSaveSessionStorageOnDisk() {
342 DCHECK(namespaces_.empty());
343 if (!sessionstorage_directory_.empty()) {
344 session_storage_database_ = new SessionStorageDatabase(
345 sessionstorage_directory_);
346 }
347 }
348
349 void DomStorageContext::StartScavengingUnusedSessionStorage() {
350 if (session_storage_database_.get()) {
351 task_runner_->PostDelayedTask(
352 FROM_HERE,
353 base::Bind(&DomStorageContext::FindUnusedNamespaces, this),
354 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
355 }
356 }
357
358 void DomStorageContext::FindUnusedNamespaces() {
359 DCHECK(session_storage_database_.get());
360 if (scavenging_started_)
361 return;
362 scavenging_started_ = true;
363 std::set<std::string> namespace_ids_in_use;
364 for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
365 it != namespaces_.end(); ++it)
366 namespace_ids_in_use.insert(it->second->persistent_namespace_id());
367 std::set<std::string> protected_persistent_session_ids;
368 protected_persistent_session_ids.swap(protected_persistent_session_ids_);
369 task_runner_->PostShutdownBlockingTask(
370 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
371 base::Bind(
372 &DomStorageContext::FindUnusedNamespacesInCommitSequence,
373 this, namespace_ids_in_use, protected_persistent_session_ids));
374 }
375
376 void DomStorageContext::FindUnusedNamespacesInCommitSequence(
377 const std::set<std::string>& namespace_ids_in_use,
378 const std::set<std::string>& protected_persistent_session_ids) {
379 DCHECK(session_storage_database_.get());
380 // Delete all namespaces which don't have an associated DomStorageNamespace
381 // alive.
382 std::map<std::string, std::vector<GURL> > namespaces_and_origins;
383 session_storage_database_->ReadNamespacesAndOrigins(&namespaces_and_origins);
384 for (std::map<std::string, std::vector<GURL> >::const_iterator it =
385 namespaces_and_origins.begin();
386 it != namespaces_and_origins.end(); ++it) {
387 if (namespace_ids_in_use.find(it->first) == namespace_ids_in_use.end() &&
388 protected_persistent_session_ids.find(it->first) ==
389 protected_persistent_session_ids.end()) {
390 deletable_persistent_namespace_ids_.push_back(it->first);
391 }
392 }
393 if (!deletable_persistent_namespace_ids_.empty()) {
394 task_runner_->PostDelayedTask(
395 FROM_HERE, base::Bind(
396 &DomStorageContext::DeleteNextUnusedNamespace,
397 this),
398 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
399 }
400 }
401
402 void DomStorageContext::DeleteNextUnusedNamespace() {
403 if (is_shutdown_)
404 return;
405 task_runner_->PostShutdownBlockingTask(
406 FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
407 base::Bind(
408 &DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence,
409 this));
410 }
411
412 void DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence() {
413 if (deletable_persistent_namespace_ids_.empty())
414 return;
415 const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
416 session_storage_database_->DeleteNamespace(persistent_id);
417 deletable_persistent_namespace_ids_.pop_back();
418 if (!deletable_persistent_namespace_ids_.empty()) {
419 task_runner_->PostDelayedTask(
420 FROM_HERE, base::Bind(
421 &DomStorageContext::DeleteNextUnusedNamespace,
422 this),
423 base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
424 }
425 }
426
427 } // namespace dom_storage
OLDNEW
« no previous file with comments | « webkit/dom_storage/dom_storage_context.h ('k') | webkit/dom_storage/dom_storage_context_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698