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