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

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: 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.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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698