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 |