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 |