Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 | |
| 7 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 8 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 9 #include "base/format_macros.h" | 11 #include "base/format_macros.h" |
| 10 #include "base/json/json_reader.h" | 12 #include "base/json/json_reader.h" |
| 11 #include "base/json/json_writer.h" | 13 #include "base/json/json_writer.h" |
| 12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 13 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 14 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| (...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 | 551 |
| 550 PutVarInt(leveldb_transaction, key, blob_key_generator_current_number); | 552 PutVarInt(leveldb_transaction, key, blob_key_generator_current_number); |
| 551 return true; | 553 return true; |
| 552 } | 554 } |
| 553 | 555 |
| 554 // TODO(ericu): Error recovery. If we persistently can't read the | 556 // TODO(ericu): Error recovery. If we persistently can't read the |
| 555 // blob journal, the safe thing to do is to clear it and leak the blobs, | 557 // blob journal, the safe thing to do is to clear it and leak the blobs, |
| 556 // though that may be costly. Still, database/directory deletion should always | 558 // though that may be costly. Still, database/directory deletion should always |
| 557 // clean things up, and we can write an fsck that will do a full correction if | 559 // clean things up, and we can write an fsck that will do a full correction if |
| 558 // need be. | 560 // need be. |
| 559 template <typename T> | 561 |
| 560 static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key, | 562 // Read and decode the specified blob journal via the supplied transaction. |
| 561 T* leveldb_transaction, | 563 // The key must be either the primary journal key or live journal key. |
| 564 template <typename TransactionType> | |
| 565 static leveldb::Status GetBlobJournal(const StringPiece& key, | |
| 566 TransactionType* transaction, | |
| 562 BlobJournalType* journal) { | 567 BlobJournalType* journal) { |
| 563 std::string data; | 568 std::string data; |
| 564 bool found = false; | 569 bool found = false; |
| 565 leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found); | 570 leveldb::Status s = transaction->Get(key, &data, &found); |
| 566 if (!s.ok()) { | 571 if (!s.ok()) { |
| 567 INTERNAL_READ_ERROR(READ_BLOB_JOURNAL); | 572 INTERNAL_READ_ERROR(READ_BLOB_JOURNAL); |
| 568 return s; | 573 return s; |
| 569 } | 574 } |
| 570 journal->clear(); | 575 journal->clear(); |
| 571 if (!found || !data.size()) | 576 if (!found || !data.size()) |
| 572 return leveldb::Status::OK(); | 577 return leveldb::Status::OK(); |
| 573 StringPiece slice(data); | 578 StringPiece slice(data); |
| 574 if (!DecodeBlobJournal(&slice, journal)) { | 579 if (!DecodeBlobJournal(&slice, journal)) { |
| 575 INTERNAL_CONSISTENCY_ERROR_UNTESTED(DECODE_BLOB_JOURNAL); | 580 INTERNAL_CONSISTENCY_ERROR_UNTESTED(DECODE_BLOB_JOURNAL); |
| 576 s = InternalInconsistencyStatus(); | 581 s = InternalInconsistencyStatus(); |
| 577 } | 582 } |
| 578 return s; | 583 return s; |
| 579 } | 584 } |
| 580 | 585 |
| 581 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, | 586 template <typename TransactionType> |
| 582 const std::string& level_db_key) { | 587 static leveldb::Status GetPrimaryBlobJournal(TransactionType* transaction, |
| 583 leveldb_transaction->Remove(level_db_key); | 588 BlobJournalType* journal) { |
| 589 return GetBlobJournal(BlobJournalKey::Encode(), transaction, journal); | |
| 584 } | 590 } |
| 585 | 591 |
| 586 static void UpdatePrimaryJournalWithBlobList( | 592 template <typename TransactionType> |
| 587 LevelDBTransaction* leveldb_transaction, | 593 static leveldb::Status GetLiveBlobJournal(TransactionType* transaction, |
| 588 const BlobJournalType& journal) { | 594 BlobJournalType* journal) { |
| 589 const std::string leveldb_key = BlobJournalKey::Encode(); | 595 return GetBlobJournal(LiveBlobJournalKey::Encode(), transaction, journal); |
| 596 } | |
| 597 | |
| 598 // Clear the specified blob journal via the supplied transaction. | |
| 599 // The key must be either the primary journal key or live journal key. | |
| 600 template <typename TransactionType> | |
| 601 static void ClearBlobJournal(TransactionType* transaction, | |
| 602 const std::string& key) { | |
| 603 transaction->Remove(key); | |
| 604 } | |
| 605 | |
| 606 // Overwrite the specified blob journal via the supplied transaction. | |
| 607 // The key must be either the primary journal key or live journal key. | |
| 608 template <typename TransactionType> | |
| 609 static void UpdateBlobJournal(TransactionType* transaction, | |
| 610 const std::string& key, | |
| 611 const BlobJournalType& journal) { | |
| 590 std::string data; | 612 std::string data; |
| 591 EncodeBlobJournal(journal, &data); | 613 EncodeBlobJournal(journal, &data); |
| 592 leveldb_transaction->Put(leveldb_key, &data); | 614 transaction->Put(key, &data); |
| 593 } | 615 } |
| 594 | 616 |
| 595 static void UpdateLiveBlobJournalWithBlobList( | 617 template <typename TransactionType> |
| 596 LevelDBTransaction* leveldb_transaction, | 618 static void UpdatePrimaryBlobJournal(TransactionType* transaction, |
| 597 const BlobJournalType& journal) { | 619 const BlobJournalType& journal) { |
| 598 const std::string leveldb_key = LiveBlobJournalKey::Encode(); | 620 UpdateBlobJournal(transaction, BlobJournalKey::Encode(), journal); |
| 599 std::string data; | |
| 600 EncodeBlobJournal(journal, &data); | |
| 601 leveldb_transaction->Put(leveldb_key, &data); | |
| 602 } | 621 } |
| 603 | 622 |
| 604 static leveldb::Status MergeBlobsIntoLiveBlobJournal( | 623 template <typename TransactionType> |
| 605 LevelDBTransaction* leveldb_transaction, | 624 static void UpdateLiveBlobJournal(TransactionType* transaction, |
| 625 const BlobJournalType& journal) { | |
| 626 UpdateBlobJournal(transaction, LiveBlobJournalKey::Encode(), journal); | |
| 627 } | |
| 628 | |
| 629 // Append blobs to the specified blob journal via the supplied transaction. | |
| 630 // The key must be either the primary journal key or live journal key. | |
| 631 template <typename TransactionType> | |
| 632 static leveldb::Status AppendBlobsToBlobJournal( | |
| 633 TransactionType* transaction, | |
| 634 const std::string& key, | |
| 606 const BlobJournalType& journal) { | 635 const BlobJournalType& journal) { |
| 636 if (!journal.size()) | |
|
cmumford
2015/01/22 00:56:57
Nit: if (journal.empty()) reads much better.
jsbell
2015/01/22 19:40:45
Fixed here and other blob places.
| |
| 637 return leveldb::Status::OK(); | |
| 607 BlobJournalType old_journal; | 638 BlobJournalType old_journal; |
| 608 const std::string key = LiveBlobJournalKey::Encode(); | 639 leveldb::Status s = GetBlobJournal(key, transaction, &old_journal); |
| 609 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal); | |
| 610 if (!s.ok()) | 640 if (!s.ok()) |
| 611 return s; | 641 return s; |
| 612 | |
| 613 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); | 642 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); |
| 614 | 643 UpdateBlobJournal(transaction, key, old_journal); |
| 615 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); | |
| 616 return leveldb::Status::OK(); | 644 return leveldb::Status::OK(); |
| 617 } | 645 } |
| 618 | 646 |
| 619 static void UpdateBlobJournalWithDatabase( | 647 template <typename TransactionType> |
| 648 static leveldb::Status AppendBlobsToPrimaryBlobJournal( | |
| 649 TransactionType* transaction, | |
| 650 const BlobJournalType& journal) { | |
| 651 return AppendBlobsToBlobJournal(transaction, BlobJournalKey::Encode(), | |
| 652 journal); | |
| 653 } | |
| 654 | |
| 655 template <typename TransactionType> | |
| 656 static leveldb::Status AppendBlobsToLiveBlobJournal( | |
| 657 TransactionType* transaction, | |
| 658 const BlobJournalType& journal) { | |
| 659 BlobJournalType old_journal; | |
|
cmumford
2015/01/22 00:56:57
Do we still need "old_journal"?
jsbell
2015/01/22 19:40:45
Nope - removed.
| |
| 660 return AppendBlobsToBlobJournal(transaction, LiveBlobJournalKey::Encode(), | |
| 661 journal); | |
| 662 } | |
| 663 | |
| 664 // Append a database to the specified blob journal via the supplied transaction. | |
| 665 // The key must be either the primary journal key or live journal key. | |
| 666 static leveldb::Status MergeDatabaseIntoBlobJournal( | |
| 667 LevelDBDirectTransaction* transaction, | |
| 668 const std::string& key, | |
| 669 int64 database_id) { | |
| 670 BlobJournalType journal; | |
| 671 leveldb::Status s = GetBlobJournal(key, transaction, &journal); | |
| 672 if (!s.ok()) | |
| 673 return s; | |
| 674 journal.push_back( | |
| 675 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 676 UpdateBlobJournal(transaction, key, journal); | |
| 677 return leveldb::Status::OK(); | |
| 678 } | |
| 679 | |
| 680 static leveldb::Status MergeDatabaseIntoPrimaryBlobJournal( | |
| 620 LevelDBDirectTransaction* leveldb_transaction, | 681 LevelDBDirectTransaction* leveldb_transaction, |
| 621 int64 database_id) { | 682 int64 database_id) { |
| 622 BlobJournalType journal; | 683 return MergeDatabaseIntoBlobJournal(leveldb_transaction, |
| 623 journal.push_back( | 684 BlobJournalKey::Encode(), database_id); |
| 624 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 625 const std::string key = BlobJournalKey::Encode(); | |
| 626 std::string data; | |
| 627 EncodeBlobJournal(journal, &data); | |
| 628 leveldb_transaction->Put(key, &data); | |
| 629 } | 685 } |
| 630 | 686 |
| 631 static leveldb::Status MergeDatabaseIntoLiveBlobJournal( | 687 static leveldb::Status MergeDatabaseIntoLiveBlobJournal( |
| 632 LevelDBDirectTransaction* leveldb_transaction, | 688 LevelDBDirectTransaction* leveldb_transaction, |
| 633 int64 database_id) { | 689 int64 database_id) { |
| 634 BlobJournalType journal; | 690 return MergeDatabaseIntoBlobJournal( |
| 635 const std::string key = LiveBlobJournalKey::Encode(); | 691 leveldb_transaction, LiveBlobJournalKey::Encode(), database_id); |
| 636 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal); | |
| 637 if (!s.ok()) | |
| 638 return s; | |
| 639 journal.push_back( | |
| 640 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 641 std::string data; | |
| 642 EncodeBlobJournal(journal, &data); | |
| 643 leveldb_transaction->Put(key, &data); | |
| 644 return leveldb::Status::OK(); | |
| 645 } | 692 } |
| 646 | 693 |
| 647 // Blob Data is encoded as a series of: | 694 // Blob Data is encoded as a series of: |
| 648 // { is_file [bool], key [int64 as varInt], | 695 // { is_file [bool], key [int64 as varInt], |
| 649 // type [string-with-length, may be empty], | 696 // type [string-with-length, may be empty], |
| 650 // (for Blobs only) size [int64 as varInt] | 697 // (for Blobs only) size [int64 as varInt] |
| 651 // (for Files only) fileName [string-with-length] | 698 // (for Files only) fileName [string-with-length] |
| 652 // } | 699 // } |
| 653 // There is no length field; just read until you run out of data. | 700 // There is no length field; just read until you run out of data. |
| 654 static std::string EncodeBlobData( | 701 static std::string EncodeBlobData( |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 709 scoped_ptr<LevelDBComparator> comparator, | 756 scoped_ptr<LevelDBComparator> comparator, |
| 710 base::SequencedTaskRunner* task_runner) | 757 base::SequencedTaskRunner* task_runner) |
| 711 : indexed_db_factory_(indexed_db_factory), | 758 : indexed_db_factory_(indexed_db_factory), |
| 712 origin_url_(origin_url), | 759 origin_url_(origin_url), |
| 713 blob_path_(blob_path), | 760 blob_path_(blob_path), |
| 714 origin_identifier_(ComputeOriginIdentifier(origin_url)), | 761 origin_identifier_(ComputeOriginIdentifier(origin_url)), |
| 715 request_context_(request_context), | 762 request_context_(request_context), |
| 716 task_runner_(task_runner), | 763 task_runner_(task_runner), |
| 717 db_(db.Pass()), | 764 db_(db.Pass()), |
| 718 comparator_(comparator.Pass()), | 765 comparator_(comparator.Pass()), |
| 719 active_blob_registry_(this) { | 766 active_blob_registry_(this), |
| 767 committing_transaction_count_(0) { | |
| 720 } | 768 } |
| 721 | 769 |
| 722 IndexedDBBackingStore::~IndexedDBBackingStore() { | 770 IndexedDBBackingStore::~IndexedDBBackingStore() { |
| 723 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { | 771 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { |
| 724 ChildProcessSecurityPolicyImpl* policy = | 772 ChildProcessSecurityPolicyImpl* policy = |
| 725 ChildProcessSecurityPolicyImpl::GetInstance(); | 773 ChildProcessSecurityPolicyImpl::GetInstance(); |
| 726 for (const auto& pid : child_process_ids_granted_) | 774 for (const auto& pid : child_process_ids_granted_) |
| 727 policy->RevokeAllPermissionsForFile(pid, blob_path_); | 775 policy->RevokeAllPermissionsForFile(pid, blob_path_); |
| 728 } | 776 } |
| 729 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), | 777 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), |
| (...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1407 transaction, database_id, object_store_id, start_key, stop_key, true); | 1455 transaction, database_id, object_store_id, start_key, stop_key, true); |
| 1408 } | 1456 } |
| 1409 | 1457 |
| 1410 leveldb::Status IndexedDBBackingStore::DeleteDatabase( | 1458 leveldb::Status IndexedDBBackingStore::DeleteDatabase( |
| 1411 const base::string16& name) { | 1459 const base::string16& name) { |
| 1412 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); | 1460 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); |
| 1413 scoped_ptr<LevelDBDirectTransaction> transaction = | 1461 scoped_ptr<LevelDBDirectTransaction> transaction = |
| 1414 LevelDBDirectTransaction::Create(db_.get()); | 1462 LevelDBDirectTransaction::Create(db_.get()); |
| 1415 | 1463 |
| 1416 leveldb::Status s; | 1464 leveldb::Status s; |
| 1417 s = CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 1418 if (!s.ok()) | |
| 1419 return s; | |
| 1420 | 1465 |
| 1421 IndexedDBDatabaseMetadata metadata; | 1466 IndexedDBDatabaseMetadata metadata; |
| 1422 bool success = false; | 1467 bool success = false; |
| 1423 s = GetIDBDatabaseMetaData(name, &metadata, &success); | 1468 s = GetIDBDatabaseMetaData(name, &metadata, &success); |
| 1424 if (!s.ok()) | 1469 if (!s.ok()) |
| 1425 return s; | 1470 return s; |
| 1426 if (!success) | 1471 if (!success) |
| 1427 return leveldb::Status::OK(); | 1472 return leveldb::Status::OK(); |
| 1428 | 1473 |
| 1429 const std::string start_key = DatabaseMetaDataKey::Encode( | 1474 const std::string start_key = DatabaseMetaDataKey::Encode( |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1443 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); | 1488 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); |
| 1444 transaction->Remove(key); | 1489 transaction->Remove(key); |
| 1445 | 1490 |
| 1446 bool need_cleanup = false; | 1491 bool need_cleanup = false; |
| 1447 if (active_blob_registry()->MarkDeletedCheckIfUsed( | 1492 if (active_blob_registry()->MarkDeletedCheckIfUsed( |
| 1448 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { | 1493 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { |
| 1449 s = MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id); | 1494 s = MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id); |
| 1450 if (!s.ok()) | 1495 if (!s.ok()) |
| 1451 return s; | 1496 return s; |
| 1452 } else { | 1497 } else { |
| 1453 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); | 1498 s = MergeDatabaseIntoPrimaryBlobJournal(transaction.get(), metadata.id); |
| 1499 if (!s.ok()) | |
| 1500 return s; | |
| 1454 need_cleanup = true; | 1501 need_cleanup = true; |
| 1455 } | 1502 } |
| 1456 | 1503 |
| 1457 s = transaction->Commit(); | 1504 s = transaction->Commit(); |
| 1458 if (!s.ok()) { | 1505 if (!s.ok()) { |
| 1459 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); | 1506 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); |
| 1460 return s; | 1507 return s; |
| 1461 } | 1508 } |
| 1462 | 1509 |
| 1510 // If another transaction is running, this will defer processing | |
| 1511 // the journal until completion. | |
| 1463 if (need_cleanup) | 1512 if (need_cleanup) |
| 1464 CleanUpBlobJournal(BlobJournalKey::Encode()); | 1513 CleanPrimaryJournalIgnoreReturn(); |
| 1465 | 1514 |
| 1466 db_->Compact(start_key, stop_key); | 1515 db_->Compact(start_key, stop_key); |
| 1467 return s; | 1516 return s; |
| 1468 } | 1517 } |
| 1469 | 1518 |
| 1470 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1519 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
| 1471 const std::string& stop_key, | 1520 const std::string& stop_key, |
| 1472 int64 object_store_id, | 1521 int64 object_store_id, |
| 1473 int64 meta_data_type) { | 1522 int64 meta_data_type) { |
| 1474 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1523 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| (...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2422 } | 2471 } |
| 2423 | 2472 |
| 2424 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, | 2473 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, |
| 2425 int64 blob_key) { | 2474 int64 blob_key) { |
| 2426 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | 2475 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
| 2427 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; | 2476 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; |
| 2428 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | 2477 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); |
| 2429 scoped_refptr<LevelDBTransaction> transaction = | 2478 scoped_refptr<LevelDBTransaction> transaction = |
| 2430 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); | 2479 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); |
| 2431 | 2480 |
| 2432 std::string live_blob_key = LiveBlobJournalKey::Encode(); | 2481 BlobJournalType live_blob_journal, primary_journal; |
| 2433 BlobJournalType live_blob_journal; | 2482 if (!GetLiveBlobJournal(transaction.get(), &live_blob_journal).ok()) |
| 2434 if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal) | |
| 2435 .ok()) | |
| 2436 return; | 2483 return; |
| 2437 DCHECK(live_blob_journal.size()); | 2484 DCHECK(live_blob_journal.size()); |
| 2438 | 2485 if (!GetPrimaryBlobJournal(transaction.get(), &primary_journal).ok()) |
| 2439 std::string primary_key = BlobJournalKey::Encode(); | |
| 2440 BlobJournalType primary_journal; | |
| 2441 if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok()) | |
| 2442 return; | 2486 return; |
| 2443 | 2487 |
| 2444 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to | 2488 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to |
| 2445 // remove all entries with database_id from the live_blob journal and add only | 2489 // remove all entries with database_id from the live_blob journal and add only |
| 2446 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) | 2490 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) |
| 2447 // and we hit kAllBlobsKey for the right database_id in the journal, we leave | 2491 // and we hit kAllBlobsKey for the right database_id in the journal, we leave |
| 2448 // the kAllBlobsKey entry in the live_blob journal but add the specific blob | 2492 // the kAllBlobsKey entry in the live_blob journal but add the specific blob |
| 2449 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a | 2493 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a |
| 2450 // matching (database_id, blob_key) tuple, we should move it to the primary | 2494 // matching (database_id, blob_key) tuple, we should move it to the primary |
| 2451 // journal. | 2495 // journal. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2472 break; | 2516 break; |
| 2473 } | 2517 } |
| 2474 } else { | 2518 } else { |
| 2475 new_live_blob_journal.push_back(*journal_iter); | 2519 new_live_blob_journal.push_back(*journal_iter); |
| 2476 } | 2520 } |
| 2477 } | 2521 } |
| 2478 if (all_blobs) { | 2522 if (all_blobs) { |
| 2479 primary_journal.push_back( | 2523 primary_journal.push_back( |
| 2480 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | 2524 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); |
| 2481 } | 2525 } |
| 2482 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); | 2526 UpdatePrimaryBlobJournal(transaction.get(), primary_journal); |
| 2483 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); | 2527 UpdateLiveBlobJournal(transaction.get(), new_live_blob_journal); |
| 2484 transaction->Commit(); | 2528 transaction->Commit(); |
| 2485 // We could just do the deletions/cleaning here, but if there are a lot of | 2529 // We could just do the deletions/cleaning here, but if there are a lot of |
| 2486 // blobs about to be garbage collected, it'd be better to wait and do them all | 2530 // blobs about to be garbage collected, it'd be better to wait and do them all |
| 2487 // at once. | 2531 // at once. |
| 2488 StartJournalCleaningTimer(); | 2532 StartJournalCleaningTimer(); |
| 2489 } | 2533 } |
| 2490 | 2534 |
| 2491 // The this reference is a raw pointer that's declared Unretained inside the | 2535 // The this reference is a raw pointer that's declared Unretained inside the |
| 2492 // timer code, so this won't confuse IndexedDBFactory's check for | 2536 // timer code, so this won't confuse IndexedDBFactory's check for |
| 2493 // HasLastBackingStoreReference. It's safe because if the backing store is | 2537 // HasLastBackingStoreReference. It's safe because if the backing store is |
| 2494 // deleted, the timer will automatically be canceled on destruction. | 2538 // deleted, the timer will automatically be canceled on destruction. |
| 2495 void IndexedDBBackingStore::StartJournalCleaningTimer() { | 2539 void IndexedDBBackingStore::StartJournalCleaningTimer() { |
| 2496 journal_cleaning_timer_.Start( | 2540 journal_cleaning_timer_.Start( |
| 2497 FROM_HERE, | 2541 FROM_HERE, |
| 2498 base::TimeDelta::FromSeconds(5), | 2542 base::TimeDelta::FromSeconds(5), |
| 2499 this, | 2543 this, |
| 2500 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); | 2544 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); |
| 2501 } | 2545 } |
| 2502 | 2546 |
| 2503 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | 2547 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. |
| 2504 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { | 2548 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, |
| 2549 int64 key) const { | |
| 2505 return GetBlobFileNameForKey(blob_path_, database_id, key); | 2550 return GetBlobFileNameForKey(blob_path_, database_id, key); |
| 2506 } | 2551 } |
| 2507 | 2552 |
| 2508 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2553 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
| 2509 const std::string& stop_key, | 2554 const std::string& stop_key, |
| 2510 int64 index_id, | 2555 int64 index_id, |
| 2511 unsigned char meta_data_type) { | 2556 unsigned char meta_data_type) { |
| 2512 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2557 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| 2513 return false; | 2558 return false; |
| 2514 | 2559 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2614 (*indexes)[index_id] = IndexedDBIndexMetadata( | 2659 (*indexes)[index_id] = IndexedDBIndexMetadata( |
| 2615 index_name, index_id, key_path, index_unique, index_multi_entry); | 2660 index_name, index_id, key_path, index_unique, index_multi_entry); |
| 2616 } | 2661 } |
| 2617 | 2662 |
| 2618 if (!s.ok()) | 2663 if (!s.ok()) |
| 2619 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); | 2664 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); |
| 2620 | 2665 |
| 2621 return s; | 2666 return s; |
| 2622 } | 2667 } |
| 2623 | 2668 |
| 2624 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | 2669 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) const { |
| 2625 FilePath fileName = GetBlobFileName(database_id, key); | 2670 FilePath fileName = GetBlobFileName(database_id, key); |
| 2626 return base::DeleteFile(fileName, false); | 2671 return base::DeleteFile(fileName, false); |
| 2627 } | 2672 } |
| 2628 | 2673 |
| 2629 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | 2674 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) const { |
| 2630 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); | 2675 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); |
| 2631 return base::DeleteFile(dirName, true); | 2676 return base::DeleteFile(dirName, true); |
| 2632 } | 2677 } |
| 2633 | 2678 |
| 2634 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal( | 2679 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournalEntries( |
| 2635 const std::string& level_db_key) { | 2680 const BlobJournalType& journal) const { |
| 2636 scoped_refptr<LevelDBTransaction> journal_transaction = | |
| 2637 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); | |
| 2638 BlobJournalType journal; | |
| 2639 leveldb::Status s = | |
| 2640 GetBlobJournal(level_db_key, journal_transaction.get(), &journal); | |
| 2641 if (!s.ok()) | |
| 2642 return s; | |
| 2643 if (!journal.size()) | 2681 if (!journal.size()) |
| 2644 return leveldb::Status::OK(); | 2682 return leveldb::Status::OK(); |
| 2645 for (const auto& entry : journal) { | 2683 for (const auto& entry : journal) { |
| 2646 int64 database_id = entry.first; | 2684 int64 database_id = entry.first; |
| 2647 int64 blob_key = entry.second; | 2685 int64 blob_key = entry.second; |
| 2648 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | 2686 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
| 2649 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { | 2687 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { |
| 2650 if (!RemoveBlobDirectory(database_id)) | 2688 if (!RemoveBlobDirectory(database_id)) |
| 2651 return IOErrorStatus(); | 2689 return IOErrorStatus(); |
| 2652 } else { | 2690 } else { |
| 2653 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | 2691 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); |
| 2654 if (!RemoveBlobFile(database_id, blob_key)) | 2692 if (!RemoveBlobFile(database_id, blob_key)) |
| 2655 return IOErrorStatus(); | 2693 return IOErrorStatus(); |
| 2656 } | 2694 } |
| 2657 } | 2695 } |
| 2696 return leveldb::Status::OK(); | |
| 2697 } | |
| 2698 | |
| 2699 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal( | |
| 2700 const std::string& level_db_key) const { | |
| 2701 DCHECK(!committing_transaction_count_); | |
| 2702 leveldb::Status s; | |
| 2703 scoped_refptr<LevelDBTransaction> journal_transaction = | |
| 2704 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); | |
| 2705 BlobJournalType journal; | |
| 2706 | |
| 2707 s = GetBlobJournal(level_db_key, journal_transaction.get(), &journal); | |
| 2708 if (!s.ok()) | |
| 2709 return s; | |
| 2710 if (!journal.size()) | |
| 2711 return leveldb::Status::OK(); | |
| 2712 s = CleanUpBlobJournalEntries(journal); | |
| 2713 if (!s.ok()) | |
| 2714 return s; | |
| 2658 ClearBlobJournal(journal_transaction.get(), level_db_key); | 2715 ClearBlobJournal(journal_transaction.get(), level_db_key); |
| 2659 return journal_transaction->Commit(); | 2716 return journal_transaction->Commit(); |
| 2660 } | 2717 } |
| 2661 | 2718 |
| 2662 leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord( | 2719 leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord( |
| 2663 int64 database_id, | 2720 int64 database_id, |
| 2664 const std::string& object_store_data_key, | 2721 const std::string& object_store_data_key, |
| 2665 IndexedDBValue* value) { | 2722 IndexedDBValue* value) { |
| 2666 BlobChangeRecord* change_record = NULL; | 2723 BlobChangeRecord* change_record = NULL; |
| 2667 BlobChangeMap::const_iterator blob_iter = | 2724 BlobChangeMap::const_iterator blob_iter = |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2716 entry.set_last_modified(info.last_modified); | 2773 entry.set_last_modified(info.last_modified); |
| 2717 entry.set_size(info.size); | 2774 entry.set_size(info.size); |
| 2718 } | 2775 } |
| 2719 } | 2776 } |
| 2720 } | 2777 } |
| 2721 } | 2778 } |
| 2722 return leveldb::Status::OK(); | 2779 return leveldb::Status::OK(); |
| 2723 } | 2780 } |
| 2724 | 2781 |
| 2725 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { | 2782 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { |
| 2726 CleanUpBlobJournal(BlobJournalKey::Encode()); | 2783 // While a transaction is busy it is not safe to clean the journal. |
| 2784 if (committing_transaction_count_ > 0) | |
| 2785 StartJournalCleaningTimer(); | |
| 2786 else | |
| 2787 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 2727 } | 2788 } |
| 2728 | 2789 |
| 2729 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2790 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
| 2730 LevelDBTransaction* transaction, | 2791 LevelDBTransaction* transaction, |
| 2731 int64 database_id, | 2792 int64 database_id, |
| 2732 int64 object_store_id, | 2793 int64 object_store_id, |
| 2733 int64 index_id) { | 2794 int64 index_id) { |
| 2734 int64 max_index_id = -1; | 2795 int64 max_index_id = -1; |
| 2735 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2796 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
| 2736 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2797 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
| (...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3875 scoped_ptr<IndexCursorImpl> cursor( | 3936 scoped_ptr<IndexCursorImpl> cursor( |
| 3876 new IndexCursorImpl(this, transaction, database_id, cursor_options)); | 3937 new IndexCursorImpl(this, transaction, database_id, cursor_options)); |
| 3877 if (!cursor->FirstSeek(s)) | 3938 if (!cursor->FirstSeek(s)) |
| 3878 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3939 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
| 3879 | 3940 |
| 3880 return cursor.Pass(); | 3941 return cursor.Pass(); |
| 3881 } | 3942 } |
| 3882 | 3943 |
| 3883 IndexedDBBackingStore::Transaction::Transaction( | 3944 IndexedDBBackingStore::Transaction::Transaction( |
| 3884 IndexedDBBackingStore* backing_store) | 3945 IndexedDBBackingStore* backing_store) |
| 3885 : backing_store_(backing_store), database_id_(-1) { | 3946 : backing_store_(backing_store), database_id_(-1), committing_(false) { |
| 3886 } | 3947 } |
| 3887 | 3948 |
| 3888 IndexedDBBackingStore::Transaction::~Transaction() { | 3949 IndexedDBBackingStore::Transaction::~Transaction() { |
| 3889 STLDeleteContainerPairSecondPointers( | 3950 STLDeleteContainerPairSecondPointers( |
| 3890 blob_change_map_.begin(), blob_change_map_.end()); | 3951 blob_change_map_.begin(), blob_change_map_.end()); |
| 3891 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), | 3952 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), |
| 3892 incognito_blob_map_.end()); | 3953 incognito_blob_map_.end()); |
| 3954 DCHECK(!committing_); | |
| 3893 } | 3955 } |
| 3894 | 3956 |
| 3895 void IndexedDBBackingStore::Transaction::Begin() { | 3957 void IndexedDBBackingStore::Transaction::Begin() { |
| 3896 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); | 3958 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); |
| 3897 DCHECK(!transaction_.get()); | 3959 DCHECK(!transaction_.get()); |
| 3898 transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction( | 3960 transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction( |
| 3899 backing_store_->db_.get()); | 3961 backing_store_->db_.get()); |
| 3900 | 3962 |
| 3901 // If incognito, this snapshots blobs just as the above transaction_ | 3963 // If incognito, this snapshots blobs just as the above transaction_ |
| 3902 // constructor snapshots the leveldb. | 3964 // constructor snapshots the leveldb. |
| 3903 for (const auto& iter : backing_store_->incognito_blob_map_) | 3965 for (const auto& iter : backing_store_->incognito_blob_map_) |
| 3904 incognito_blob_map_[iter.first] = iter.second->Clone().release(); | 3966 incognito_blob_map_[iter.first] = iter.second->Clone().release(); |
| 3905 } | 3967 } |
| 3906 | 3968 |
| 3907 static GURL getURLFromUUID(const string& uuid) { | 3969 static GURL getURLFromUUID(const string& uuid) { |
| 3908 return GURL("blob:uuid/" + uuid); | 3970 return GURL("blob:uuid/" + uuid); |
| 3909 } | 3971 } |
| 3910 | 3972 |
| 3911 leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( | 3973 leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( |
| 3912 BlobEntryKeyValuePairVec* new_blob_entries, | 3974 BlobEntryKeyValuePairVec* new_blob_entries, |
| 3913 WriteDescriptorVec* new_files_to_write) { | 3975 WriteDescriptorVec* new_files_to_write) { |
| 3914 if (backing_store_->is_incognito()) | 3976 if (backing_store_->is_incognito()) |
| 3915 return leveldb::Status::OK(); | 3977 return leveldb::Status::OK(); |
| 3916 | 3978 |
| 3917 new_blob_entries->clear(); | 3979 DCHECK(new_blob_entries->empty()); |
| 3918 new_files_to_write->clear(); | 3980 DCHECK(new_files_to_write->empty()); |
| 3919 if (!blob_change_map_.empty()) { | 3981 DCHECK(blobs_to_write_.empty()); |
| 3920 // Create LevelDBTransaction for the name generator seed and add-journal. | 3982 |
| 3921 scoped_refptr<LevelDBTransaction> pre_transaction = | 3983 if (blob_change_map_.empty()) |
| 3922 IndexedDBClassFactory::Get()->CreateLevelDBTransaction( | 3984 return leveldb::Status::OK(); |
| 3923 backing_store_->db_.get()); | 3985 |
| 3924 BlobJournalType journal; | 3986 // Create LevelDBTransaction for the name generator seed and add-journal. |
| 3925 for (auto& iter : blob_change_map_) { | 3987 scoped_refptr<LevelDBTransaction> pre_transaction = |
| 3926 std::vector<IndexedDBBlobInfo*> new_blob_keys; | 3988 IndexedDBClassFactory::Get()->CreateLevelDBTransaction( |
| 3927 for (auto& entry : iter.second->mutable_blob_info()) { | 3989 backing_store_->db_.get()); |
| 3928 int64 next_blob_key = -1; | 3990 |
| 3929 bool result = GetBlobKeyGeneratorCurrentNumber( | 3991 for (auto& iter : blob_change_map_) { |
| 3930 pre_transaction.get(), database_id_, &next_blob_key); | 3992 std::vector<IndexedDBBlobInfo*> new_blob_keys; |
| 3931 if (!result || next_blob_key < 0) | 3993 for (auto& entry : iter.second->mutable_blob_info()) { |
| 3932 return InternalInconsistencyStatus(); | 3994 int64 next_blob_key = -1; |
| 3933 BlobJournalEntryType journal_entry = | 3995 bool result = GetBlobKeyGeneratorCurrentNumber( |
| 3934 std::make_pair(database_id_, next_blob_key); | 3996 pre_transaction.get(), database_id_, &next_blob_key); |
| 3935 journal.push_back(journal_entry); | 3997 if (!result || next_blob_key < 0) |
| 3936 if (entry.is_file() && !entry.file_path().empty()) { | 3998 return InternalInconsistencyStatus(); |
| 3937 new_files_to_write->push_back( | 3999 BlobJournalEntryType journal_entry = |
| 3938 WriteDescriptor(entry.file_path(), | 4000 std::make_pair(database_id_, next_blob_key); |
| 3939 next_blob_key, | 4001 blobs_to_write_.push_back(journal_entry); |
|
cmumford
2015/01/22 00:56:57
Nit: Do you even need the journal_entry variable?
jsbell
2015/01/22 19:40:45
Nope - just made it inline.
| |
| 3940 entry.size(), | 4002 if (entry.is_file() && !entry.file_path().empty()) { |
| 3941 entry.last_modified())); | 4003 new_files_to_write->push_back( |
| 3942 } else { | 4004 WriteDescriptor(entry.file_path(), next_blob_key, entry.size(), |
| 3943 new_files_to_write->push_back( | 4005 entry.last_modified())); |
| 3944 WriteDescriptor(getURLFromUUID(entry.uuid()), | 4006 } else { |
| 3945 next_blob_key, | 4007 new_files_to_write->push_back( |
| 3946 entry.size(), | 4008 WriteDescriptor(getURLFromUUID(entry.uuid()), next_blob_key, |
| 3947 entry.last_modified())); | 4009 entry.size(), entry.last_modified())); |
| 3948 } | |
| 3949 entry.set_key(next_blob_key); | |
| 3950 new_blob_keys.push_back(&entry); | |
| 3951 result = UpdateBlobKeyGeneratorCurrentNumber( | |
| 3952 pre_transaction.get(), database_id_, next_blob_key + 1); | |
| 3953 if (!result) | |
| 3954 return InternalInconsistencyStatus(); | |
| 3955 } | 4010 } |
| 3956 BlobEntryKey blob_entry_key; | 4011 entry.set_key(next_blob_key); |
| 3957 StringPiece key_piece(iter.second->key()); | 4012 new_blob_keys.push_back(&entry); |
| 3958 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | 4013 result = UpdateBlobKeyGeneratorCurrentNumber( |
| 3959 NOTREACHED(); | 4014 pre_transaction.get(), database_id_, next_blob_key + 1); |
| 4015 if (!result) | |
| 3960 return InternalInconsistencyStatus(); | 4016 return InternalInconsistencyStatus(); |
| 3961 } | |
| 3962 new_blob_entries->push_back( | |
| 3963 std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys))); | |
| 3964 } | 4017 } |
| 3965 UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal); | 4018 BlobEntryKey blob_entry_key; |
| 3966 leveldb::Status s = pre_transaction->Commit(); | 4019 StringPiece key_piece(iter.second->key()); |
| 3967 if (!s.ok()) | 4020 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { |
| 4021 NOTREACHED(); | |
| 3968 return InternalInconsistencyStatus(); | 4022 return InternalInconsistencyStatus(); |
| 4023 } | |
| 4024 new_blob_entries->push_back( | |
| 4025 std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys))); | |
| 3969 } | 4026 } |
| 4027 | |
| 4028 AppendBlobsToPrimaryBlobJournal(pre_transaction.get(), blobs_to_write_); | |
| 4029 leveldb::Status s = pre_transaction->Commit(); | |
| 4030 if (!s.ok()) | |
| 4031 return InternalInconsistencyStatus(); | |
| 4032 | |
| 3970 return leveldb::Status::OK(); | 4033 return leveldb::Status::OK(); |
| 3971 } | 4034 } |
| 3972 | 4035 |
| 3973 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { | 4036 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { |
| 3974 if (backing_store_->is_incognito()) | 4037 if (backing_store_->is_incognito()) |
| 3975 return true; | 4038 return true; |
| 3976 | 4039 |
| 3977 // Look up all old files to remove as part of the transaction, store their | 4040 // Look up all old files to remove as part of the transaction, store their |
| 3978 // names in blobs_to_remove_, and remove their old blob data entries. | 4041 // names in blobs_to_remove_, and remove their old blob data entries. |
| 3979 for (const auto& iter : blob_change_map_) { | 4042 for (const auto& iter : blob_change_map_) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 4003 } | 4066 } |
| 4004 for (const auto& blob : blob_info) { | 4067 for (const auto& blob : blob_info) { |
| 4005 blobs_to_remove_.push_back(std::make_pair(database_id_, blob.key())); | 4068 blobs_to_remove_.push_back(std::make_pair(database_id_, blob.key())); |
| 4006 transaction_->Remove(blob_entry_key_bytes); | 4069 transaction_->Remove(blob_entry_key_bytes); |
| 4007 } | 4070 } |
| 4008 } | 4071 } |
| 4009 } | 4072 } |
| 4010 return true; | 4073 return true; |
| 4011 } | 4074 } |
| 4012 | 4075 |
| 4013 leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() { | 4076 void IndexedDBBackingStore::Transaction::PartitionBlobsToRemove( |
| 4077 BlobJournalType* dead_blobs, | |
| 4078 BlobJournalType* live_blobs) const { | |
| 4014 IndexedDBActiveBlobRegistry* registry = | 4079 IndexedDBActiveBlobRegistry* registry = |
| 4015 backing_store_->active_blob_registry(); | 4080 backing_store_->active_blob_registry(); |
| 4016 BlobJournalType primary_journal, live_blob_journal; | |
| 4017 for (const auto& iter : blobs_to_remove_) { | 4081 for (const auto& iter : blobs_to_remove_) { |
| 4018 if (registry->MarkDeletedCheckIfUsed(iter.first, iter.second)) | 4082 if (registry->MarkDeletedCheckIfUsed(iter.first, iter.second)) |
| 4019 live_blob_journal.push_back(iter); | 4083 live_blobs->push_back(iter); |
| 4020 else | 4084 else |
| 4021 primary_journal.push_back(iter); | 4085 dead_blobs->push_back(iter); |
| 4022 } | 4086 } |
| 4023 UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal); | |
| 4024 leveldb::Status s = | |
| 4025 MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal); | |
| 4026 if (!s.ok()) | |
| 4027 return s; | |
| 4028 // To signal how many blobs need attention right now. | |
| 4029 blobs_to_remove_.swap(primary_journal); | |
| 4030 return leveldb::Status::OK(); | |
| 4031 } | 4087 } |
| 4032 | 4088 |
| 4033 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne( | 4089 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne( |
| 4034 scoped_refptr<BlobWriteCallback> callback) { | 4090 scoped_refptr<BlobWriteCallback> callback) { |
| 4035 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne"); | 4091 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne"); |
| 4036 DCHECK(transaction_.get()); | 4092 DCHECK(transaction_.get()); |
| 4037 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); | 4093 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); |
| 4038 | 4094 |
| 4039 leveldb::Status s; | 4095 leveldb::Status s; |
| 4040 | 4096 |
| 4041 s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 4042 if (!s.ok()) { | |
| 4043 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 4044 transaction_ = NULL; | |
| 4045 return s; | |
| 4046 } | |
| 4047 | |
| 4048 BlobEntryKeyValuePairVec new_blob_entries; | 4097 BlobEntryKeyValuePairVec new_blob_entries; |
| 4049 WriteDescriptorVec new_files_to_write; | 4098 WriteDescriptorVec new_files_to_write; |
| 4050 s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write); | 4099 s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write); |
| 4051 if (!s.ok()) { | 4100 if (!s.ok()) { |
| 4052 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 4101 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); |
| 4053 transaction_ = NULL; | 4102 transaction_ = NULL; |
| 4054 return s; | 4103 return s; |
| 4055 } | 4104 } |
| 4056 | 4105 |
| 4057 DCHECK(!new_files_to_write.size() || | 4106 DCHECK(!new_files_to_write.size() || |
| 4058 KeyPrefix::IsValidDatabaseId(database_id_)); | 4107 KeyPrefix::IsValidDatabaseId(database_id_)); |
| 4059 if (!CollectBlobFilesToRemove()) { | 4108 if (!CollectBlobFilesToRemove()) { |
| 4060 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 4109 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); |
| 4061 transaction_ = NULL; | 4110 transaction_ = NULL; |
| 4062 return InternalInconsistencyStatus(); | 4111 return InternalInconsistencyStatus(); |
| 4063 } | 4112 } |
| 4064 | 4113 |
| 4114 committing_ = true; | |
| 4115 ++backing_store_->committing_transaction_count_; | |
| 4116 | |
| 4065 if (new_files_to_write.size()) { | 4117 if (new_files_to_write.size()) { |
| 4066 // This kicks off the writes of the new blobs, if any. | 4118 // This kicks off the writes of the new blobs, if any. |
| 4067 // This call will zero out new_blob_entries and new_files_to_write. | 4119 // This call will zero out new_blob_entries and new_files_to_write. |
| 4068 WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback); | 4120 WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback); |
| 4069 // Remove the add journal, if any; once the blobs are written, and we | |
| 4070 // commit, this will do the cleanup. | |
| 4071 ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode()); | |
| 4072 } else { | 4121 } else { |
| 4073 callback->Run(true); | 4122 callback->Run(true); |
| 4074 } | 4123 } |
| 4075 | 4124 |
| 4076 return leveldb::Status::OK(); | 4125 return leveldb::Status::OK(); |
| 4077 } | 4126 } |
| 4078 | 4127 |
| 4079 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() { | 4128 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() { |
| 4080 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo"); | 4129 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo"); |
| 4081 leveldb::Status s; | 4130 leveldb::Status s; |
| 4082 if (blobs_to_remove_.size()) { | 4131 |
| 4083 s = SortBlobsToRemove(); | 4132 DCHECK(committing_); |
| 4084 if (!s.ok()) { | 4133 committing_ = false; |
| 4085 INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 4134 --backing_store_->committing_transaction_count_; |
|
cmumford
2015/01/22 00:56:57
We sure it won't underflow? DCHECK maybe?
jsbell
2015/01/22 19:40:45
Added a DCHECK (here and in Rollback). I wasn't su
| |
| 4086 transaction_ = NULL; | 4135 |
| 4136 // Read the persisted states of the primary/live blob journals, | |
| 4137 // so that they can be updated correctly by the transaction. | |
| 4138 BlobJournalType primary_journal, live_journal; | |
| 4139 { | |
| 4140 scoped_refptr<LevelDBTransaction> journal_transaction = | |
| 4141 IndexedDBClassFactory::Get()->CreateLevelDBTransaction( | |
| 4142 backing_store_->db_.get()); | |
| 4143 s = GetPrimaryBlobJournal(journal_transaction.get(), &primary_journal); | |
| 4144 if (!s.ok()) | |
| 4087 return s; | 4145 return s; |
| 4088 } | 4146 s = GetLiveBlobJournal(journal_transaction.get(), &live_journal); |
| 4147 if (!s.ok()) | |
| 4148 return s; | |
| 4089 } | 4149 } |
| 4090 | 4150 |
| 4151 // Remove newly added blobs from the journal - they will be accounted | |
| 4152 // for in blob entry tables in the transaction. | |
| 4153 { | |
| 4154 std::sort(primary_journal.begin(), primary_journal.end()); | |
| 4155 std::sort(blobs_to_write_.begin(), blobs_to_write_.end()); | |
| 4156 BlobJournalType new_journal = base::STLSetDifference<BlobJournalType>( | |
| 4157 primary_journal, blobs_to_write_); | |
| 4158 primary_journal.swap(new_journal); | |
| 4159 } | |
| 4160 | |
| 4161 // Append newly deleted blobs to appropriate primary/live journals. | |
| 4162 BlobJournalType saved_primary_journal = primary_journal; | |
| 4163 BlobJournalType dead_blobs, live_blobs; | |
| 4164 if (blobs_to_remove_.size()) { | |
| 4165 DCHECK(!backing_store_->is_incognito()); | |
| 4166 PartitionBlobsToRemove(&dead_blobs, &live_blobs); | |
| 4167 } | |
| 4168 primary_journal.insert(primary_journal.end(), dead_blobs.begin(), | |
| 4169 dead_blobs.end()); | |
| 4170 live_journal.insert(live_journal.end(), live_blobs.begin(), live_blobs.end()); | |
| 4171 UpdatePrimaryBlobJournal(transaction_.get(), primary_journal); | |
| 4172 UpdateLiveBlobJournal(transaction_.get(), live_journal); | |
| 4173 | |
| 4174 // Actually commit. If this succeeds, the journals will appropriately | |
| 4175 // reflect pending blob work - dead files that should be deleted | |
| 4176 // immediately, and live files to monitor. | |
| 4091 s = transaction_->Commit(); | 4177 s = transaction_->Commit(); |
| 4092 transaction_ = NULL; | 4178 transaction_ = NULL; |
| 4093 | 4179 |
| 4094 if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) { | 4180 if (!s.ok()) { |
| 4095 BlobChangeMap& target_map = backing_store_->incognito_blob_map_; | 4181 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); |
| 4096 for (auto& iter : blob_change_map_) { | 4182 return s; |
| 4097 BlobChangeMap::iterator target_record = target_map.find(iter.first); | 4183 } |
| 4098 if (target_record != target_map.end()) { | 4184 |
| 4099 delete target_record->second; | 4185 if (backing_store_->is_incognito()) { |
| 4100 target_map.erase(target_record); | 4186 if (!blob_change_map_.empty()) { |
| 4101 } | 4187 BlobChangeMap& target_map = backing_store_->incognito_blob_map_; |
| 4102 if (iter.second) { | 4188 for (auto& iter : blob_change_map_) { |
| 4103 target_map[iter.first] = iter.second; | 4189 BlobChangeMap::iterator target_record = target_map.find(iter.first); |
| 4104 iter.second = NULL; | 4190 if (target_record != target_map.end()) { |
| 4191 delete target_record->second; | |
| 4192 target_map.erase(target_record); | |
| 4193 } | |
| 4194 if (iter.second) { | |
| 4195 target_map[iter.first] = iter.second; | |
| 4196 iter.second = NULL; | |
| 4197 } | |
| 4105 } | 4198 } |
| 4106 } | 4199 } |
| 4200 return leveldb::Status::OK(); | |
| 4107 } | 4201 } |
| 4108 if (!s.ok()) | |
| 4109 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 4110 else if (blobs_to_remove_.size()) | |
| 4111 s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 4112 | 4202 |
| 4203 // Actually delete dead blob files, then remove those entries | |
| 4204 // from the persisted primary journal. | |
| 4205 if (!dead_blobs.size()) | |
| 4206 return leveldb::Status::OK(); | |
| 4207 | |
| 4208 s = backing_store_->CleanUpBlobJournalEntries(dead_blobs); | |
| 4209 if (!s.ok()) { | |
| 4210 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | |
| 4211 return s; | |
| 4212 } | |
| 4213 | |
| 4214 scoped_refptr<LevelDBTransaction> update_journal_transaction = | |
| 4215 IndexedDBClassFactory::Get()->CreateLevelDBTransaction( | |
| 4216 backing_store_->db_.get()); | |
| 4217 UpdatePrimaryBlobJournal(update_journal_transaction.get(), | |
| 4218 saved_primary_journal); | |
| 4219 s = update_journal_transaction->Commit(); | |
| 4113 return s; | 4220 return s; |
| 4114 } | 4221 } |
| 4115 | 4222 |
| 4116 | 4223 |
| 4117 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper | 4224 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper |
| 4118 : public IndexedDBBackingStore::BlobWriteCallback { | 4225 : public IndexedDBBackingStore::BlobWriteCallback { |
| 4119 public: | 4226 public: |
| 4120 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, | 4227 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, |
| 4121 scoped_refptr<BlobWriteCallback> callback) | 4228 scoped_refptr<BlobWriteCallback> callback) |
| 4122 : transaction_(transaction), callback_(callback) {} | 4229 : transaction_(transaction), callback_(callback) {} |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4154 // Creating the writer will start it going asynchronously. | 4261 // Creating the writer will start it going asynchronously. |
| 4155 chained_blob_writer_ = | 4262 chained_blob_writer_ = |
| 4156 new ChainedBlobWriterImpl(database_id_, | 4263 new ChainedBlobWriterImpl(database_id_, |
| 4157 backing_store_, | 4264 backing_store_, |
| 4158 new_files_to_write, | 4265 new_files_to_write, |
| 4159 new BlobWriteCallbackWrapper(this, callback)); | 4266 new BlobWriteCallbackWrapper(this, callback)); |
| 4160 } | 4267 } |
| 4161 | 4268 |
| 4162 void IndexedDBBackingStore::Transaction::Rollback() { | 4269 void IndexedDBBackingStore::Transaction::Rollback() { |
| 4163 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 4270 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
| 4271 if (committing_) { | |
| 4272 committing_ = false; | |
| 4273 --backing_store_->committing_transaction_count_; | |
| 4274 } | |
| 4275 | |
| 4164 if (chained_blob_writer_.get()) { | 4276 if (chained_blob_writer_.get()) { |
| 4165 chained_blob_writer_->Abort(); | 4277 chained_blob_writer_->Abort(); |
| 4166 chained_blob_writer_ = NULL; | 4278 chained_blob_writer_ = NULL; |
| 4167 } | 4279 } |
| 4168 if (transaction_.get() == NULL) | 4280 if (transaction_.get() == NULL) |
| 4169 return; | 4281 return; |
| 4170 transaction_->Rollback(); | 4282 transaction_->Rollback(); |
| 4171 transaction_ = NULL; | 4283 transaction_ = NULL; |
| 4172 } | 4284 } |
| 4173 | 4285 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4283 int64_t size, | 4395 int64_t size, |
| 4284 base::Time last_modified) | 4396 base::Time last_modified) |
| 4285 : is_file_(true), | 4397 : is_file_(true), |
| 4286 file_path_(file_path), | 4398 file_path_(file_path), |
| 4287 key_(key), | 4399 key_(key), |
| 4288 size_(size), | 4400 size_(size), |
| 4289 last_modified_(last_modified) { | 4401 last_modified_(last_modified) { |
| 4290 } | 4402 } |
| 4291 | 4403 |
| 4292 } // namespace content | 4404 } // namespace content |
| OLD | NEW |