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