Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
| 14 #include "base/strings/stringprintf.h" | |
| 14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 15 #include "content/browser/child_process_security_policy_impl.h" | 16 #include "content/browser/child_process_security_policy_impl.h" |
| 16 #include "content/browser/indexed_db/indexed_db_blob_info.h" | 17 #include "content/browser/indexed_db/indexed_db_blob_info.h" |
| 17 #include "content/browser/indexed_db/indexed_db_database_error.h" | 18 #include "content/browser/indexed_db/indexed_db_database_error.h" |
| 18 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 19 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
| 19 #include "content/browser/indexed_db/indexed_db_metadata.h" | 20 #include "content/browser/indexed_db/indexed_db_metadata.h" |
| 20 #include "content/browser/indexed_db/indexed_db_tracing.h" | 21 #include "content/browser/indexed_db/indexed_db_tracing.h" |
| 21 #include "content/browser/indexed_db/indexed_db_value.h" | 22 #include "content/browser/indexed_db/indexed_db_value.h" |
| 22 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 23 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" |
| 23 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 24 #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
| 24 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 25 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" |
| 25 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 26 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
| 26 #include "content/common/indexed_db/indexed_db_key.h" | 27 #include "content/common/indexed_db/indexed_db_key.h" |
| 27 #include "content/common/indexed_db/indexed_db_key_path.h" | 28 #include "content/common/indexed_db/indexed_db_key_path.h" |
| 28 #include "content/common/indexed_db/indexed_db_key_range.h" | 29 #include "content/common/indexed_db/indexed_db_key_range.h" |
| 30 #include "content/public/browser/browser_thread.h" | |
| 31 #include "net/url_request/url_request_context.h" | |
| 29 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 32 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
| 30 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" | 33 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" |
| 31 #include "third_party/leveldatabase/env_chromium.h" | 34 #include "third_party/leveldatabase/env_chromium.h" |
| 32 #include "webkit/browser/blob/blob_data_handle.h" | 35 #include "webkit/browser/blob/blob_data_handle.h" |
| 36 #include "webkit/browser/fileapi/file_stream_writer.h" | |
| 37 #include "webkit/browser/fileapi/file_writer_delegate.h" | |
| 38 #include "webkit/browser/fileapi/local_file_stream_writer.h" | |
| 33 #include "webkit/common/database/database_identifier.h" | 39 #include "webkit/common/database/database_identifier.h" |
| 34 | 40 |
| 41 using base::FilePath; | |
| 35 using base::StringPiece; | 42 using base::StringPiece; |
| 43 using fileapi::FileWriterDelegate; | |
| 36 | 44 |
| 37 namespace content { | 45 namespace content { |
| 38 | 46 |
| 39 namespace { | 47 namespace { |
| 40 | 48 |
| 49 FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) { | |
| 50 return pathBase.AppendASCII(base::StringPrintf("%lx", database_id)); | |
| 51 } | |
| 52 | |
| 53 FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase, | |
| 54 int64 database_id, | |
| 55 int64 key) { | |
| 56 FilePath path = GetBlobDirectoryName(pathBase, database_id); | |
| 57 path = path.AppendASCII(base::StringPrintf( | |
| 58 "%02x", static_cast<int>(key & 0x000000000000ff00) >> 8)); | |
| 59 return path; | |
| 60 } | |
| 61 | |
| 62 FilePath GetBlobFileNameForKey(const FilePath& pathBase, | |
| 63 int64 database_id, | |
| 64 int64 key) { | |
| 65 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); | |
| 66 path = path.AppendASCII(base::StringPrintf("%lx", key)); | |
| 67 return path; | |
| 68 } | |
| 69 | |
| 70 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | |
| 71 bool MakeIDBBlobDirectory(const FilePath& pathBase, | |
| 72 int64 database_id, | |
| 73 int64 key) { | |
| 74 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); | |
| 75 return base::CreateDirectory(path); | |
| 76 } | |
| 77 | |
| 41 static std::string ComputeOriginIdentifier(const GURL& origin_url) { | 78 static std::string ComputeOriginIdentifier(const GURL& origin_url) { |
| 42 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; | 79 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; |
| 43 } | 80 } |
| 44 | 81 |
| 45 static base::FilePath ComputeFileName(const GURL& origin_url) { | 82 static base::FilePath ComputeFileName(const GURL& origin_url) { |
| 46 return base::FilePath() | 83 return base::FilePath() |
| 47 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | 84 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) |
| 48 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 85 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); |
| 49 } | 86 } |
| 50 | 87 |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 434 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) | 471 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) |
| 435 OVERRIDE { | 472 OVERRIDE { |
| 436 return LevelDBDatabase::Destroy(file_name); | 473 return LevelDBDatabase::Destroy(file_name); |
| 437 } | 474 } |
| 438 }; | 475 }; |
| 439 | 476 |
| 440 IndexedDBBackingStore::IndexedDBBackingStore( | 477 IndexedDBBackingStore::IndexedDBBackingStore( |
| 441 IndexedDBFactory* indexed_db_factory, | 478 IndexedDBFactory* indexed_db_factory, |
| 442 const GURL& origin_url, | 479 const GURL& origin_url, |
| 443 const base::FilePath& blob_path, | 480 const base::FilePath& blob_path, |
| 481 net::URLRequestContext* request_context, | |
| 444 scoped_ptr<LevelDBDatabase> db, | 482 scoped_ptr<LevelDBDatabase> db, |
| 445 scoped_ptr<LevelDBComparator> comparator, | 483 scoped_ptr<LevelDBComparator> comparator, |
| 446 base::TaskRunner* task_runner) | 484 base::TaskRunner* task_runner) |
| 447 : indexed_db_factory_(indexed_db_factory), | 485 : indexed_db_factory_(indexed_db_factory), |
| 448 origin_url_(origin_url), | 486 origin_url_(origin_url), |
| 449 blob_path_(blob_path), | 487 blob_path_(blob_path), |
| 450 origin_identifier_(ComputeOriginIdentifier(origin_url)), | 488 origin_identifier_(ComputeOriginIdentifier(origin_url)), |
| 489 request_context_(request_context), | |
| 451 task_runner_(task_runner), | 490 task_runner_(task_runner), |
| 452 db_(db.Pass()), | 491 db_(db.Pass()), |
| 453 comparator_(comparator.Pass()), | 492 comparator_(comparator.Pass()), |
| 454 active_blob_registry_(this) {} | 493 active_blob_registry_(this) {} |
| 455 | 494 |
| 456 IndexedDBBackingStore::~IndexedDBBackingStore() { | 495 IndexedDBBackingStore::~IndexedDBBackingStore() { |
| 457 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { | 496 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { |
| 458 ChildProcessSecurityPolicyImpl* policy = | 497 ChildProcessSecurityPolicyImpl* policy = |
| 459 ChildProcessSecurityPolicyImpl::GetInstance(); | 498 ChildProcessSecurityPolicyImpl::GetInstance(); |
| 460 std::set<int>::const_iterator iter; | 499 std::set<int>::const_iterator iter; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, | 538 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, |
| 500 INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, | 539 INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, |
| 501 INDEXED_DB_BACKING_STORE_OPEN_MAX, | 540 INDEXED_DB_BACKING_STORE_OPEN_MAX, |
| 502 }; | 541 }; |
| 503 | 542 |
| 504 // static | 543 // static |
| 505 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 544 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 506 IndexedDBFactory* indexed_db_factory, | 545 IndexedDBFactory* indexed_db_factory, |
| 507 const GURL& origin_url, | 546 const GURL& origin_url, |
| 508 const base::FilePath& path_base, | 547 const base::FilePath& path_base, |
| 548 net::URLRequestContext* request_context, | |
| 509 blink::WebIDBDataLoss* data_loss, | 549 blink::WebIDBDataLoss* data_loss, |
| 510 std::string* data_loss_message, | 550 std::string* data_loss_message, |
| 511 bool* disk_full, | 551 bool* disk_full, |
| 512 base::TaskRunner* task_runner) { | 552 base::TaskRunner* task_runner) { |
| 513 *data_loss = blink::WebIDBDataLossNone; | 553 *data_loss = blink::WebIDBDataLossNone; |
| 514 DefaultLevelDBFactory leveldb_factory; | 554 DefaultLevelDBFactory leveldb_factory; |
| 515 return IndexedDBBackingStore::Open(indexed_db_factory, | 555 return IndexedDBBackingStore::Open(indexed_db_factory, |
| 516 origin_url, | 556 origin_url, |
| 517 path_base, | 557 path_base, |
| 558 request_context, | |
| 518 data_loss, | 559 data_loss, |
| 519 data_loss_message, | 560 data_loss_message, |
| 520 disk_full, | 561 disk_full, |
| 521 &leveldb_factory, | 562 &leveldb_factory, |
| 522 task_runner); | 563 task_runner); |
| 523 } | 564 } |
| 524 | 565 |
| 525 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { | 566 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { |
| 526 if (origin_url.host() == "docs.google.com") | 567 if (origin_url.host() == "docs.google.com") |
| 527 return ".Docs"; | 568 return ".Docs"; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 return false; | 689 return false; |
| 649 int written = file.Write(0, output_js.c_str(), output_js.length()); | 690 int written = file.Write(0, output_js.c_str(), output_js.length()); |
| 650 return size_t(written) == output_js.length(); | 691 return size_t(written) == output_js.length(); |
| 651 } | 692 } |
| 652 | 693 |
| 653 // static | 694 // static |
| 654 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 695 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 655 IndexedDBFactory* indexed_db_factory, | 696 IndexedDBFactory* indexed_db_factory, |
| 656 const GURL& origin_url, | 697 const GURL& origin_url, |
| 657 const base::FilePath& path_base, | 698 const base::FilePath& path_base, |
| 699 net::URLRequestContext* request_context, | |
| 658 blink::WebIDBDataLoss* data_loss, | 700 blink::WebIDBDataLoss* data_loss, |
| 659 std::string* data_loss_message, | 701 std::string* data_loss_message, |
| 660 bool* is_disk_full, | 702 bool* is_disk_full, |
| 661 LevelDBFactory* leveldb_factory, | 703 LevelDBFactory* leveldb_factory, |
| 662 base::TaskRunner* task_runner) { | 704 base::TaskRunner* task_runner) { |
| 663 IDB_TRACE("IndexedDBBackingStore::Open"); | 705 IDB_TRACE("IndexedDBBackingStore::Open"); |
| 664 DCHECK(!path_base.empty()); | 706 DCHECK(!path_base.empty()); |
| 665 *data_loss = blink::WebIDBDataLossNone; | 707 *data_loss = blink::WebIDBDataLossNone; |
| 666 *data_loss_message = ""; | 708 *data_loss_message = ""; |
| 667 *is_disk_full = false; | 709 *is_disk_full = false; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 773 if (!db) { | 815 if (!db) { |
| 774 NOTREACHED(); | 816 NOTREACHED(); |
| 775 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, | 817 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, |
| 776 origin_url); | 818 origin_url); |
| 777 return scoped_refptr<IndexedDBBackingStore>(); | 819 return scoped_refptr<IndexedDBBackingStore>(); |
| 778 } | 820 } |
| 779 | 821 |
| 780 return Create(indexed_db_factory, | 822 return Create(indexed_db_factory, |
| 781 origin_url, | 823 origin_url, |
| 782 blob_path, | 824 blob_path, |
| 825 request_context, | |
| 783 db.Pass(), | 826 db.Pass(), |
| 784 comparator.Pass(), | 827 comparator.Pass(), |
| 785 task_runner); | 828 task_runner); |
| 786 } | 829 } |
| 787 | 830 |
| 788 // static | 831 // static |
| 789 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 832 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
| 790 const GURL& origin_url, | 833 const GURL& origin_url, |
| 791 base::TaskRunner* task_runner) { | 834 base::TaskRunner* task_runner) { |
| 792 DefaultLevelDBFactory leveldb_factory; | 835 DefaultLevelDBFactory leveldb_factory; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 808 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; | 851 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; |
| 809 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 852 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
| 810 origin_url); | 853 origin_url); |
| 811 return scoped_refptr<IndexedDBBackingStore>(); | 854 return scoped_refptr<IndexedDBBackingStore>(); |
| 812 } | 855 } |
| 813 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); | 856 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); |
| 814 | 857 |
| 815 return Create(NULL /* indexed_db_factory */, | 858 return Create(NULL /* indexed_db_factory */, |
| 816 origin_url, | 859 origin_url, |
| 817 base::FilePath(), | 860 base::FilePath(), |
| 861 NULL /* request_context */, | |
| 818 db.Pass(), | 862 db.Pass(), |
| 819 comparator.Pass(), | 863 comparator.Pass(), |
| 820 task_runner); | 864 task_runner); |
| 821 } | 865 } |
| 822 | 866 |
| 823 // static | 867 // static |
| 824 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 868 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( |
| 825 IndexedDBFactory* indexed_db_factory, | 869 IndexedDBFactory* indexed_db_factory, |
| 826 const GURL& origin_url, | 870 const GURL& origin_url, |
| 827 const base::FilePath& blob_path, | 871 const base::FilePath& blob_path, |
| 872 net::URLRequestContext* request_context, | |
| 828 scoped_ptr<LevelDBDatabase> db, | 873 scoped_ptr<LevelDBDatabase> db, |
| 829 scoped_ptr<LevelDBComparator> comparator, | 874 scoped_ptr<LevelDBComparator> comparator, |
| 830 base::TaskRunner* task_runner) { | 875 base::TaskRunner* task_runner) { |
| 831 // TODO(jsbell): Handle comparator name changes. | 876 // TODO(jsbell): Handle comparator name changes. |
| 832 | |
| 833 scoped_refptr<IndexedDBBackingStore> backing_store( | 877 scoped_refptr<IndexedDBBackingStore> backing_store( |
| 834 new IndexedDBBackingStore(indexed_db_factory, | 878 new IndexedDBBackingStore(indexed_db_factory, |
| 835 origin_url, | 879 origin_url, |
| 836 blob_path, | 880 blob_path, |
| 881 request_context, | |
| 837 db.Pass(), | 882 db.Pass(), |
| 838 comparator.Pass(), | 883 comparator.Pass(), |
| 839 task_runner)); | 884 task_runner)); |
| 840 if (!SetUpMetadata(backing_store->db_.get(), | 885 if (!SetUpMetadata(backing_store->db_.get(), |
| 841 backing_store->origin_identifier_)) | 886 backing_store->origin_identifier_)) |
| 842 return scoped_refptr<IndexedDBBackingStore>(); | 887 return scoped_refptr<IndexedDBBackingStore>(); |
| 843 | 888 |
| 844 return backing_store; | 889 return backing_store; |
| 845 } | 890 } |
| 846 | 891 |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1686 StringPiece slice(data); | 1731 StringPiece slice(data); |
| 1687 if (!DecodeVarInt(&slice, &version)) | 1732 if (!DecodeVarInt(&slice, &version)) |
| 1688 return InternalInconsistencyStatus(); | 1733 return InternalInconsistencyStatus(); |
| 1689 | 1734 |
| 1690 std::string encoded_key; | 1735 std::string encoded_key; |
| 1691 EncodeIDBKey(key, &encoded_key); | 1736 EncodeIDBKey(key, &encoded_key); |
| 1692 found_record_identifier->Reset(encoded_key, version); | 1737 found_record_identifier->Reset(encoded_key, version); |
| 1693 return s; | 1738 return s; |
| 1694 } | 1739 } |
| 1695 | 1740 |
| 1741 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl | |
| 1742 : public IndexedDBBackingStore::Transaction::ChainedBlobWriter { | |
| 1743 public: | |
| 1744 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec | |
| 1745 WriteDescriptorVec; | |
| 1746 ChainedBlobWriterImpl( | |
| 1747 int64 database_id, | |
| 1748 IndexedDBBackingStore* backingStore, | |
| 1749 WriteDescriptorVec& blobs, | |
| 1750 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) | |
| 1751 : waiting_for_callback_(false), | |
| 1752 database_id_(database_id), | |
| 1753 backing_store_(backingStore), | |
| 1754 callback_(callback), | |
| 1755 aborted_(false) { | |
| 1756 blobs_.swap(blobs); | |
| 1757 iter_ = blobs_.begin(); | |
| 1758 WriteNextFile(); | |
| 1759 } | |
| 1760 | |
| 1761 void set_delegate(scoped_ptr<FileWriterDelegate> delegate) { | |
| 1762 delegate_.reset(delegate.release()); | |
| 1763 } | |
| 1764 | |
| 1765 void ReportWriteCompletion(bool succeeded, int64 bytes_written) { | |
| 1766 // TODO(ericu): Check bytes_written against the blob's snapshot value. | |
| 1767 DCHECK(waiting_for_callback_); | |
| 1768 DCHECK(!succeeded || bytes_written >= 0); | |
| 1769 waiting_for_callback_ = false; | |
| 1770 if (delegate_.get()) // Only present for Blob, not File. | |
| 1771 content::BrowserThread::DeleteSoon( | |
| 1772 content::BrowserThread::IO, FROM_HERE, delegate_.release()); | |
| 1773 if (aborted_) { | |
| 1774 self_ref_ = NULL; | |
| 1775 return; | |
| 1776 } | |
| 1777 if (succeeded) | |
| 1778 WriteNextFile(); | |
| 1779 else | |
| 1780 callback_->Run(false); | |
| 1781 } | |
| 1782 | |
| 1783 void Abort() { | |
| 1784 if (!waiting_for_callback_) | |
| 1785 return; | |
| 1786 self_ref_ = this; | |
| 1787 aborted_ = true; | |
| 1788 } | |
| 1789 | |
| 1790 private: | |
| 1791 void WriteNextFile() { | |
| 1792 DCHECK(!waiting_for_callback_); | |
| 1793 DCHECK(!aborted_); | |
| 1794 if (iter_ == blobs_.end()) { | |
| 1795 DCHECK(!self_ref_); | |
| 1796 callback_->Run(true); | |
| 1797 return; | |
| 1798 } else { | |
| 1799 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { | |
| 1800 callback_->Run(false); | |
| 1801 return; | |
| 1802 } | |
| 1803 waiting_for_callback_ = true; | |
| 1804 ++iter_; | |
| 1805 } | |
| 1806 } | |
| 1807 | |
| 1808 bool waiting_for_callback_; | |
| 1809 scoped_refptr<ChainedBlobWriterImpl> self_ref_; | |
| 1810 WriteDescriptorVec blobs_; | |
| 1811 WriteDescriptorVec::const_iterator iter_; | |
| 1812 int64 database_id_; | |
| 1813 IndexedDBBackingStore* backing_store_; | |
| 1814 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; | |
| 1815 scoped_ptr<FileWriterDelegate> delegate_; | |
| 1816 bool aborted_; | |
| 1817 }; | |
| 1818 | |
| 1819 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, | |
| 1820 public base::RefCounted<LocalWriteClosure> { | |
| 1821 public: | |
| 1822 LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter* | |
| 1823 chained_blob_writer_, | |
| 1824 base::TaskRunner* task_runner) | |
| 1825 : chained_blob_writer_(chained_blob_writer_), | |
| 1826 task_runner_(task_runner), | |
| 1827 bytes_written_(-1) {} | |
| 1828 | |
| 1829 void Run(base::File::Error rv, | |
| 1830 int64 bytes, | |
| 1831 FileWriterDelegate::WriteProgressStatus write_status) { | |
| 1832 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) | |
| 1833 return; // We don't care about progress events. | |
| 1834 if (rv == base::File::FILE_OK) { | |
| 1835 DCHECK(bytes >= 0); | |
| 1836 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); | |
| 1837 bytes_written_ = bytes; | |
| 1838 } else { | |
| 1839 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || | |
| 1840 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); | |
| 1841 } | |
| 1842 task_runner_->PostTask( | |
| 1843 FROM_HERE, | |
| 1844 base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, | |
| 1845 this, | |
| 1846 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); | |
| 1847 } | |
| 1848 | |
| 1849 void writeBlobToFileOnIOThread(const FilePath& file_path, | |
| 1850 const GURL& blob_url, | |
| 1851 net::URLRequestContext* request_context) { | |
| 1852 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 1853 scoped_ptr<fileapi::FileStreamWriter> writer( | |
| 1854 fileapi::FileStreamWriter::CreateForLocalFile( | |
| 1855 task_runner_, file_path, 0, | |
| 1856 fileapi::FileStreamWriter::CREATE_NEW_FILE)); | |
| 1857 scoped_ptr<FileWriterDelegate> delegate( | |
| 1858 new FileWriterDelegate(writer.Pass())); | |
| 1859 | |
| 1860 DCHECK(blob_url.is_valid()); | |
| 1861 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( | |
| 1862 blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL)); | |
| 1863 | |
| 1864 delegate->Start(blob_request.Pass(), | |
| 1865 base::Bind(&LocalWriteClosure::Run, this)); | |
| 1866 chained_blob_writer_->set_delegate(delegate.Pass()); | |
| 1867 } | |
| 1868 | |
| 1869 private: | |
| 1870 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { | |
| 1871 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
| 1872 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); | |
| 1873 } | |
| 1874 | |
| 1875 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; | |
| 1876 base::TaskRunner* task_runner_; | |
| 1877 int64 bytes_written_; | |
| 1878 }; | |
| 1879 | |
| 1880 bool IndexedDBBackingStore::WriteBlobFile( | |
| 1881 int64 database_id, | |
| 1882 const Transaction::WriteDescriptor& descriptor, | |
| 1883 Transaction::ChainedBlobWriter* chained_blob_writer) { | |
| 1884 | |
| 1885 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) | |
| 1886 return false; | |
| 1887 | |
| 1888 FilePath path = GetBlobFileName(database_id, descriptor.key()); | |
| 1889 | |
| 1890 if (descriptor.is_file()) { | |
| 1891 DCHECK(!descriptor.file_path().empty()); | |
| 1892 if (!base::CopyFile(descriptor.file_path(), path)) | |
| 1893 return false; | |
| 1894 | |
| 1895 base::File::Info info; | |
| 1896 if (base::GetFileInfo(descriptor.file_path(), &info)) { | |
| 1897 // TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor | |
| 1898 // to include snapshot date and file size, and check both. | |
| 1899 if (!base::TouchFile(path, info.last_accessed, info.last_modified)) | |
| 1900 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 1901 } else { | |
| 1902 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 1903 } | |
| 1904 | |
| 1905 task_runner_->PostTask( | |
| 1906 FROM_HERE, | |
| 1907 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
| 1908 chained_blob_writer, | |
| 1909 true, | |
| 1910 info.size)); | |
| 1911 } else { | |
| 1912 DCHECK(descriptor.url().is_valid()); | |
| 1913 scoped_refptr<LocalWriteClosure> write_closure( | |
| 1914 new LocalWriteClosure(chained_blob_writer, task_runner_)); | |
| 1915 content::BrowserThread::PostTask( | |
| 1916 content::BrowserThread::IO, | |
| 1917 FROM_HERE, | |
| 1918 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, | |
| 1919 write_closure.get(), | |
| 1920 path, | |
| 1921 descriptor.url(), | |
| 1922 request_context_)); | |
| 1923 } | |
| 1924 return true; | |
| 1925 } | |
| 1926 | |
| 1927 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | |
|
jsbell
2014/04/28 18:04:20
Nit: This comment could be moved/removed now.
| |
| 1928 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { | |
| 1929 return GetBlobFileNameForKey(blob_path_, database_id, key); | |
| 1930 } | |
| 1931 | |
| 1696 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 1932 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
| 1697 const std::string& stop_key, | 1933 const std::string& stop_key, |
| 1698 int64 index_id, | 1934 int64 index_id, |
| 1699 unsigned char meta_data_type) { | 1935 unsigned char meta_data_type) { |
| 1700 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1936 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| 1701 return false; | 1937 return false; |
| 1702 | 1938 |
| 1703 StringPiece slice(it->Key()); | 1939 StringPiece slice(it->Key()); |
| 1704 IndexMetaDataKey meta_data_key; | 1940 IndexMetaDataKey meta_data_key; |
| 1705 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 1941 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1802 (*indexes)[index_id] = IndexedDBIndexMetadata( | 2038 (*indexes)[index_id] = IndexedDBIndexMetadata( |
| 1803 index_name, index_id, key_path, index_unique, index_multi_entry); | 2039 index_name, index_id, key_path, index_unique, index_multi_entry); |
| 1804 } | 2040 } |
| 1805 | 2041 |
| 1806 if (!s.ok()) | 2042 if (!s.ok()) |
| 1807 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); | 2043 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); |
| 1808 | 2044 |
| 1809 return s; | 2045 return s; |
| 1810 } | 2046 } |
| 1811 | 2047 |
| 2048 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | |
| 2049 FilePath fileName = GetBlobFileName(database_id, key); | |
| 2050 return base::DeleteFile(fileName, false); | |
| 2051 } | |
| 2052 | |
| 2053 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | |
| 2054 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); | |
| 2055 return base::DeleteFile(dirName, true); | |
| 2056 } | |
| 2057 | |
| 1812 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2058 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
| 1813 LevelDBTransaction* transaction, | 2059 LevelDBTransaction* transaction, |
| 1814 int64 database_id, | 2060 int64 database_id, |
| 1815 int64 object_store_id, | 2061 int64 object_store_id, |
| 1816 int64 index_id) { | 2062 int64 index_id) { |
| 1817 int64 max_index_id = -1; | 2063 int64 max_index_id = -1; |
| 1818 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2064 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
| 1819 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2065 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
| 1820 bool found = false; | 2066 bool found = false; |
| 1821 leveldb::Status s = | 2067 leveldb::Status s = |
| (...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2939 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { | 3185 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { |
| 2940 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3186 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); |
| 2941 DCHECK(transaction_.get()); | 3187 DCHECK(transaction_.get()); |
| 2942 leveldb::Status s = transaction_->Commit(); | 3188 leveldb::Status s = transaction_->Commit(); |
| 2943 transaction_ = NULL; | 3189 transaction_ = NULL; |
| 2944 if (!s.ok()) | 3190 if (!s.ok()) |
| 2945 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 3191 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); |
| 2946 return s; | 3192 return s; |
| 2947 } | 3193 } |
| 2948 | 3194 |
| 3195 | |
| 3196 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper | |
| 3197 : public IndexedDBBackingStore::BlobWriteCallback { | |
| 3198 public: | |
| 3199 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, | |
| 3200 scoped_refptr<BlobWriteCallback> callback) | |
| 3201 : transaction_(transaction), callback_(callback) {} | |
| 3202 virtual void Run(bool succeeded) { | |
| 3203 callback_->Run(succeeded); | |
| 3204 transaction_->chained_blob_writer_ = NULL; | |
| 3205 } | |
| 3206 | |
| 3207 private: | |
| 3208 IndexedDBBackingStore::Transaction* transaction_; | |
| 3209 scoped_refptr<BlobWriteCallback> callback_; | |
| 3210 }; | |
| 3211 | |
| 3212 void IndexedDBBackingStore::Transaction::WriteNewBlobs( | |
| 3213 BlobEntryKeyValuePairVec& new_blob_entries, | |
| 3214 WriteDescriptorVec& new_files_to_write, | |
| 3215 scoped_refptr<BlobWriteCallback> callback) { | |
| 3216 DCHECK_GT(new_files_to_write.size(), 0UL); | |
| 3217 DCHECK_GT(database_id_, 0); | |
| 3218 BlobEntryKeyValuePairVec::iterator blob_entry_iter; | |
| 3219 for (blob_entry_iter = new_blob_entries.begin(); | |
| 3220 blob_entry_iter != new_blob_entries.end(); | |
| 3221 ++blob_entry_iter) { | |
| 3222 // Add the new blob-table entry for each blob to the main transaction, or | |
| 3223 // remove any entry that may exist if there's no new one. | |
| 3224 if (!blob_entry_iter->second.size()) | |
| 3225 transaction_->Remove(blob_entry_iter->first.Encode()); | |
| 3226 else | |
| 3227 transaction_->Put(blob_entry_iter->first.Encode(), | |
| 3228 &blob_entry_iter->second); | |
| 3229 } | |
| 3230 // Creating the writer will start it going asynchronously. | |
| 3231 chained_blob_writer_ = | |
| 3232 new ChainedBlobWriterImpl(database_id_, | |
| 3233 backing_store_, | |
| 3234 new_files_to_write, | |
| 3235 new BlobWriteCallbackWrapper(this, callback)); | |
| 3236 } | |
| 3237 | |
| 2949 void IndexedDBBackingStore::Transaction::Rollback() { | 3238 void IndexedDBBackingStore::Transaction::Rollback() { |
| 2950 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3239 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
| 2951 DCHECK(transaction_.get()); | 3240 DCHECK(transaction_.get()); |
| 3241 if (chained_blob_writer_) { | |
| 3242 chained_blob_writer_->Abort(); | |
| 3243 chained_blob_writer_ = NULL; | |
| 3244 } | |
| 2952 transaction_->Rollback(); | 3245 transaction_->Rollback(); |
| 2953 transaction_ = NULL; | 3246 transaction_ = NULL; |
| 2954 } | 3247 } |
| 2955 | 3248 |
| 2956 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( | 3249 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( |
| 2957 const std::string& key, int64 object_store_id) | 3250 const std::string& key, int64 object_store_id) |
| 2958 : key_(key), object_store_id_(object_store_id) { | 3251 : key_(key), object_store_id_(object_store_id) { |
| 2959 } | 3252 } |
| 2960 | 3253 |
| 2961 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { | 3254 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2997 blob_change_map_[key] = record; | 3290 blob_change_map_[key] = record; |
| 2998 } else { | 3291 } else { |
| 2999 record = it->second; | 3292 record = it->second; |
| 3000 } | 3293 } |
| 3001 DCHECK_EQ(record->object_store_id(), object_store_id); | 3294 DCHECK_EQ(record->object_store_id(), object_store_id); |
| 3002 record->SetBlobInfo(blob_info); | 3295 record->SetBlobInfo(blob_info); |
| 3003 record->SetHandles(handles); | 3296 record->SetHandles(handles); |
| 3004 DCHECK(!handles || !handles->size()); | 3297 DCHECK(!handles || !handles->size()); |
| 3005 } | 3298 } |
| 3006 | 3299 |
| 3300 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3301 const GURL& url, | |
| 3302 int64_t key) | |
| 3303 : is_file_(false), url_(url), key_(key) {} | |
| 3304 | |
| 3305 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3306 const FilePath& file_path, | |
| 3307 int64_t key) | |
| 3308 : is_file_(true), file_path_(file_path), key_(key) {} | |
| 3309 | |
| 3007 } // namespace content | 3310 } // namespace content |
| OLD | NEW |