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/format_macros.h" |
9 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
10 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
13 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/stringprintf.h" |
14 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
15 #include "content/browser/child_process_security_policy_impl.h" | 17 #include "content/browser/child_process_security_policy_impl.h" |
16 #include "content/browser/indexed_db/indexed_db_blob_info.h" | 18 #include "content/browser/indexed_db/indexed_db_blob_info.h" |
17 #include "content/browser/indexed_db/indexed_db_database_error.h" | 19 #include "content/browser/indexed_db/indexed_db_database_error.h" |
18 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 20 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
19 #include "content/browser/indexed_db/indexed_db_metadata.h" | 21 #include "content/browser/indexed_db/indexed_db_metadata.h" |
20 #include "content/browser/indexed_db/indexed_db_tracing.h" | 22 #include "content/browser/indexed_db/indexed_db_tracing.h" |
21 #include "content/browser/indexed_db/indexed_db_value.h" | 23 #include "content/browser/indexed_db/indexed_db_value.h" |
22 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 24 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" |
23 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 25 #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
24 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 26 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" |
25 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 27 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
26 #include "content/common/indexed_db/indexed_db_key.h" | 28 #include "content/common/indexed_db/indexed_db_key.h" |
27 #include "content/common/indexed_db/indexed_db_key_path.h" | 29 #include "content/common/indexed_db/indexed_db_key_path.h" |
28 #include "content/common/indexed_db/indexed_db_key_range.h" | 30 #include "content/common/indexed_db/indexed_db_key_range.h" |
| 31 #include "content/public/browser/browser_thread.h" |
| 32 #include "net/url_request/url_request_context.h" |
29 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 33 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
30 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" | 34 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" |
31 #include "third_party/leveldatabase/env_chromium.h" | 35 #include "third_party/leveldatabase/env_chromium.h" |
32 #include "webkit/browser/blob/blob_data_handle.h" | 36 #include "webkit/browser/blob/blob_data_handle.h" |
| 37 #include "webkit/browser/fileapi/file_stream_writer.h" |
| 38 #include "webkit/browser/fileapi/file_writer_delegate.h" |
| 39 #include "webkit/browser/fileapi/local_file_stream_writer.h" |
33 #include "webkit/common/database/database_identifier.h" | 40 #include "webkit/common/database/database_identifier.h" |
34 | 41 |
| 42 using base::FilePath; |
35 using base::StringPiece; | 43 using base::StringPiece; |
| 44 using fileapi::FileWriterDelegate; |
36 | 45 |
37 namespace content { | 46 namespace content { |
38 | 47 |
39 namespace { | 48 namespace { |
40 | 49 |
| 50 FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) { |
| 51 return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id)); |
| 52 } |
| 53 |
| 54 FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase, |
| 55 int64 database_id, |
| 56 int64 key) { |
| 57 FilePath path = GetBlobDirectoryName(pathBase, database_id); |
| 58 path = path.AppendASCII(base::StringPrintf( |
| 59 "%02x", static_cast<int>(key & 0x000000000000ff00) >> 8)); |
| 60 return path; |
| 61 } |
| 62 |
| 63 FilePath GetBlobFileNameForKey(const FilePath& pathBase, |
| 64 int64 database_id, |
| 65 int64 key) { |
| 66 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); |
| 67 path = path.AppendASCII(base::StringPrintf("%" PRIx64, key)); |
| 68 return path; |
| 69 } |
| 70 |
| 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 virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE { |
| 1762 delegate_.reset(delegate.release()); |
| 1763 } |
| 1764 |
| 1765 virtual void ReportWriteCompletion(bool succeeded, |
| 1766 int64 bytes_written) OVERRIDE { |
| 1767 // TODO(ericu): Check bytes_written against the blob's snapshot value. |
| 1768 DCHECK(waiting_for_callback_); |
| 1769 DCHECK(!succeeded || bytes_written >= 0); |
| 1770 waiting_for_callback_ = false; |
| 1771 if (delegate_.get()) // Only present for Blob, not File. |
| 1772 content::BrowserThread::DeleteSoon( |
| 1773 content::BrowserThread::IO, FROM_HERE, delegate_.release()); |
| 1774 if (aborted_) { |
| 1775 self_ref_ = NULL; |
| 1776 return; |
| 1777 } |
| 1778 if (succeeded) |
| 1779 WriteNextFile(); |
| 1780 else |
| 1781 callback_->Run(false); |
| 1782 } |
| 1783 |
| 1784 virtual void Abort() OVERRIDE { |
| 1785 if (!waiting_for_callback_) |
| 1786 return; |
| 1787 self_ref_ = this; |
| 1788 aborted_ = true; |
| 1789 } |
| 1790 |
| 1791 private: |
| 1792 virtual ~ChainedBlobWriterImpl() {} |
| 1793 |
| 1794 void WriteNextFile() { |
| 1795 DCHECK(!waiting_for_callback_); |
| 1796 DCHECK(!aborted_); |
| 1797 if (iter_ == blobs_.end()) { |
| 1798 DCHECK(!self_ref_); |
| 1799 callback_->Run(true); |
| 1800 return; |
| 1801 } else { |
| 1802 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { |
| 1803 callback_->Run(false); |
| 1804 return; |
| 1805 } |
| 1806 waiting_for_callback_ = true; |
| 1807 ++iter_; |
| 1808 } |
| 1809 } |
| 1810 |
| 1811 bool waiting_for_callback_; |
| 1812 scoped_refptr<ChainedBlobWriterImpl> self_ref_; |
| 1813 WriteDescriptorVec blobs_; |
| 1814 WriteDescriptorVec::const_iterator iter_; |
| 1815 int64 database_id_; |
| 1816 IndexedDBBackingStore* backing_store_; |
| 1817 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; |
| 1818 scoped_ptr<FileWriterDelegate> delegate_; |
| 1819 bool aborted_; |
| 1820 }; |
| 1821 |
| 1822 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, |
| 1823 public base::RefCounted<LocalWriteClosure> { |
| 1824 public: |
| 1825 LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter* |
| 1826 chained_blob_writer_, |
| 1827 base::TaskRunner* task_runner) |
| 1828 : chained_blob_writer_(chained_blob_writer_), |
| 1829 task_runner_(task_runner), |
| 1830 bytes_written_(-1) {} |
| 1831 |
| 1832 void Run(base::File::Error rv, |
| 1833 int64 bytes, |
| 1834 FileWriterDelegate::WriteProgressStatus write_status) { |
| 1835 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) |
| 1836 return; // We don't care about progress events. |
| 1837 if (rv == base::File::FILE_OK) { |
| 1838 DCHECK(bytes >= 0); |
| 1839 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); |
| 1840 bytes_written_ = bytes; |
| 1841 } else { |
| 1842 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || |
| 1843 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); |
| 1844 } |
| 1845 task_runner_->PostTask( |
| 1846 FROM_HERE, |
| 1847 base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, |
| 1848 this, |
| 1849 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); |
| 1850 } |
| 1851 |
| 1852 void writeBlobToFileOnIOThread(const FilePath& file_path, |
| 1853 const GURL& blob_url, |
| 1854 net::URLRequestContext* request_context) { |
| 1855 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 1856 scoped_ptr<fileapi::FileStreamWriter> writer( |
| 1857 fileapi::FileStreamWriter::CreateForLocalFile( |
| 1858 task_runner_, file_path, 0, |
| 1859 fileapi::FileStreamWriter::CREATE_NEW_FILE)); |
| 1860 scoped_ptr<FileWriterDelegate> delegate( |
| 1861 new FileWriterDelegate(writer.Pass())); |
| 1862 |
| 1863 DCHECK(blob_url.is_valid()); |
| 1864 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( |
| 1865 blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL)); |
| 1866 |
| 1867 delegate->Start(blob_request.Pass(), |
| 1868 base::Bind(&LocalWriteClosure::Run, this)); |
| 1869 chained_blob_writer_->set_delegate(delegate.Pass()); |
| 1870 } |
| 1871 |
| 1872 private: |
| 1873 virtual ~LocalWriteClosure() {} |
| 1874 friend class base::RefCounted<LocalWriteClosure>; |
| 1875 |
| 1876 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { |
| 1877 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
| 1878 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); |
| 1879 } |
| 1880 |
| 1881 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; |
| 1882 base::TaskRunner* task_runner_; |
| 1883 int64 bytes_written_; |
| 1884 }; |
| 1885 |
| 1886 bool IndexedDBBackingStore::WriteBlobFile( |
| 1887 int64 database_id, |
| 1888 const Transaction::WriteDescriptor& descriptor, |
| 1889 Transaction::ChainedBlobWriter* chained_blob_writer) { |
| 1890 |
| 1891 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) |
| 1892 return false; |
| 1893 |
| 1894 FilePath path = GetBlobFileName(database_id, descriptor.key()); |
| 1895 |
| 1896 if (descriptor.is_file()) { |
| 1897 DCHECK(!descriptor.file_path().empty()); |
| 1898 if (!base::CopyFile(descriptor.file_path(), path)) |
| 1899 return false; |
| 1900 |
| 1901 base::File::Info info; |
| 1902 if (base::GetFileInfo(descriptor.file_path(), &info)) { |
| 1903 // TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor |
| 1904 // to include snapshot date and file size, and check both. |
| 1905 if (!base::TouchFile(path, info.last_accessed, info.last_modified)) { |
| 1906 // TODO(ericu): Complain quietly; timestamp's probably not vital. |
| 1907 } |
| 1908 } else { |
| 1909 // TODO(ericu): Complain quietly; timestamp's probably not vital. |
| 1910 } |
| 1911 |
| 1912 task_runner_->PostTask( |
| 1913 FROM_HERE, |
| 1914 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, |
| 1915 chained_blob_writer, |
| 1916 true, |
| 1917 info.size)); |
| 1918 } else { |
| 1919 DCHECK(descriptor.url().is_valid()); |
| 1920 scoped_refptr<LocalWriteClosure> write_closure( |
| 1921 new LocalWriteClosure(chained_blob_writer, task_runner_)); |
| 1922 content::BrowserThread::PostTask( |
| 1923 content::BrowserThread::IO, |
| 1924 FROM_HERE, |
| 1925 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, |
| 1926 write_closure.get(), |
| 1927 path, |
| 1928 descriptor.url(), |
| 1929 request_context_)); |
| 1930 } |
| 1931 return true; |
| 1932 } |
| 1933 |
| 1934 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. |
| 1935 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { |
| 1936 return GetBlobFileNameForKey(blob_path_, database_id, key); |
| 1937 } |
| 1938 |
1696 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 1939 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
1697 const std::string& stop_key, | 1940 const std::string& stop_key, |
1698 int64 index_id, | 1941 int64 index_id, |
1699 unsigned char meta_data_type) { | 1942 unsigned char meta_data_type) { |
1700 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1943 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
1701 return false; | 1944 return false; |
1702 | 1945 |
1703 StringPiece slice(it->Key()); | 1946 StringPiece slice(it->Key()); |
1704 IndexMetaDataKey meta_data_key; | 1947 IndexMetaDataKey meta_data_key; |
1705 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 1948 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( | 2045 (*indexes)[index_id] = IndexedDBIndexMetadata( |
1803 index_name, index_id, key_path, index_unique, index_multi_entry); | 2046 index_name, index_id, key_path, index_unique, index_multi_entry); |
1804 } | 2047 } |
1805 | 2048 |
1806 if (!s.ok()) | 2049 if (!s.ok()) |
1807 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); | 2050 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); |
1808 | 2051 |
1809 return s; | 2052 return s; |
1810 } | 2053 } |
1811 | 2054 |
| 2055 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { |
| 2056 FilePath fileName = GetBlobFileName(database_id, key); |
| 2057 return base::DeleteFile(fileName, false); |
| 2058 } |
| 2059 |
| 2060 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { |
| 2061 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); |
| 2062 return base::DeleteFile(dirName, true); |
| 2063 } |
| 2064 |
1812 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2065 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
1813 LevelDBTransaction* transaction, | 2066 LevelDBTransaction* transaction, |
1814 int64 database_id, | 2067 int64 database_id, |
1815 int64 object_store_id, | 2068 int64 object_store_id, |
1816 int64 index_id) { | 2069 int64 index_id) { |
1817 int64 max_index_id = -1; | 2070 int64 max_index_id = -1; |
1818 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2071 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
1819 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2072 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
1820 bool found = false; | 2073 bool found = false; |
1821 leveldb::Status s = | 2074 leveldb::Status s = |
(...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2939 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { | 3192 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { |
2940 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3193 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); |
2941 DCHECK(transaction_.get()); | 3194 DCHECK(transaction_.get()); |
2942 leveldb::Status s = transaction_->Commit(); | 3195 leveldb::Status s = transaction_->Commit(); |
2943 transaction_ = NULL; | 3196 transaction_ = NULL; |
2944 if (!s.ok()) | 3197 if (!s.ok()) |
2945 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 3198 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); |
2946 return s; | 3199 return s; |
2947 } | 3200 } |
2948 | 3201 |
| 3202 |
| 3203 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper |
| 3204 : public IndexedDBBackingStore::BlobWriteCallback { |
| 3205 public: |
| 3206 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, |
| 3207 scoped_refptr<BlobWriteCallback> callback) |
| 3208 : transaction_(transaction), callback_(callback) {} |
| 3209 virtual void Run(bool succeeded) OVERRIDE { |
| 3210 callback_->Run(succeeded); |
| 3211 transaction_->chained_blob_writer_ = NULL; |
| 3212 } |
| 3213 |
| 3214 private: |
| 3215 virtual ~BlobWriteCallbackWrapper() {} |
| 3216 friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>; |
| 3217 |
| 3218 IndexedDBBackingStore::Transaction* transaction_; |
| 3219 scoped_refptr<BlobWriteCallback> callback_; |
| 3220 }; |
| 3221 |
| 3222 void IndexedDBBackingStore::Transaction::WriteNewBlobs( |
| 3223 BlobEntryKeyValuePairVec& new_blob_entries, |
| 3224 WriteDescriptorVec& new_files_to_write, |
| 3225 scoped_refptr<BlobWriteCallback> callback) { |
| 3226 DCHECK_GT(new_files_to_write.size(), 0UL); |
| 3227 DCHECK_GT(database_id_, 0); |
| 3228 BlobEntryKeyValuePairVec::iterator blob_entry_iter; |
| 3229 for (blob_entry_iter = new_blob_entries.begin(); |
| 3230 blob_entry_iter != new_blob_entries.end(); |
| 3231 ++blob_entry_iter) { |
| 3232 // Add the new blob-table entry for each blob to the main transaction, or |
| 3233 // remove any entry that may exist if there's no new one. |
| 3234 if (!blob_entry_iter->second.size()) |
| 3235 transaction_->Remove(blob_entry_iter->first.Encode()); |
| 3236 else |
| 3237 transaction_->Put(blob_entry_iter->first.Encode(), |
| 3238 &blob_entry_iter->second); |
| 3239 } |
| 3240 // Creating the writer will start it going asynchronously. |
| 3241 chained_blob_writer_ = |
| 3242 new ChainedBlobWriterImpl(database_id_, |
| 3243 backing_store_, |
| 3244 new_files_to_write, |
| 3245 new BlobWriteCallbackWrapper(this, callback)); |
| 3246 } |
| 3247 |
2949 void IndexedDBBackingStore::Transaction::Rollback() { | 3248 void IndexedDBBackingStore::Transaction::Rollback() { |
2950 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3249 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
2951 DCHECK(transaction_.get()); | 3250 DCHECK(transaction_.get()); |
| 3251 if (chained_blob_writer_) { |
| 3252 chained_blob_writer_->Abort(); |
| 3253 chained_blob_writer_ = NULL; |
| 3254 } |
2952 transaction_->Rollback(); | 3255 transaction_->Rollback(); |
2953 transaction_ = NULL; | 3256 transaction_ = NULL; |
2954 } | 3257 } |
2955 | 3258 |
2956 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( | 3259 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( |
2957 const std::string& key, int64 object_store_id) | 3260 const std::string& key, int64 object_store_id) |
2958 : key_(key), object_store_id_(object_store_id) { | 3261 : key_(key), object_store_id_(object_store_id) { |
2959 } | 3262 } |
2960 | 3263 |
2961 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { | 3264 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2997 blob_change_map_[key] = record; | 3300 blob_change_map_[key] = record; |
2998 } else { | 3301 } else { |
2999 record = it->second; | 3302 record = it->second; |
3000 } | 3303 } |
3001 DCHECK_EQ(record->object_store_id(), object_store_id); | 3304 DCHECK_EQ(record->object_store_id(), object_store_id); |
3002 record->SetBlobInfo(blob_info); | 3305 record->SetBlobInfo(blob_info); |
3003 record->SetHandles(handles); | 3306 record->SetHandles(handles); |
3004 DCHECK(!handles || !handles->size()); | 3307 DCHECK(!handles || !handles->size()); |
3005 } | 3308 } |
3006 | 3309 |
| 3310 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
| 3311 const GURL& url, |
| 3312 int64_t key) |
| 3313 : is_file_(false), url_(url), key_(key) {} |
| 3314 |
| 3315 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
| 3316 const FilePath& file_path, |
| 3317 int64_t key) |
| 3318 : is_file_(true), file_path_(file_path), key_(key) {} |
| 3319 |
3007 } // namespace content | 3320 } // namespace content |
OLD | NEW |