Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(594)

Side by Side Diff: content/browser/indexed_db/indexed_db_backing_store.cc

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

Powered by Google App Engine
This is Rietveld 408576698