| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |