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

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

Issue 9963107: Persist sessionStorage on disk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Code review (pkasting) Created 8 years, 4 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/session_storage_database.h" 5 #include "webkit/dom_storage/session_storage_database.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/stringprintf.h" 9 #include "base/stringprintf.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 SessionStorageDatabase::~SessionStorageDatabase() { 45 SessionStorageDatabase::~SessionStorageDatabase() {
46 } 46 }
47 47
48 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id, 48 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id,
49 const GURL& origin, 49 const GURL& origin,
50 ValuesMap* result) { 50 ValuesMap* result) {
51 // We don't create a database if it doesn't exist. In that case, there is 51 // We don't create a database if it doesn't exist. In that case, there is
52 // nothing to be added to the result. 52 // nothing to be added to the result.
53 if (!LazyOpen(false)) 53 if (!LazyOpen(false))
54 return; 54 return;
55
56 // While ReadAreaValues is in progress, another thread can call
57 // CommitAreaChanges. CommitAreaChanges might update map ref count key while
58 // this thread is iterating over the map ref count key. To protect the reading
59 // operation, create a snapshot and read from it.
60 leveldb::ReadOptions options;
61 options.snapshot = db_->GetSnapshot();
62
55 std::string map_id; 63 std::string map_id;
56 bool exists; 64 bool exists;
57 if (!GetMapForArea(namespace_id, origin.spec(), &exists, &map_id)) 65 if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) &&
58 return; 66 exists)
59 if (exists) 67 ReadMap(map_id, options, result, false);
60 ReadMap(map_id, result, false); 68 db_->ReleaseSnapshot(options.snapshot);
61 } 69 }
62 70
63 bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id, 71 bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id,
64 const GURL& origin, 72 const GURL& origin,
65 bool clear_all_first, 73 bool clear_all_first,
66 const ValuesMap& changes) { 74 const ValuesMap& changes) {
67 // Even if |changes| is empty, we need to write the appropriate placeholders 75 // Even if |changes| is empty, we need to write the appropriate placeholders
68 // in the database, so that it can be later shallow-copied succssfully. 76 // in the database, so that it can be later shallow-copied succssfully.
69 if (!LazyOpen(true)) 77 if (!LazyOpen(true))
70 return false; 78 return false;
71 79
72 leveldb::WriteBatch batch; 80 leveldb::WriteBatch batch;
73 // Ensure that the keys "namespace-" "namespace-N" (see the schema above) 81 // Ensure that the keys "namespace-" "namespace-N" (see the schema above)
74 // exist. 82 // exist.
75 const bool kOkIfExists = true; 83 const bool kOkIfExists = true;
76 if (!CreateNamespace(namespace_id, kOkIfExists, &batch)) 84 if (!CreateNamespace(namespace_id, kOkIfExists, &batch))
77 return false; 85 return false;
78 86
79 std::string map_id; 87 std::string map_id;
80 bool exists; 88 bool exists;
81 if (!GetMapForArea(namespace_id, origin.spec(), &exists, &map_id)) 89 if (!GetMapForArea(namespace_id, origin.spec(), leveldb::ReadOptions(),
90 &exists, &map_id))
82 return false; 91 return false;
83 if (exists) { 92 if (exists) {
84 int64 ref_count; 93 int64 ref_count;
85 if (!GetMapRefCount(map_id, &ref_count)) 94 if (!GetMapRefCount(map_id, &ref_count))
86 return false; 95 return false;
87 if (ref_count > 1) { 96 if (ref_count > 1) {
88 if (!DeepCopyArea(namespace_id, origin, !clear_all_first, 97 if (!DeepCopyArea(namespace_id, origin, !clear_all_first,
89 &map_id, &batch)) 98 &map_id, &batch))
90 return false; 99 return false;
91 } 100 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 } 194 }
186 195
187 bool SessionStorageDatabase::ReadNamespaceIds( 196 bool SessionStorageDatabase::ReadNamespaceIds(
188 std::vector<std::string>* namespace_ids) { 197 std::vector<std::string>* namespace_ids) {
189 if (!LazyOpen(true)) 198 if (!LazyOpen(true))
190 return false; 199 return false;
191 200
192 std::string namespace_prefix = NamespacePrefix(); 201 std::string namespace_prefix = NamespacePrefix();
193 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions())); 202 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
194 it->Seek(namespace_prefix); 203 it->Seek(namespace_prefix);
195 if (it->status().IsNotFound()) 204 // If the key is not found, the status of the iterator won't be IsNotFound(),
205 // but the iterator will be invalid.
206 if (!it->Valid())
196 return true; 207 return true;
197 208
198 if (!DatabaseErrorCheck(it->status().ok())) 209 if (!DatabaseErrorCheck(it->status().ok()))
199 return false; 210 return false;
200 211
201 // Skip the dummy entry "namespace-" and iterate the namespaces. 212 // Skip the dummy entry "namespace-" and iterate the namespaces.
202 std::string current_namespace_start_key; 213 std::string current_namespace_start_key;
203 for (it->Next(); it->Valid(); it->Next()) { 214 for (it->Next(); it->Valid(); it->Next()) {
204 std::string key = it->key().ToString(); 215 std::string key = it->key().ToString();
205 if (key.find(namespace_prefix) != 0) { 216 if (key.find(namespace_prefix) != 0) {
(...skipping 10 matching lines...) Expand all
216 // <namespaceid>. 227 // <namespaceid>.
217 current_namespace_start_key = key; 228 current_namespace_start_key = key;
218 namespace_ids->push_back( 229 namespace_ids->push_back(
219 key.substr(namespace_prefix.length(), 230 key.substr(namespace_prefix.length(),
220 key.length() - namespace_prefix.length() - 1)); 231 key.length() - namespace_prefix.length() - 1));
221 } 232 }
222 } 233 }
223 return true; 234 return true;
224 } 235 }
225 236
237 bool SessionStorageDatabase::ReadOriginsInNamespace(
238 const std::string& namespace_id, std::vector<GURL>* origins) {
239 std::map<std::string, std::string> areas;
240 if (!GetAreasInNamespace(namespace_id, &areas))
241 return false;
242 for (std::map<std::string, std::string>::const_iterator it = areas.begin();
243 it != areas.end(); ++it)
244 origins->push_back(GURL(it->first));
245 return true;
246 }
247
226 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) { 248 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
227 base::AutoLock auto_lock(db_lock_); 249 base::AutoLock auto_lock(db_lock_);
228 if (db_error_ || is_inconsistent_) { 250 if (db_error_ || is_inconsistent_) {
229 // Don't try to open a database that we know has failed already. 251 // Don't try to open a database that we know has failed already.
230 return false; 252 return false;
231 } 253 }
232 if (IsOpen()) 254 if (IsOpen())
233 return true; 255 return true;
234 256
235 if (!create_if_needed && 257 if (!create_if_needed &&
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 } 352 }
331 return CallerErrorCheck(ok_if_exists); 353 return CallerErrorCheck(ok_if_exists);
332 } 354 }
333 355
334 bool SessionStorageDatabase::GetAreasInNamespace( 356 bool SessionStorageDatabase::GetAreasInNamespace(
335 const std::string& namespace_id, 357 const std::string& namespace_id,
336 std::map<std::string, std::string>* areas) { 358 std::map<std::string, std::string>* areas) {
337 std::string namespace_start_key = NamespaceStartKey(namespace_id); 359 std::string namespace_start_key = NamespaceStartKey(namespace_id);
338 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions())); 360 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
339 it->Seek(namespace_start_key); 361 it->Seek(namespace_start_key);
340 if (it->status().IsNotFound()) { 362 // If the key is not found, the status of the iterator won't be IsNotFound(),
363 // but the iterator will be invalid.
364 if (!it->Valid()) {
341 // The namespace_start_key is not found when the namespace doesn't contain 365 // The namespace_start_key is not found when the namespace doesn't contain
342 // any areas. We don't need to do anything. 366 // any areas. We don't need to do anything.
343 return true; 367 return true;
344 } 368 }
345 if (!DatabaseErrorCheck(it->status().ok())) 369 if (!DatabaseErrorCheck(it->status().ok()))
346 return false; 370 return false;
347 371
348 // Skip the dummy entry "namespace-<namespaceid>-" and iterate the origins. 372 // Skip the dummy entry "namespace-<namespaceid>-" and iterate the origins.
349 for (it->Next(); it->Valid(); it->Next()) { 373 for (it->Next(); it->Valid(); it->Next()) {
350 std::string key = it->key().ToString(); 374 std::string key = it->key().ToString();
(...skipping 15 matching lines...) Expand all
366 std::string namespace_key = NamespaceKey(namespace_id, origin); 390 std::string namespace_key = NamespaceKey(namespace_id, origin);
367 batch->Put(namespace_key, map_id); 391 batch->Put(namespace_key, map_id);
368 } 392 }
369 393
370 bool SessionStorageDatabase::DeleteAreaHelper( 394 bool SessionStorageDatabase::DeleteAreaHelper(
371 const std::string& namespace_id, 395 const std::string& namespace_id,
372 const std::string& origin, 396 const std::string& origin,
373 leveldb::WriteBatch* batch) { 397 leveldb::WriteBatch* batch) {
374 std::string map_id; 398 std::string map_id;
375 bool exists; 399 bool exists;
376 if (!GetMapForArea(namespace_id, origin, &exists, &map_id)) 400 if (!GetMapForArea(namespace_id, origin, leveldb::ReadOptions(), &exists,
401 &map_id))
377 return false; 402 return false;
378 if (!exists) 403 if (!exists)
379 return true; // Nothing to delete. 404 return true; // Nothing to delete.
380 if (!DecreaseMapRefCount(map_id, 1, batch)) 405 if (!DecreaseMapRefCount(map_id, 1, batch))
381 return false; 406 return false;
382 std::string namespace_key = NamespaceKey(namespace_id, origin); 407 std::string namespace_key = NamespaceKey(namespace_id, origin);
383 batch->Delete(namespace_key); 408 batch->Delete(namespace_key);
384 return true; 409 return true;
385 } 410 }
386 411
387 bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id, 412 bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id,
388 const std::string& origin, 413 const std::string& origin,
414 const leveldb::ReadOptions& options,
389 bool* exists, std::string* map_id) { 415 bool* exists, std::string* map_id) {
390 std::string namespace_key = NamespaceKey(namespace_id, origin); 416 std::string namespace_key = NamespaceKey(namespace_id, origin);
391 leveldb::Status s = db_->Get(leveldb::ReadOptions(), namespace_key, map_id); 417 leveldb::Status s = db_->Get(options, namespace_key, map_id);
392 if (s.IsNotFound()) { 418 if (s.IsNotFound()) {
393 *exists = false; 419 *exists = false;
394 return true; 420 return true;
395 } 421 }
396 *exists = true; 422 *exists = true;
397 return DatabaseErrorCheck(s.ok()); 423 return DatabaseErrorCheck(s.ok());
398 } 424 }
399 425
400 bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id, 426 bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id,
401 const GURL& origin, 427 const GURL& origin,
(...skipping 12 matching lines...) Expand all
414 return false; 440 return false;
415 } 441 }
416 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id)); 442 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id));
417 std::string namespace_key = NamespaceKey(namespace_id, origin.spec()); 443 std::string namespace_key = NamespaceKey(namespace_id, origin.spec());
418 batch->Put(namespace_key, *map_id); 444 batch->Put(namespace_key, *map_id);
419 batch->Put(MapRefCountKey(*map_id), "1"); 445 batch->Put(MapRefCountKey(*map_id), "1");
420 return true; 446 return true;
421 } 447 }
422 448
423 bool SessionStorageDatabase::ReadMap(const std::string& map_id, 449 bool SessionStorageDatabase::ReadMap(const std::string& map_id,
450 const leveldb::ReadOptions& options,
424 ValuesMap* result, 451 ValuesMap* result,
425 bool only_keys) { 452 bool only_keys) {
426 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions())); 453 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
427 std::string map_start_key = MapRefCountKey(map_id); 454 std::string map_start_key = MapRefCountKey(map_id);
428 it->Seek(map_start_key); 455 it->Seek(map_start_key);
429 // The map needs to exist, otherwise we have a stale map_id in the database. 456 // If the key is not found, the status of the iterator won't be IsNotFound(),
430 if (!ConsistencyCheck(!it->status().IsNotFound())) 457 // but the iterator will be invalid. The map needs to exist, otherwise we have
458 // a stale map_id in the database.
459 if (!ConsistencyCheck(it->Valid()))
431 return false; 460 return false;
432 if (!DatabaseErrorCheck(it->status().ok())) 461 if (!DatabaseErrorCheck(it->status().ok()))
433 return false; 462 return false;
434 // Skip the dummy entry "map-<mapid>-". 463 // Skip the dummy entry "map-<mapid>-".
435 for (it->Next(); it->Valid(); it->Next()) { 464 for (it->Next(); it->Valid(); it->Next()) {
436 std::string key = it->key().ToString(); 465 std::string key = it->key().ToString();
437 if (key.find(map_start_key) != 0) { 466 if (key.find(map_start_key) != 0) {
438 // Iterated past the keys in this map. 467 // Iterated past the keys in this map.
439 break; 468 break;
440 } 469 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 if (!ClearMap(map_id, batch)) 540 if (!ClearMap(map_id, batch))
512 return false; 541 return false;
513 batch->Delete(MapRefCountKey(map_id)); 542 batch->Delete(MapRefCountKey(map_id));
514 } 543 }
515 return true; 544 return true;
516 } 545 }
517 546
518 bool SessionStorageDatabase::ClearMap(const std::string& map_id, 547 bool SessionStorageDatabase::ClearMap(const std::string& map_id,
519 leveldb::WriteBatch* batch) { 548 leveldb::WriteBatch* batch) {
520 ValuesMap values; 549 ValuesMap values;
521 if (!ReadMap(map_id, &values, true)) 550 if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true))
522 return false; 551 return false;
523 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it) 552 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it)
524 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first))); 553 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first)));
525 return true; 554 return true;
526 } 555 }
527 556
528 bool SessionStorageDatabase::DeepCopyArea( 557 bool SessionStorageDatabase::DeepCopyArea(
529 const std::string& namespace_id, const GURL& origin, bool copy_data, 558 const std::string& namespace_id, const GURL& origin, bool copy_data,
530 std::string* map_id, leveldb::WriteBatch* batch) { 559 std::string* map_id, leveldb::WriteBatch* batch) {
531 // Example, data before deep copy: 560 // Example, data before deep copy:
(...skipping 10 matching lines...) Expand all
542 // | namespace-2- | dummy | 571 // | namespace-2- | dummy |
543 // | namespace-2-origin1 | 2 (mapid) << references the new map 572 // | namespace-2-origin1 | 2 (mapid) << references the new map
544 // | map-1- | 1 (dec. refcount) | 573 // | map-1- | 1 (dec. refcount) |
545 // | map-1-a | b | 574 // | map-1-a | b |
546 // | map-2- | 1 (refcount) | 575 // | map-2- | 1 (refcount) |
547 // | map-2-a | b | 576 // | map-2-a | b |
548 577
549 // Read the values from the old map here. If we don't need to copy the data, 578 // Read the values from the old map here. If we don't need to copy the data,
550 // this can stay empty. 579 // this can stay empty.
551 ValuesMap values; 580 ValuesMap values;
552 if (copy_data && !ReadMap(*map_id, &values, false)) 581 if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false))
553 return false; 582 return false;
554 if (!DecreaseMapRefCount(*map_id, 1, batch)) 583 if (!DecreaseMapRefCount(*map_id, 1, batch))
555 return false; 584 return false;
556 // Create a new map (this will also break the association to the old map) and 585 // Create a new map (this will also break the association to the old map) and
557 // write the old data into it. This will write the id of the created map into 586 // write the old data into it. This will write the id of the created map into
558 // |map_id|. 587 // |map_id|.
559 if (!CreateMapForArea(namespace_id, origin, map_id, batch)) 588 if (!CreateMapForArea(namespace_id, origin, map_id, batch))
560 return false; 589 return false;
561 WriteValuesToMap(*map_id, values, batch); 590 WriteValuesToMap(*map_id, values, batch);
562 return true; 591 return true;
(...skipping 21 matching lines...) Expand all
584 std::string SessionStorageDatabase::MapKey(const std::string& map_id, 613 std::string SessionStorageDatabase::MapKey(const std::string& map_id,
585 const std::string& key) { 614 const std::string& key) {
586 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str()); 615 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str());
587 } 616 }
588 617
589 const char* SessionStorageDatabase::NextMapIdKey() { 618 const char* SessionStorageDatabase::NextMapIdKey() {
590 return "next-map-id"; 619 return "next-map-id";
591 } 620 }
592 621
593 } // namespace dom_storage 622 } // namespace dom_storage
OLDNEW
« no previous file with comments | « webkit/dom_storage/session_storage_database.h ('k') | webkit/dom_storage/session_storage_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698