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 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | |
| 63 bool MakeIDBBlobDirectory(const FilePath& pathBase, | |
| 64 int64 database_id, | |
| 65 int64 key) { | |
| 66 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); | |
| 67 return base::CreateDirectory(path); | |
| 68 } | |
| 69 | |
| 41 static std::string ComputeOriginIdentifier(const GURL& origin_url) { | 70 static std::string ComputeOriginIdentifier(const GURL& origin_url) { |
| 42 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; | 71 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; |
| 43 } | 72 } |
| 44 | 73 |
| 45 static base::FilePath ComputeFileName(const GURL& origin_url) { | 74 static base::FilePath ComputeFileName(const GURL& origin_url) { |
| 46 return base::FilePath() | 75 return base::FilePath() |
| 47 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | 76 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) |
| 48 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 77 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); |
| 49 } | 78 } |
| 50 | 79 |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 434 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) | 463 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) |
| 435 OVERRIDE { | 464 OVERRIDE { |
| 436 return LevelDBDatabase::Destroy(file_name); | 465 return LevelDBDatabase::Destroy(file_name); |
| 437 } | 466 } |
| 438 }; | 467 }; |
| 439 | 468 |
| 440 IndexedDBBackingStore::IndexedDBBackingStore( | 469 IndexedDBBackingStore::IndexedDBBackingStore( |
| 441 IndexedDBFactory* indexed_db_factory, | 470 IndexedDBFactory* indexed_db_factory, |
| 442 const GURL& origin_url, | 471 const GURL& origin_url, |
| 443 const base::FilePath& blob_path, | 472 const base::FilePath& blob_path, |
| 473 net::URLRequestContext* request_context, | |
| 444 scoped_ptr<LevelDBDatabase> db, | 474 scoped_ptr<LevelDBDatabase> db, |
| 445 scoped_ptr<LevelDBComparator> comparator, | 475 scoped_ptr<LevelDBComparator> comparator, |
| 446 base::TaskRunner* task_runner) | 476 base::TaskRunner* task_runner) |
| 447 : indexed_db_factory_(indexed_db_factory), | 477 : indexed_db_factory_(indexed_db_factory), |
| 448 origin_url_(origin_url), | 478 origin_url_(origin_url), |
| 449 blob_path_(blob_path), | 479 blob_path_(blob_path), |
| 450 origin_identifier_(ComputeOriginIdentifier(origin_url)), | 480 origin_identifier_(ComputeOriginIdentifier(origin_url)), |
| 481 request_context_(request_context), | |
| 451 task_runner_(task_runner), | 482 task_runner_(task_runner), |
| 452 db_(db.Pass()), | 483 db_(db.Pass()), |
| 453 comparator_(comparator.Pass()), | 484 comparator_(comparator.Pass()), |
| 454 active_blob_registry_(this) {} | 485 active_blob_registry_(this) {} |
| 455 | 486 |
| 456 IndexedDBBackingStore::~IndexedDBBackingStore() { | 487 IndexedDBBackingStore::~IndexedDBBackingStore() { |
| 457 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { | 488 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { |
| 458 ChildProcessSecurityPolicyImpl* policy = | 489 ChildProcessSecurityPolicyImpl* policy = |
| 459 ChildProcessSecurityPolicyImpl::GetInstance(); | 490 ChildProcessSecurityPolicyImpl::GetInstance(); |
| 460 std::set<int>::const_iterator iter; | 491 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, | 530 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, |
| 500 INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, | 531 INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, |
| 501 INDEXED_DB_BACKING_STORE_OPEN_MAX, | 532 INDEXED_DB_BACKING_STORE_OPEN_MAX, |
| 502 }; | 533 }; |
| 503 | 534 |
| 504 // static | 535 // static |
| 505 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 536 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 506 IndexedDBFactory* indexed_db_factory, | 537 IndexedDBFactory* indexed_db_factory, |
| 507 const GURL& origin_url, | 538 const GURL& origin_url, |
| 508 const base::FilePath& path_base, | 539 const base::FilePath& path_base, |
| 540 net::URLRequestContext* request_context, | |
| 509 blink::WebIDBDataLoss* data_loss, | 541 blink::WebIDBDataLoss* data_loss, |
| 510 std::string* data_loss_message, | 542 std::string* data_loss_message, |
| 511 bool* disk_full, | 543 bool* disk_full, |
| 512 base::TaskRunner* task_runner) { | 544 base::TaskRunner* task_runner) { |
| 513 *data_loss = blink::WebIDBDataLossNone; | 545 *data_loss = blink::WebIDBDataLossNone; |
| 514 DefaultLevelDBFactory leveldb_factory; | 546 DefaultLevelDBFactory leveldb_factory; |
| 515 return IndexedDBBackingStore::Open(indexed_db_factory, | 547 return IndexedDBBackingStore::Open(indexed_db_factory, |
| 516 origin_url, | 548 origin_url, |
| 517 path_base, | 549 path_base, |
| 550 request_context, | |
| 518 data_loss, | 551 data_loss, |
| 519 data_loss_message, | 552 data_loss_message, |
| 520 disk_full, | 553 disk_full, |
| 521 &leveldb_factory, | 554 &leveldb_factory, |
| 522 task_runner); | 555 task_runner); |
| 523 } | 556 } |
| 524 | 557 |
| 525 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { | 558 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { |
| 526 if (origin_url.host() == "docs.google.com") | 559 if (origin_url.host() == "docs.google.com") |
| 527 return ".Docs"; | 560 return ".Docs"; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 648 return false; | 681 return false; |
| 649 int written = file.Write(0, output_js.c_str(), output_js.length()); | 682 int written = file.Write(0, output_js.c_str(), output_js.length()); |
| 650 return size_t(written) == output_js.length(); | 683 return size_t(written) == output_js.length(); |
| 651 } | 684 } |
| 652 | 685 |
| 653 // static | 686 // static |
| 654 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 687 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
| 655 IndexedDBFactory* indexed_db_factory, | 688 IndexedDBFactory* indexed_db_factory, |
| 656 const GURL& origin_url, | 689 const GURL& origin_url, |
| 657 const base::FilePath& path_base, | 690 const base::FilePath& path_base, |
| 691 net::URLRequestContext* request_context, | |
| 658 blink::WebIDBDataLoss* data_loss, | 692 blink::WebIDBDataLoss* data_loss, |
| 659 std::string* data_loss_message, | 693 std::string* data_loss_message, |
| 660 bool* is_disk_full, | 694 bool* is_disk_full, |
| 661 LevelDBFactory* leveldb_factory, | 695 LevelDBFactory* leveldb_factory, |
| 662 base::TaskRunner* task_runner) { | 696 base::TaskRunner* task_runner) { |
| 663 IDB_TRACE("IndexedDBBackingStore::Open"); | 697 IDB_TRACE("IndexedDBBackingStore::Open"); |
| 664 DCHECK(!path_base.empty()); | 698 DCHECK(!path_base.empty()); |
| 665 *data_loss = blink::WebIDBDataLossNone; | 699 *data_loss = blink::WebIDBDataLossNone; |
| 666 *data_loss_message = ""; | 700 *data_loss_message = ""; |
| 667 *is_disk_full = false; | 701 *is_disk_full = false; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 773 if (!db) { | 807 if (!db) { |
| 774 NOTREACHED(); | 808 NOTREACHED(); |
| 775 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, | 809 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, |
| 776 origin_url); | 810 origin_url); |
| 777 return scoped_refptr<IndexedDBBackingStore>(); | 811 return scoped_refptr<IndexedDBBackingStore>(); |
| 778 } | 812 } |
| 779 | 813 |
| 780 return Create(indexed_db_factory, | 814 return Create(indexed_db_factory, |
| 781 origin_url, | 815 origin_url, |
| 782 blob_path, | 816 blob_path, |
| 817 request_context, | |
| 783 db.Pass(), | 818 db.Pass(), |
| 784 comparator.Pass(), | 819 comparator.Pass(), |
| 785 task_runner); | 820 task_runner); |
| 786 } | 821 } |
| 787 | 822 |
| 788 // static | 823 // static |
| 789 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 824 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
| 790 const GURL& origin_url, | 825 const GURL& origin_url, |
| 791 base::TaskRunner* task_runner) { | 826 base::TaskRunner* task_runner) { |
| 792 DefaultLevelDBFactory leveldb_factory; | 827 DefaultLevelDBFactory leveldb_factory; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 808 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; | 843 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; |
| 809 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 844 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
| 810 origin_url); | 845 origin_url); |
| 811 return scoped_refptr<IndexedDBBackingStore>(); | 846 return scoped_refptr<IndexedDBBackingStore>(); |
| 812 } | 847 } |
| 813 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); | 848 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); |
| 814 | 849 |
| 815 return Create(NULL /* indexed_db_factory */, | 850 return Create(NULL /* indexed_db_factory */, |
| 816 origin_url, | 851 origin_url, |
| 817 base::FilePath(), | 852 base::FilePath(), |
| 853 NULL /* request_context */, | |
| 818 db.Pass(), | 854 db.Pass(), |
| 819 comparator.Pass(), | 855 comparator.Pass(), |
| 820 task_runner); | 856 task_runner); |
| 821 } | 857 } |
| 822 | 858 |
| 823 // static | 859 // static |
| 824 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 860 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( |
| 825 IndexedDBFactory* indexed_db_factory, | 861 IndexedDBFactory* indexed_db_factory, |
| 826 const GURL& origin_url, | 862 const GURL& origin_url, |
| 827 const base::FilePath& blob_path, | 863 const base::FilePath& blob_path, |
| 864 net::URLRequestContext* request_context, | |
| 828 scoped_ptr<LevelDBDatabase> db, | 865 scoped_ptr<LevelDBDatabase> db, |
| 829 scoped_ptr<LevelDBComparator> comparator, | 866 scoped_ptr<LevelDBComparator> comparator, |
| 830 base::TaskRunner* task_runner) { | 867 base::TaskRunner* task_runner) { |
| 831 // TODO(jsbell): Handle comparator name changes. | 868 // TODO(jsbell): Handle comparator name changes. |
| 832 | |
| 833 scoped_refptr<IndexedDBBackingStore> backing_store( | 869 scoped_refptr<IndexedDBBackingStore> backing_store( |
| 834 new IndexedDBBackingStore(indexed_db_factory, | 870 new IndexedDBBackingStore(indexed_db_factory, |
| 835 origin_url, | 871 origin_url, |
| 836 blob_path, | 872 blob_path, |
| 873 request_context, | |
| 837 db.Pass(), | 874 db.Pass(), |
| 838 comparator.Pass(), | 875 comparator.Pass(), |
| 839 task_runner)); | 876 task_runner)); |
| 840 if (!SetUpMetadata(backing_store->db_.get(), | 877 if (!SetUpMetadata(backing_store->db_.get(), |
| 841 backing_store->origin_identifier_)) | 878 backing_store->origin_identifier_)) |
| 842 return scoped_refptr<IndexedDBBackingStore>(); | 879 return scoped_refptr<IndexedDBBackingStore>(); |
| 843 | 880 |
| 844 return backing_store; | 881 return backing_store; |
| 845 } | 882 } |
| 846 | 883 |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1686 StringPiece slice(data); | 1723 StringPiece slice(data); |
| 1687 if (!DecodeVarInt(&slice, &version)) | 1724 if (!DecodeVarInt(&slice, &version)) |
| 1688 return InternalInconsistencyStatus(); | 1725 return InternalInconsistencyStatus(); |
| 1689 | 1726 |
| 1690 std::string encoded_key; | 1727 std::string encoded_key; |
| 1691 EncodeIDBKey(key, &encoded_key); | 1728 EncodeIDBKey(key, &encoded_key); |
| 1692 found_record_identifier->Reset(encoded_key, version); | 1729 found_record_identifier->Reset(encoded_key, version); |
| 1693 return s; | 1730 return s; |
| 1694 } | 1731 } |
| 1695 | 1732 |
| 1733 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl | |
| 1734 : public IndexedDBBackingStore::Transaction::ChainedBlobWriter { | |
| 1735 public: | |
| 1736 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec | |
| 1737 WriteDescriptorVec; | |
| 1738 ChainedBlobWriterImpl( | |
| 1739 int64 database_id, | |
| 1740 IndexedDBBackingStore* backingStore, | |
| 1741 WriteDescriptorVec& blobs, | |
| 1742 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) | |
| 1743 : waiting_for_callback_(false), | |
| 1744 database_id_(database_id), | |
| 1745 backing_store_(backingStore), | |
| 1746 callback_(callback), | |
| 1747 aborted_(false) { | |
| 1748 blobs_.swap(blobs); | |
| 1749 iter_ = blobs_.begin(); | |
| 1750 WriteNextFile(); | |
|
cmumford
2014/04/18 17:19:06
By writing the first file in the constructor do yo
ericu
2014/04/21 20:54:19
No, the delegate gets set in writeBlobToFileOnIOTh
| |
| 1751 } | |
| 1752 | |
| 1753 void set_delegate(scoped_ptr<FileWriterDelegate> delegate) { | |
| 1754 delegate_.reset(delegate.release()); | |
| 1755 } | |
| 1756 | |
| 1757 void ReportWriteCompletion(bool succeeded, int64 bytes_written) { | |
| 1758 // TODO(ericu): Check bytes_written against the blob's snapshot value. | |
| 1759 DCHECK(waiting_for_callback_); | |
| 1760 DCHECK(!succeeded || bytes_written >= 0); | |
| 1761 waiting_for_callback_ = false; | |
| 1762 content::BrowserThread::DeleteSoon( | |
| 1763 content::BrowserThread::IO, FROM_HERE, delegate_.release()); | |
| 1764 if (aborted_) { | |
| 1765 self_ref_ = NULL; | |
| 1766 return; | |
| 1767 } | |
| 1768 if (succeeded) | |
| 1769 WriteNextFile(); | |
| 1770 else | |
| 1771 callback_->DidFail(); | |
| 1772 } | |
| 1773 | |
| 1774 void Abort() { | |
| 1775 if (!waiting_for_callback_) | |
| 1776 return; | |
| 1777 self_ref_ = this; | |
| 1778 aborted_ = true; | |
| 1779 } | |
| 1780 | |
| 1781 private: | |
| 1782 void WriteNextFile() { | |
| 1783 DCHECK(!waiting_for_callback_); | |
| 1784 DCHECK(!aborted_); | |
| 1785 if (iter_ == blobs_.end()) { | |
| 1786 DCHECK(!self_ref_); | |
| 1787 callback_->DidSucceed(); | |
| 1788 return; | |
| 1789 } else { | |
| 1790 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { | |
| 1791 callback_->DidFail(); | |
| 1792 return; | |
| 1793 } | |
| 1794 waiting_for_callback_ = true; | |
| 1795 ++iter_; | |
| 1796 } | |
| 1797 } | |
| 1798 | |
| 1799 bool waiting_for_callback_; | |
| 1800 scoped_refptr<ChainedBlobWriterImpl> self_ref_; | |
|
cmumford
2014/04/18 17:19:06
having a self reference seems like a scary way to
ericu
2014/04/21 20:54:19
It's safe for us to outlive the backing store. Th
| |
| 1801 WriteDescriptorVec blobs_; | |
| 1802 WriteDescriptorVec::const_iterator iter_; | |
| 1803 int64 database_id_; | |
| 1804 IndexedDBBackingStore* backing_store_; | |
| 1805 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; | |
| 1806 scoped_ptr<FileWriterDelegate> delegate_; | |
| 1807 bool aborted_; | |
| 1808 }; | |
| 1809 | |
| 1810 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, | |
| 1811 public base::RefCounted<LocalWriteClosure> { | |
| 1812 public: | |
| 1813 LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter* | |
| 1814 chained_blob_writer_, | |
| 1815 base::TaskRunner* task_runner) | |
| 1816 : chained_blob_writer_(chained_blob_writer_), | |
| 1817 task_runner_(task_runner), | |
| 1818 bytes_written_(-1) {} | |
| 1819 | |
| 1820 void Run(base::File::Error rv, | |
| 1821 int64 bytes, | |
| 1822 FileWriterDelegate::WriteProgressStatus write_status) { | |
| 1823 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) | |
| 1824 return; // We don't care about progress events. | |
| 1825 if (rv == base::File::FILE_OK) { | |
| 1826 DCHECK(bytes >= 0); | |
| 1827 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); | |
| 1828 bytes_written_ = bytes; | |
| 1829 } else { | |
| 1830 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || | |
| 1831 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); | |
| 1832 } | |
| 1833 task_runner_->PostTask( | |
| 1834 FROM_HERE, | |
| 1835 base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, | |
| 1836 this, | |
| 1837 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); | |
| 1838 } | |
| 1839 | |
| 1840 void writeBlobToFileOnIOThread(const FilePath& file_path, | |
| 1841 const GURL& blob_url, | |
| 1842 net::URLRequestContext* request_context) { | |
| 1843 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 1844 scoped_ptr<fileapi::FileStreamWriter> writer( | |
| 1845 fileapi::FileStreamWriter::CreateForLocalFile( | |
| 1846 task_runner_, file_path, 0, | |
| 1847 fileapi::FileStreamWriter::CREATE_NEW_FILE)); | |
| 1848 scoped_ptr<FileWriterDelegate> delegate( | |
| 1849 new FileWriterDelegate(writer.Pass())); | |
| 1850 | |
| 1851 DCHECK(blob_url.is_valid()); | |
| 1852 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( | |
| 1853 blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL)); | |
| 1854 | |
| 1855 delegate->Start(blob_request.Pass(), | |
| 1856 base::Bind(&LocalWriteClosure::Run, this)); | |
| 1857 chained_blob_writer_->set_delegate(delegate.Pass()); | |
| 1858 } | |
| 1859 | |
| 1860 private: | |
| 1861 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { | |
| 1862 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
| 1863 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); | |
| 1864 } | |
| 1865 | |
| 1866 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; | |
| 1867 base::TaskRunner* task_runner_; | |
| 1868 int64 bytes_written_; | |
| 1869 }; | |
| 1870 | |
| 1871 bool IndexedDBBackingStore::WriteBlobFile( | |
| 1872 int64 database_id, | |
| 1873 const Transaction::WriteDescriptor& descriptor, | |
| 1874 Transaction::ChainedBlobWriter* chained_blob_writer) { | |
| 1875 | |
| 1876 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) | |
| 1877 return false; | |
|
cmumford
2014/04/18 17:19:06
If we can't create the dir (or copy the file below
ericu
2014/04/21 20:54:19
We return false, and WriteNextFile [our only calle
| |
| 1878 | |
| 1879 FilePath path = GetBlobFileName(database_id, descriptor.key()); | |
| 1880 | |
| 1881 if (descriptor.is_file()) { | |
| 1882 DCHECK(!descriptor.file_path().empty()); | |
| 1883 if (!base::CopyFile(descriptor.file_path(), path)) | |
| 1884 return false; | |
| 1885 | |
| 1886 base::File::Info info; | |
| 1887 if (base::GetFileInfo(descriptor.file_path(), &info)) { | |
| 1888 // TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor | |
| 1889 // to include snapshot date and file size, and check both. | |
| 1890 if (!base::TouchFile(path, info.last_accessed, info.last_modified)) | |
| 1891 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 1892 } else { | |
| 1893 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
| 1894 } | |
| 1895 | |
| 1896 task_runner_->PostTask( | |
| 1897 FROM_HERE, | |
| 1898 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
| 1899 chained_blob_writer, | |
| 1900 true, | |
| 1901 info.size)); | |
| 1902 } else { | |
| 1903 DCHECK(descriptor.url().is_valid()); | |
| 1904 scoped_refptr<LocalWriteClosure> write_closure( | |
| 1905 new LocalWriteClosure(chained_blob_writer, task_runner_)); | |
| 1906 content::BrowserThread::PostTask( | |
| 1907 content::BrowserThread::IO, | |
| 1908 FROM_HERE, | |
| 1909 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, | |
| 1910 write_closure.get(), | |
| 1911 path, | |
| 1912 descriptor.url(), | |
| 1913 request_context_)); | |
| 1914 } | |
| 1915 return true; | |
| 1916 } | |
| 1917 | |
| 1918 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | |
| 1919 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { | |
| 1920 FilePath path = GetBlobDirectoryNameForKey(blob_path_, database_id, key); | |
| 1921 path = path.AppendASCII(base::StringPrintf("%lx", key)); | |
| 1922 return path; | |
| 1923 } | |
| 1924 | |
| 1696 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 1925 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
| 1697 const std::string& stop_key, | 1926 const std::string& stop_key, |
| 1698 int64 index_id, | 1927 int64 index_id, |
| 1699 unsigned char meta_data_type) { | 1928 unsigned char meta_data_type) { |
| 1700 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1929 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
| 1701 return false; | 1930 return false; |
| 1702 | 1931 |
| 1703 StringPiece slice(it->Key()); | 1932 StringPiece slice(it->Key()); |
| 1704 IndexMetaDataKey meta_data_key; | 1933 IndexMetaDataKey meta_data_key; |
| 1705 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 1934 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( | 2031 (*indexes)[index_id] = IndexedDBIndexMetadata( |
| 1803 index_name, index_id, key_path, index_unique, index_multi_entry); | 2032 index_name, index_id, key_path, index_unique, index_multi_entry); |
| 1804 } | 2033 } |
| 1805 | 2034 |
| 1806 if (!s.ok()) | 2035 if (!s.ok()) |
| 1807 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); | 2036 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); |
| 1808 | 2037 |
| 1809 return s; | 2038 return s; |
| 1810 } | 2039 } |
| 1811 | 2040 |
| 2041 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | |
| 2042 FilePath fileName = GetBlobFileName(database_id, key); | |
| 2043 return base::DeleteFile(fileName, false); | |
| 2044 } | |
| 2045 | |
| 2046 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | |
| 2047 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); | |
| 2048 return base::DeleteFile(dirName, true); | |
| 2049 } | |
| 2050 | |
| 1812 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2051 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
| 1813 LevelDBTransaction* transaction, | 2052 LevelDBTransaction* transaction, |
| 1814 int64 database_id, | 2053 int64 database_id, |
| 1815 int64 object_store_id, | 2054 int64 object_store_id, |
| 1816 int64 index_id) { | 2055 int64 index_id) { |
| 1817 int64 max_index_id = -1; | 2056 int64 max_index_id = -1; |
| 1818 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2057 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
| 1819 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2058 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
| 1820 bool found = false; | 2059 bool found = false; |
| 1821 leveldb::Status s = | 2060 leveldb::Status s = |
| (...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2939 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { | 3178 leveldb::Status IndexedDBBackingStore::Transaction::Commit() { |
| 2940 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3179 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); |
| 2941 DCHECK(transaction_.get()); | 3180 DCHECK(transaction_.get()); |
| 2942 leveldb::Status s = transaction_->Commit(); | 3181 leveldb::Status s = transaction_->Commit(); |
| 2943 transaction_ = NULL; | 3182 transaction_ = NULL; |
| 2944 if (!s.ok()) | 3183 if (!s.ok()) |
| 2945 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); | 3184 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); |
| 2946 return s; | 3185 return s; |
| 2947 } | 3186 } |
| 2948 | 3187 |
| 3188 | |
| 3189 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper | |
| 3190 : public IndexedDBBackingStore::BlobWriteCallback { | |
| 3191 public: | |
| 3192 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, | |
| 3193 scoped_refptr<BlobWriteCallback> callback) | |
| 3194 : transaction_(transaction), callback_(callback) {} | |
| 3195 virtual void DidSucceed() { | |
| 3196 callback_->DidSucceed(); | |
| 3197 transaction_->chained_blob_writer_ = NULL; | |
| 3198 } | |
| 3199 virtual void DidFail() { | |
| 3200 callback_->DidFail(); | |
| 3201 transaction_->chained_blob_writer_ = NULL; | |
| 3202 } | |
| 3203 | |
| 3204 private: | |
| 3205 IndexedDBBackingStore::Transaction* transaction_; | |
| 3206 scoped_refptr<BlobWriteCallback> callback_; | |
| 3207 }; | |
| 3208 | |
| 3209 void IndexedDBBackingStore::Transaction::WriteNewBlobs( | |
| 3210 BlobEntryKeyValuePairVec& new_blob_entries, | |
| 3211 WriteDescriptorVec& new_files_to_write, | |
| 3212 scoped_refptr<BlobWriteCallback> callback) { | |
| 3213 DCHECK_GT(new_files_to_write.size(), 0UL); | |
| 3214 DCHECK_GT(database_id_, 0); | |
| 3215 BlobEntryKeyValuePairVec::iterator blob_entry_iter; | |
| 3216 for (blob_entry_iter = new_blob_entries.begin(); | |
| 3217 blob_entry_iter != new_blob_entries.end(); | |
| 3218 ++blob_entry_iter) { | |
| 3219 // Add the new blob-table entry for each blob to the main transaction, or | |
| 3220 // remove any entry that may exist if there's no new one. | |
| 3221 if (!blob_entry_iter->second.size()) | |
| 3222 transaction_->Remove(blob_entry_iter->first.Encode()); | |
| 3223 else | |
| 3224 transaction_->Put(blob_entry_iter->first.Encode(), | |
| 3225 &blob_entry_iter->second); | |
| 3226 } | |
| 3227 // Creating the writer will start it going asynchronously. | |
| 3228 chained_blob_writer_ = | |
| 3229 new ChainedBlobWriterImpl(database_id_, | |
| 3230 backing_store_, | |
| 3231 new_files_to_write, | |
| 3232 new BlobWriteCallbackWrapper(this, callback)); | |
| 3233 } | |
| 3234 | |
| 2949 void IndexedDBBackingStore::Transaction::Rollback() { | 3235 void IndexedDBBackingStore::Transaction::Rollback() { |
| 2950 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3236 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
| 2951 DCHECK(transaction_.get()); | 3237 DCHECK(transaction_.get()); |
| 3238 if (chained_blob_writer_) { | |
| 3239 chained_blob_writer_->Abort(); | |
| 3240 chained_blob_writer_ = NULL; | |
| 3241 } | |
| 2952 transaction_->Rollback(); | 3242 transaction_->Rollback(); |
| 2953 transaction_ = NULL; | 3243 transaction_ = NULL; |
| 2954 } | 3244 } |
| 2955 | 3245 |
| 2956 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( | 3246 IndexedDBBackingStore::Transaction::BlobChangeRecord::BlobChangeRecord( |
| 2957 const std::string& key, int64 object_store_id) | 3247 const std::string& key, int64 object_store_id) |
| 2958 : key_(key), object_store_id_(object_store_id) { | 3248 : key_(key), object_store_id_(object_store_id) { |
| 2959 } | 3249 } |
| 2960 | 3250 |
| 2961 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { | 3251 IndexedDBBackingStore::Transaction::BlobChangeRecord::~BlobChangeRecord() { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2997 blob_change_map_[key] = record; | 3287 blob_change_map_[key] = record; |
| 2998 } else { | 3288 } else { |
| 2999 record = it->second; | 3289 record = it->second; |
| 3000 } | 3290 } |
| 3001 DCHECK_EQ(record->object_store_id(), object_store_id); | 3291 DCHECK_EQ(record->object_store_id(), object_store_id); |
| 3002 record->SetBlobInfo(blob_info); | 3292 record->SetBlobInfo(blob_info); |
| 3003 record->SetHandles(handles); | 3293 record->SetHandles(handles); |
| 3004 DCHECK(!handles || !handles->size()); | 3294 DCHECK(!handles || !handles->size()); |
| 3005 } | 3295 } |
| 3006 | 3296 |
| 3297 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3298 const GURL& url, | |
| 3299 int64_t key) | |
| 3300 : is_file_(false), url_(url), key_(key) {} | |
| 3301 | |
| 3302 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3303 const FilePath& file_path, | |
| 3304 int64_t key) | |
| 3305 : is_file_(true), file_path_(file_path), key_(key) {} | |
| 3306 | |
| 3007 } // namespace content | 3307 } // namespace content |
| OLD | NEW |