| 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/browser/dom_storage/session_storage_database.h" | 5 #include "content/browser/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/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "third_party/leveldatabase/src/include/leveldb/db.h" | 13 #include "third_party/leveldatabase/src/include/leveldb/db.h" |
| 14 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | 14 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" |
| 15 #include "third_party/leveldatabase/src/include/leveldb/options.h" | 15 #include "third_party/leveldatabase/src/include/leveldb/options.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 42 // | namespace-1-origin1 | 1 (mapid) | | 42 // | namespace-1-origin1 | 1 (mapid) | |
| 43 // | namespace-1-origin2 | 2 | | 43 // | namespace-1-origin2 | 2 | |
| 44 // | namespace-2- | dummy | | 44 // | namespace-2- | dummy | |
| 45 // | namespace-2-origin1 | 1 (shallow copy) | | 45 // | namespace-2-origin1 | 1 (shallow copy) | |
| 46 // | namespace-2-origin2 | 2 (shallow copy) | | 46 // | namespace-2-origin2 | 2 (shallow copy) | |
| 47 // | namespace-3- | dummy | | 47 // | namespace-3- | dummy | |
| 48 // | namespace-3-origin1 | 3 (deep copy) | | 48 // | namespace-3-origin1 | 3 (deep copy) | |
| 49 // | namespace-3-origin2 | 2 (shallow copy) | | 49 // | namespace-3-origin2 | 2 (shallow copy) | |
| 50 // | next-map-id | 4 | | 50 // | next-map-id | 4 | |
| 51 | 51 |
| 52 namespace dom_storage { | 52 namespace content { |
| 53 | 53 |
| 54 SessionStorageDatabase::SessionStorageDatabase(const base::FilePath& file_path) | 54 SessionStorageDatabase::SessionStorageDatabase(const base::FilePath& file_path) |
| 55 : file_path_(file_path), | 55 : file_path_(file_path), |
| 56 db_error_(false), | 56 db_error_(false), |
| 57 is_inconsistent_(false) { | 57 is_inconsistent_(false) { |
| 58 } | 58 } |
| 59 | 59 |
| 60 SessionStorageDatabase::~SessionStorageDatabase() { | 60 SessionStorageDatabase::~SessionStorageDatabase() { |
| 61 } | 61 } |
| 62 | 62 |
| 63 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id, | 63 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id, |
| 64 const GURL& origin, | 64 const GURL& origin, |
| 65 ValuesMap* result) { | 65 DOMStorageValuesMap* result) { |
| 66 // We don't create a database if it doesn't exist. In that case, there is | 66 // We don't create a database if it doesn't exist. In that case, there is |
| 67 // nothing to be added to the result. | 67 // nothing to be added to the result. |
| 68 if (!LazyOpen(false)) | 68 if (!LazyOpen(false)) |
| 69 return; | 69 return; |
| 70 | 70 |
| 71 // While ReadAreaValues is in progress, another thread can call | 71 // While ReadAreaValues is in progress, another thread can call |
| 72 // CommitAreaChanges. CommitAreaChanges might update map ref count key while | 72 // CommitAreaChanges. CommitAreaChanges might update map ref count key while |
| 73 // this thread is iterating over the map ref count key. To protect the reading | 73 // this thread is iterating over the map ref count key. To protect the reading |
| 74 // operation, create a snapshot and read from it. | 74 // operation, create a snapshot and read from it. |
| 75 leveldb::ReadOptions options; | 75 leveldb::ReadOptions options; |
| 76 options.snapshot = db_->GetSnapshot(); | 76 options.snapshot = db_->GetSnapshot(); |
| 77 | 77 |
| 78 std::string map_id; | 78 std::string map_id; |
| 79 bool exists; | 79 bool exists; |
| 80 if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) && | 80 if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) && |
| 81 exists) | 81 exists) |
| 82 ReadMap(map_id, options, result, false); | 82 ReadMap(map_id, options, result, false); |
| 83 db_->ReleaseSnapshot(options.snapshot); | 83 db_->ReleaseSnapshot(options.snapshot); |
| 84 } | 84 } |
| 85 | 85 |
| 86 bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id, | 86 bool SessionStorageDatabase::CommitAreaChanges( |
| 87 const GURL& origin, | 87 const std::string& namespace_id, |
| 88 bool clear_all_first, | 88 const GURL& origin, |
| 89 const ValuesMap& changes) { | 89 bool clear_all_first, |
| 90 const DOMStorageValuesMap& changes) { |
| 90 // Even if |changes| is empty, we need to write the appropriate placeholders | 91 // Even if |changes| is empty, we need to write the appropriate placeholders |
| 91 // in the database, so that it can be later shallow-copied succssfully. | 92 // in the database, so that it can be later shallow-copied succssfully. |
| 92 if (!LazyOpen(true)) | 93 if (!LazyOpen(true)) |
| 93 return false; | 94 return false; |
| 94 | 95 |
| 95 leveldb::WriteBatch batch; | 96 leveldb::WriteBatch batch; |
| 96 // Ensure that the keys "namespace-" "namespace-N" (see the schema above) | 97 // Ensure that the keys "namespace-" "namespace-N" (see the schema above) |
| 97 // exist. | 98 // exist. |
| 98 const bool kOkIfExists = true; | 99 const bool kOkIfExists = true; |
| 99 if (!CreateNamespace(namespace_id, kOkIfExists, &batch)) | 100 if (!CreateNamespace(namespace_id, kOkIfExists, &batch)) |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 } | 496 } |
| 496 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id)); | 497 batch->Put(next_map_id_key, base::Int64ToString(++next_map_id)); |
| 497 std::string namespace_key = NamespaceKey(namespace_id, origin.spec()); | 498 std::string namespace_key = NamespaceKey(namespace_id, origin.spec()); |
| 498 batch->Put(namespace_key, *map_id); | 499 batch->Put(namespace_key, *map_id); |
| 499 batch->Put(MapRefCountKey(*map_id), "1"); | 500 batch->Put(MapRefCountKey(*map_id), "1"); |
| 500 return true; | 501 return true; |
| 501 } | 502 } |
| 502 | 503 |
| 503 bool SessionStorageDatabase::ReadMap(const std::string& map_id, | 504 bool SessionStorageDatabase::ReadMap(const std::string& map_id, |
| 504 const leveldb::ReadOptions& options, | 505 const leveldb::ReadOptions& options, |
| 505 ValuesMap* result, | 506 DOMStorageValuesMap* result, |
| 506 bool only_keys) { | 507 bool only_keys) { |
| 507 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); | 508 scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options)); |
| 508 std::string map_start_key = MapRefCountKey(map_id); | 509 std::string map_start_key = MapRefCountKey(map_id); |
| 509 it->Seek(map_start_key); | 510 it->Seek(map_start_key); |
| 510 // If the key is not found, the status of the iterator won't be IsNotFound(), | 511 // If the key is not found, the status of the iterator won't be IsNotFound(), |
| 511 // but the iterator will be invalid. The map needs to exist, otherwise we have | 512 // but the iterator will be invalid. The map needs to exist, otherwise we have |
| 512 // a stale map_id in the database. | 513 // a stale map_id in the database. |
| 513 if (!ConsistencyCheck(it->Valid())) | 514 if (!ConsistencyCheck(it->Valid())) |
| 514 return false; | 515 return false; |
| 515 if (!DatabaseErrorCheck(it->status().ok())) | 516 if (!DatabaseErrorCheck(it->status().ok())) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 532 const char16* data_ptr = | 533 const char16* data_ptr = |
| 533 reinterpret_cast<const char16*>(it->value().data()); | 534 reinterpret_cast<const char16*>(it->value().data()); |
| 534 (*result)[key16] = | 535 (*result)[key16] = |
| 535 base::NullableString16(base::string16(data_ptr, len), false); | 536 base::NullableString16(base::string16(data_ptr, len), false); |
| 536 } | 537 } |
| 537 } | 538 } |
| 538 return true; | 539 return true; |
| 539 } | 540 } |
| 540 | 541 |
| 541 void SessionStorageDatabase::WriteValuesToMap(const std::string& map_id, | 542 void SessionStorageDatabase::WriteValuesToMap(const std::string& map_id, |
| 542 const ValuesMap& values, | 543 const DOMStorageValuesMap& values, |
| 543 leveldb::WriteBatch* batch) { | 544 leveldb::WriteBatch* batch) { |
| 544 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); | 545 for (DOMStorageValuesMap::const_iterator it = values.begin(); |
| 546 it != values.end(); |
| 545 ++it) { | 547 ++it) { |
| 546 base::NullableString16 value = it->second; | 548 base::NullableString16 value = it->second; |
| 547 std::string key = MapKey(map_id, UTF16ToUTF8(it->first)); | 549 std::string key = MapKey(map_id, UTF16ToUTF8(it->first)); |
| 548 if (value.is_null()) { | 550 if (value.is_null()) { |
| 549 batch->Delete(key); | 551 batch->Delete(key); |
| 550 } else { | 552 } else { |
| 551 // Convert the raw data stored in base::string16 to raw data stored in | 553 // Convert the raw data stored in base::string16 to raw data stored in |
| 552 // std::string. | 554 // std::string. |
| 553 const char* data = reinterpret_cast<const char*>(value.string().data()); | 555 const char* data = reinterpret_cast<const char*>(value.string().data()); |
| 554 size_t size = value.string().size() * 2; | 556 size_t size = value.string().size() * 2; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 594 // Clear all keys in the map. | 596 // Clear all keys in the map. |
| 595 if (!ClearMap(map_id, batch)) | 597 if (!ClearMap(map_id, batch)) |
| 596 return false; | 598 return false; |
| 597 batch->Delete(MapRefCountKey(map_id)); | 599 batch->Delete(MapRefCountKey(map_id)); |
| 598 } | 600 } |
| 599 return true; | 601 return true; |
| 600 } | 602 } |
| 601 | 603 |
| 602 bool SessionStorageDatabase::ClearMap(const std::string& map_id, | 604 bool SessionStorageDatabase::ClearMap(const std::string& map_id, |
| 603 leveldb::WriteBatch* batch) { | 605 leveldb::WriteBatch* batch) { |
| 604 ValuesMap values; | 606 DOMStorageValuesMap values; |
| 605 if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true)) | 607 if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true)) |
| 606 return false; | 608 return false; |
| 607 for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it) | 609 for (DOMStorageValuesMap::const_iterator it = values.begin(); |
| 610 it != values.end(); ++it) |
| 608 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first))); | 611 batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first))); |
| 609 return true; | 612 return true; |
| 610 } | 613 } |
| 611 | 614 |
| 612 bool SessionStorageDatabase::DeepCopyArea( | 615 bool SessionStorageDatabase::DeepCopyArea( |
| 613 const std::string& namespace_id, const GURL& origin, bool copy_data, | 616 const std::string& namespace_id, const GURL& origin, bool copy_data, |
| 614 std::string* map_id, leveldb::WriteBatch* batch) { | 617 std::string* map_id, leveldb::WriteBatch* batch) { |
| 615 // Example, data before deep copy: | 618 // Example, data before deep copy: |
| 616 // | namespace-1- (1 = namespace id)| dummy | | 619 // | namespace-1- (1 = namespace id)| dummy | |
| 617 // | namespace-1-origin1 | 1 (mapid) | | 620 // | namespace-1-origin1 | 1 (mapid) | |
| 618 // | namespace-2- | dummy | | 621 // | namespace-2- | dummy | |
| 619 // | namespace-2-origin1 | 1 (mapid) << references the same map | 622 // | namespace-2-origin1 | 1 (mapid) << references the same map |
| 620 // | map-1- | 2 (refcount) | | 623 // | map-1- | 2 (refcount) | |
| 621 // | map-1-a | b | | 624 // | map-1-a | b | |
| 622 | 625 |
| 623 // Example, data after deep copy copy: | 626 // Example, data after deep copy copy: |
| 624 // | namespace-1-(1 = namespace id) | dummy | | 627 // | namespace-1-(1 = namespace id) | dummy | |
| 625 // | namespace-1-origin1 | 1 (mapid) | | 628 // | namespace-1-origin1 | 1 (mapid) | |
| 626 // | namespace-2- | dummy | | 629 // | namespace-2- | dummy | |
| 627 // | namespace-2-origin1 | 2 (mapid) << references the new map | 630 // | namespace-2-origin1 | 2 (mapid) << references the new map |
| 628 // | map-1- | 1 (dec. refcount) | | 631 // | map-1- | 1 (dec. refcount) | |
| 629 // | map-1-a | b | | 632 // | map-1-a | b | |
| 630 // | map-2- | 1 (refcount) | | 633 // | map-2- | 1 (refcount) | |
| 631 // | map-2-a | b | | 634 // | map-2-a | b | |
| 632 | 635 |
| 633 // Read the values from the old map here. If we don't need to copy the data, | 636 // Read the values from the old map here. If we don't need to copy the data, |
| 634 // this can stay empty. | 637 // this can stay empty. |
| 635 ValuesMap values; | 638 DOMStorageValuesMap values; |
| 636 if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false)) | 639 if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false)) |
| 637 return false; | 640 return false; |
| 638 if (!DecreaseMapRefCount(*map_id, 1, batch)) | 641 if (!DecreaseMapRefCount(*map_id, 1, batch)) |
| 639 return false; | 642 return false; |
| 640 // Create a new map (this will also break the association to the old map) and | 643 // Create a new map (this will also break the association to the old map) and |
| 641 // write the old data into it. This will write the id of the created map into | 644 // write the old data into it. This will write the id of the created map into |
| 642 // |map_id|. | 645 // |map_id|. |
| 643 if (!CreateMapForArea(namespace_id, origin, map_id, batch)) | 646 if (!CreateMapForArea(namespace_id, origin, map_id, batch)) |
| 644 return false; | 647 return false; |
| 645 WriteValuesToMap(*map_id, values, batch); | 648 WriteValuesToMap(*map_id, values, batch); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 667 | 670 |
| 668 std::string SessionStorageDatabase::MapKey(const std::string& map_id, | 671 std::string SessionStorageDatabase::MapKey(const std::string& map_id, |
| 669 const std::string& key) { | 672 const std::string& key) { |
| 670 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str()); | 673 return base::StringPrintf("map-%s-%s", map_id.c_str(), key.c_str()); |
| 671 } | 674 } |
| 672 | 675 |
| 673 const char* SessionStorageDatabase::NextMapIdKey() { | 676 const char* SessionStorageDatabase::NextMapIdKey() { |
| 674 return "next-map-id"; | 677 return "next-map-id"; |
| 675 } | 678 } |
| 676 | 679 |
| 677 } // namespace dom_storage | 680 } // namespace content |
| OLD | NEW |