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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |