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

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 Created 8 years, 5 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 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 // <namespaceid>. 225 // <namespaceid>.
217 current_namespace_start_key = key; 226 current_namespace_start_key = key;
218 namespace_ids->push_back( 227 namespace_ids->push_back(
219 key.substr(namespace_prefix.length(), 228 key.substr(namespace_prefix.length(),
220 key.length() - namespace_prefix.length() - 1)); 229 key.length() - namespace_prefix.length() - 1));
221 } 230 }
222 } 231 }
223 return true; 232 return true;
224 } 233 }
225 234
235 bool SessionStorageDatabase::ReadOriginsInNamespace(
236 const std::string& namespace_id, std::vector<GURL>* origins) {
237 std::map<std::string, std::string> areas;
238 if (!GetAreasInNamespace(namespace_id, &areas))
239 return false;
240 for (std::map<std::string, std::string>::const_iterator it = areas.begin();
241 it != areas.end(); ++it)
242 origins->push_back(GURL(it->first));
243 return true;
244 }
245
226 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) { 246 bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
227 base::AutoLock auto_lock(db_lock_); 247 base::AutoLock auto_lock(db_lock_);
228 if (db_error_ || is_inconsistent_) { 248 if (db_error_ || is_inconsistent_) {
229 // Don't try to open a database that we know has failed already. 249 // Don't try to open a database that we know has failed already.
230 return false; 250 return false;
231 } 251 }
232 if (IsOpen()) 252 if (IsOpen())
233 return true; 253 return true;
234 254
235 if (!create_if_needed && 255 if (!create_if_needed &&
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 std::string namespace_key = NamespaceKey(namespace_id, origin); 386 std::string namespace_key = NamespaceKey(namespace_id, origin);
367 batch->Put(namespace_key, map_id); 387 batch->Put(namespace_key, map_id);
368 } 388 }
369 389
370 bool SessionStorageDatabase::DeleteAreaHelper( 390 bool SessionStorageDatabase::DeleteAreaHelper(
371 const std::string& namespace_id, 391 const std::string& namespace_id,
372 const std::string& origin, 392 const std::string& origin,
373 leveldb::WriteBatch* batch) { 393 leveldb::WriteBatch* batch) {
374 std::string map_id; 394 std::string map_id;
375 bool exists; 395 bool exists;
376 if (!GetMapForArea(namespace_id, origin, &exists, &map_id)) 396 if (!GetMapForArea(namespace_id, origin, leveldb::ReadOptions(), &exists,
397 &map_id))
377 return false; 398 return false;
378 if (!exists) 399 if (!exists)
379 return true; // Nothing to delete. 400 return true; // Nothing to delete.
380 if (!DecreaseMapRefCount(map_id, 1, batch)) 401 if (!DecreaseMapRefCount(map_id, 1, batch))
381 return false; 402 return false;
382 std::string namespace_key = NamespaceKey(namespace_id, origin); 403 std::string namespace_key = NamespaceKey(namespace_id, origin);
383 batch->Delete(namespace_key); 404 batch->Delete(namespace_key);
384 return true; 405 return true;
385 } 406 }
386 407
387 bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id, 408 bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id,
388 const std::string& origin, 409 const std::string& origin,
410 const leveldb::ReadOptions& options,
389 bool* exists, std::string* map_id) { 411 bool* exists, std::string* map_id) {
390 std::string namespace_key = NamespaceKey(namespace_id, origin); 412 std::string namespace_key = NamespaceKey(namespace_id, origin);
391 leveldb::Status s = db_->Get(leveldb::ReadOptions(), namespace_key, map_id); 413 leveldb::Status s = db_->Get(options, namespace_key, map_id);
392 if (s.IsNotFound()) { 414 if (s.IsNotFound()) {
393 *exists = false; 415 *exists = false;
394 return true; 416 return true;
395 } 417 }
396 *exists = true; 418 *exists = true;
397 return DatabaseErrorCheck(s.ok()); 419 return DatabaseErrorCheck(s.ok());
398 } 420 }
399 421
400 bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id, 422 bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id,
401 const GURL& origin, 423 const GURL& origin,
(...skipping 12 matching lines...) Expand all
414 return false; 436 return false;
415 } 437 }
416 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id)); 438 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id));
417 std::string namespace_key = NamespaceKey(namespace_id, origin.spec()); 439 std::string namespace_key = NamespaceKey(namespace_id, origin.spec());
418 batch->Put(namespace_key, *map_id); 440 batch->Put(namespace_key, *map_id);
419 batch->Put(MapRefCountKey(*map_id), "1"); 441 batch->Put(MapRefCountKey(*map_id), "1");
420 return true; 442 return true;
421 } 443 }
422 444
423 bool SessionStorageDatabase::ReadMap(const std::string& map_id, 445 bool SessionStorageDatabase::ReadMap(const std::string& map_id,
446 const leveldb::ReadOptions& options,
424 ValuesMap* result, 447 ValuesMap* result,
425 bool only_keys) { 448 bool only_keys) {
426 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions())); 449 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
427 std::string map_start_key = MapRefCountKey(map_id); 450 std::string map_start_key = MapRefCountKey(map_id);
428 it->Seek(map_start_key); 451 it->Seek(map_start_key);
429 // The map needs to exist, otherwise we have a stale map_id in the database. 452 // The map needs to exist, otherwise we have a stale map_id in the database.
430 if (!ConsistencyCheck(!it->status().IsNotFound())) 453 if (!ConsistencyCheck(!it->status().IsNotFound()))
431 return false; 454 return false;
432 if (!DatabaseErrorCheck(it->status().ok())) 455 if (!DatabaseErrorCheck(it->status().ok()))
433 return false; 456 return false;
434 // Skip the dummy entry "map-<mapid>-". 457 // Skip the dummy entry "map-<mapid>-".
435 for (it->Next(); it->Valid(); it->Next()) { 458 for (it->Next(); it->Valid(); it->Next()) {
436 std::string key = it->key().ToString(); 459 std::string key = it->key().ToString();
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 if (!ClearMap(map_id, batch)) 534 if (!ClearMap(map_id, batch))
512 return false; 535 return false;
513 batch->Delete(MapRefCountKey(map_id)); 536 batch->Delete(MapRefCountKey(map_id));
514 } 537 }
515 return true; 538 return true;
516 } 539 }
517 540
518 bool SessionStorageDatabase::ClearMap(const std::string& map_id, 541 bool SessionStorageDatabase::ClearMap(const std::string& map_id,
519 leveldb::WriteBatch* batch) { 542 leveldb::WriteBatch* batch) {
520 ValuesMap values; 543 ValuesMap values;
521 if (!ReadMap(map_id, &values, true)) 544 if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true))
522 return false; 545 return false;
523 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it) 546 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it)
524 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first))); 547 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first)));
525 return true; 548 return true;
526 } 549 }
527 550
528 bool SessionStorageDatabase::DeepCopyArea( 551 bool SessionStorageDatabase::DeepCopyArea(
529 const std::string& namespace_id, const GURL& origin, bool copy_data, 552 const std::string& namespace_id, const GURL& origin, bool copy_data,
530 std::string* map_id, leveldb::WriteBatch* batch) { 553 std::string* map_id, leveldb::WriteBatch* batch) {
531 // Example, data before deep copy: 554 // Example, data before deep copy:
(...skipping 10 matching lines...) Expand all
542 // | namespace-2- | dummy | 565 // | namespace-2- | dummy |
543 // | namespace-2-origin1 | 2 (mapid) << references the new map 566 // | namespace-2-origin1 | 2 (mapid) << references the new map
544 // | map-1- | 1 (dec. refcount) | 567 // | map-1- | 1 (dec. refcount) |
545 // | map-1-a | b | 568 // | map-1-a | b |
546 // | map-2- | 1 (refcount) | 569 // | map-2- | 1 (refcount) |
547 // | map-2-a | b | 570 // | map-2-a | b |
548 571
549 // Read the values from the old map here. If we don't need to copy the data, 572 // Read the values from the old map here. If we don't need to copy the data,
550 // this can stay empty. 573 // this can stay empty.
551 ValuesMap values; 574 ValuesMap values;
552 if (copy_data && !ReadMap(*map_id, &values, false)) 575 if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false))
553 return false; 576 return false;
554 if (!DecreaseMapRefCount(*map_id, 1, batch)) 577 if (!DecreaseMapRefCount(*map_id, 1, batch))
555 return false; 578 return false;
556 // Create a new map (this will also break the association to the old map) and 579 // 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 580 // write the old data into it. This will write the id of the created map into
558 // |map_id|. 581 // |map_id|.
559 if (!CreateMapForArea(namespace_id, origin, map_id, batch)) 582 if (!CreateMapForArea(namespace_id, origin, map_id, batch))
560 return false; 583 return false;
561 WriteValuesToMap(*map_id, values, batch); 584 WriteValuesToMap(*map_id, values, batch);
562 return true; 585 return true;
(...skipping 21 matching lines...) Expand all
584 std::string SessionStorageDatabase::MapKey(const std::string& map_id, 607 std::string SessionStorageDatabase::MapKey(const std::string& map_id,
585 const std::string& key) { 608 const std::string& key) {
586 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str()); 609 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str());
587 } 610 }
588 611
589 const char* SessionStorageDatabase::NextMapIdKey() { 612 const char* SessionStorageDatabase::NextMapIdKey() {
590 return "next-map-id"; 613 return "next-map-id";
591 } 614 }
592 615
593 } // namespace dom_storage 616 } // namespace dom_storage
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698