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/format_macros.h" |
10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 SET_MAX_OBJECT_STORE_ID, | 119 SET_MAX_OBJECT_STORE_ID, |
120 SET_MAX_INDEX_ID, | 120 SET_MAX_INDEX_ID, |
121 GET_NEW_DATABASE_ID, | 121 GET_NEW_DATABASE_ID, |
122 GET_NEW_VERSION_NUMBER, | 122 GET_NEW_VERSION_NUMBER, |
123 CREATE_IDBDATABASE_METADATA, | 123 CREATE_IDBDATABASE_METADATA, |
124 DELETE_DATABASE, | 124 DELETE_DATABASE, |
125 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro | 125 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro |
126 GET_DATABASE_NAMES, | 126 GET_DATABASE_NAMES, |
127 DELETE_INDEX, | 127 DELETE_INDEX, |
128 CLEAR_OBJECT_STORE, | 128 CLEAR_OBJECT_STORE, |
| 129 READ_BLOB_JOURNAL, |
| 130 DECODE_BLOB_JOURNAL, |
129 INTERNAL_ERROR_MAX, | 131 INTERNAL_ERROR_MAX, |
130 }; | 132 }; |
131 | 133 |
132 static void RecordInternalError(const char* type, | 134 static void RecordInternalError(const char* type, |
133 IndexedDBBackingStoreErrorSource location) { | 135 IndexedDBBackingStoreErrorSource location) { |
134 std::string name; | 136 std::string name; |
135 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 137 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); |
136 base::Histogram::FactoryGet(name, | 138 base::Histogram::FactoryGet(name, |
137 1, | 139 1, |
138 INTERNAL_ERROR_MAX, | 140 INTERNAL_ERROR_MAX, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 // Was able to use LevelDB to read the data w/o error, but the data read was not | 187 // Was able to use LevelDB to read the data w/o error, but the data read was not |
186 // in the expected format. | 188 // in the expected format. |
187 static leveldb::Status InternalInconsistencyStatus() { | 189 static leveldb::Status InternalInconsistencyStatus() { |
188 return leveldb::Status::Corruption("Internal inconsistency"); | 190 return leveldb::Status::Corruption("Internal inconsistency"); |
189 } | 191 } |
190 | 192 |
191 static leveldb::Status InvalidDBKeyStatus() { | 193 static leveldb::Status InvalidDBKeyStatus() { |
192 return leveldb::Status::InvalidArgument("Invalid database key ID"); | 194 return leveldb::Status::InvalidArgument("Invalid database key ID"); |
193 } | 195 } |
194 | 196 |
| 197 static leveldb::Status IOErrorStatus() { |
| 198 return leveldb::Status::IOError("IO Error"); |
| 199 } |
| 200 |
195 template <typename DBOrTransaction> | 201 template <typename DBOrTransaction> |
196 static leveldb::Status GetInt(DBOrTransaction* db, | 202 static leveldb::Status GetInt(DBOrTransaction* db, |
197 const StringPiece& key, | 203 const StringPiece& key, |
198 int64* found_int, | 204 int64* found_int, |
199 bool* found) { | 205 bool* found) { |
200 std::string result; | 206 std::string result; |
201 leveldb::Status s = db->Get(key, &result, found); | 207 leveldb::Status s = db->Get(key, &result, found); |
202 if (!s.ok()) | 208 if (!s.ok()) |
203 return s; | 209 return s; |
204 if (!*found) | 210 if (!*found) |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 scoped_ptr<LevelDBDatabase>* db, | 473 scoped_ptr<LevelDBDatabase>* db, |
468 bool* is_disk_full) OVERRIDE { | 474 bool* is_disk_full) OVERRIDE { |
469 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 475 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
470 } | 476 } |
471 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) | 477 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) |
472 OVERRIDE { | 478 OVERRIDE { |
473 return LevelDBDatabase::Destroy(file_name); | 479 return LevelDBDatabase::Destroy(file_name); |
474 } | 480 } |
475 }; | 481 }; |
476 | 482 |
| 483 // TODO(ericu): Error recovery. If we persistently can't read the |
| 484 // blob journal, the safe thing to do is to clear it and leak the blobs, |
| 485 // though that may be costly. Still, database/directory deletion should always |
| 486 // clean things up, and we can write an fsck that will do a full correction if |
| 487 // need be. |
| 488 template <typename T> |
| 489 static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key, |
| 490 T* leveldb_transaction, |
| 491 BlobJournalType* journal) { |
| 492 std::string data; |
| 493 bool found = false; |
| 494 leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found); |
| 495 if (!s.ok()) { |
| 496 INTERNAL_READ_ERROR_UNTESTED(READ_BLOB_JOURNAL); |
| 497 return s; |
| 498 } |
| 499 journal->clear(); |
| 500 if (!found || !data.size()) |
| 501 return leveldb::Status::OK(); |
| 502 StringPiece slice(data); |
| 503 if (!DecodeBlobJournal(&slice, journal)) { |
| 504 INTERNAL_READ_ERROR_UNTESTED(DECODE_BLOB_JOURNAL); |
| 505 s = InternalInconsistencyStatus(); |
| 506 } |
| 507 return s; |
| 508 } |
| 509 |
| 510 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, |
| 511 const std::string& level_db_key) { |
| 512 leveldb_transaction->Remove(level_db_key); |
| 513 } |
| 514 |
| 515 static void UpdatePrimaryJournalWithBlobList( |
| 516 LevelDBTransaction* leveldb_transaction, |
| 517 const BlobJournalType& journal) { |
| 518 const std::string leveldb_key = BlobJournalKey::Encode(); |
| 519 std::string data; |
| 520 EncodeBlobJournal(journal, &data); |
| 521 leveldb_transaction->Put(leveldb_key, &data); |
| 522 } |
| 523 |
| 524 static void UpdateLiveBlobJournalWithBlobList( |
| 525 LevelDBTransaction* leveldb_transaction, |
| 526 const BlobJournalType& journal) { |
| 527 const std::string leveldb_key = LiveBlobJournalKey::Encode(); |
| 528 std::string data; |
| 529 EncodeBlobJournal(journal, &data); |
| 530 leveldb_transaction->Put(leveldb_key, &data); |
| 531 } |
| 532 |
| 533 static leveldb::Status MergeBlobsIntoLiveBlobJournal( |
| 534 LevelDBTransaction* leveldb_transaction, |
| 535 const BlobJournalType& journal) { |
| 536 BlobJournalType old_journal; |
| 537 const std::string key = LiveBlobJournalKey::Encode(); |
| 538 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal); |
| 539 if (!s.ok()) |
| 540 return s; |
| 541 |
| 542 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); |
| 543 |
| 544 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); |
| 545 return leveldb::Status::OK(); |
| 546 } |
| 547 |
| 548 static void UpdateBlobJournalWithDatabase( |
| 549 LevelDBDirectTransaction* leveldb_transaction, |
| 550 int64 database_id) { |
| 551 BlobJournalType journal; |
| 552 journal.push_back( |
| 553 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); |
| 554 const std::string key = BlobJournalKey::Encode(); |
| 555 std::string data; |
| 556 EncodeBlobJournal(journal, &data); |
| 557 leveldb_transaction->Put(key, &data); |
| 558 } |
| 559 |
| 560 static leveldb::Status MergeDatabaseIntoLiveBlobJournal( |
| 561 LevelDBDirectTransaction* leveldb_transaction, |
| 562 int64 database_id) { |
| 563 BlobJournalType journal; |
| 564 const std::string key = LiveBlobJournalKey::Encode(); |
| 565 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal); |
| 566 if (!s.ok()) |
| 567 return s; |
| 568 journal.push_back( |
| 569 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); |
| 570 std::string data; |
| 571 EncodeBlobJournal(journal, &data); |
| 572 leveldb_transaction->Put(key, &data); |
| 573 return leveldb::Status::OK(); |
| 574 } |
| 575 |
477 IndexedDBBackingStore::IndexedDBBackingStore( | 576 IndexedDBBackingStore::IndexedDBBackingStore( |
478 IndexedDBFactory* indexed_db_factory, | 577 IndexedDBFactory* indexed_db_factory, |
479 const GURL& origin_url, | 578 const GURL& origin_url, |
480 const base::FilePath& blob_path, | 579 const base::FilePath& blob_path, |
481 net::URLRequestContext* request_context, | 580 net::URLRequestContext* request_context, |
482 scoped_ptr<LevelDBDatabase> db, | 581 scoped_ptr<LevelDBDatabase> db, |
483 scoped_ptr<LevelDBComparator> comparator, | 582 scoped_ptr<LevelDBComparator> comparator, |
484 base::TaskRunner* task_runner) | 583 base::TaskRunner* task_runner) |
485 : indexed_db_factory_(indexed_db_factory), | 584 : indexed_db_factory_(indexed_db_factory), |
486 origin_url_(origin_url), | 585 origin_url_(origin_url), |
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1091 s = it->Next()) | 1190 s = it->Next()) |
1092 transaction->Remove(it->Key()); | 1191 transaction->Remove(it->Key()); |
1093 if (!s.ok()) { | 1192 if (!s.ok()) { |
1094 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); | 1193 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); |
1095 return s; | 1194 return s; |
1096 } | 1195 } |
1097 | 1196 |
1098 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); | 1197 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); |
1099 transaction->Remove(key); | 1198 transaction->Remove(key); |
1100 | 1199 |
| 1200 // TODO(ericu): Put the real calls to the blob journal code here. For now, |
| 1201 // I've inserted fake calls so that we don't get "you didn't use this static |
| 1202 // function" compiler errors. |
| 1203 if (false) { |
| 1204 scoped_refptr<LevelDBTransaction> fake_transaction = |
| 1205 new LevelDBTransaction(NULL); |
| 1206 BlobJournalType fake_journal; |
| 1207 MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id); |
| 1208 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); |
| 1209 MergeBlobsIntoLiveBlobJournal(fake_transaction.get(), fake_journal); |
| 1210 } |
| 1211 |
1101 s = transaction->Commit(); | 1212 s = transaction->Commit(); |
1102 if (!s.ok()) { | 1213 if (!s.ok()) { |
1103 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); | 1214 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); |
1104 return s; | 1215 return s; |
1105 } | 1216 } |
1106 db_->Compact(start_key, stop_key); | 1217 db_->Compact(start_key, stop_key); |
1107 return s; | 1218 return s; |
1108 } | 1219 } |
1109 | 1220 |
1110 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1221 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1927 FROM_HERE, | 2038 FROM_HERE, |
1928 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, | 2039 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, |
1929 write_closure.get(), | 2040 write_closure.get(), |
1930 path, | 2041 path, |
1931 descriptor.url(), | 2042 descriptor.url(), |
1932 request_context_)); | 2043 request_context_)); |
1933 } | 2044 } |
1934 return true; | 2045 return true; |
1935 } | 2046 } |
1936 | 2047 |
| 2048 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, |
| 2049 int64 blob_key) { |
| 2050 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
| 2051 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; |
| 2052 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); |
| 2053 scoped_refptr<LevelDBTransaction> transaction = |
| 2054 new LevelDBTransaction(db_.get()); |
| 2055 |
| 2056 std::string live_blob_key = LiveBlobJournalKey::Encode(); |
| 2057 BlobJournalType live_blob_journal; |
| 2058 if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal) |
| 2059 .ok()) |
| 2060 return; |
| 2061 DCHECK(live_blob_journal.size()); |
| 2062 |
| 2063 std::string primary_key = BlobJournalKey::Encode(); |
| 2064 BlobJournalType primary_journal; |
| 2065 if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok()) |
| 2066 return; |
| 2067 |
| 2068 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to |
| 2069 // remove all entries with database_id from the live_blob journal and add only |
| 2070 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) |
| 2071 // and we hit kAllBlobsKey for the right database_id in the journal, we leave |
| 2072 // the kAllBlobsKey entry in the live_blob journal but add the specific blob |
| 2073 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a |
| 2074 // matching (database_id, blob_key) tuple, we should move it to the primary |
| 2075 // journal. |
| 2076 BlobJournalType new_live_blob_journal; |
| 2077 for (BlobJournalType::iterator journal_iter = live_blob_journal.begin(); |
| 2078 journal_iter != live_blob_journal.end(); |
| 2079 ++journal_iter) { |
| 2080 int64 current_database_id = journal_iter->first; |
| 2081 int64 current_blob_key = journal_iter->second; |
| 2082 bool current_all_blobs = |
| 2083 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; |
| 2084 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || |
| 2085 current_all_blobs); |
| 2086 if (current_database_id == database_id && |
| 2087 (all_blobs || current_all_blobs || blob_key == current_blob_key)) { |
| 2088 if (!all_blobs) { |
| 2089 primary_journal.push_back( |
| 2090 std::make_pair(database_id, current_blob_key)); |
| 2091 if (current_all_blobs) |
| 2092 new_live_blob_journal.push_back(*journal_iter); |
| 2093 new_live_blob_journal.insert(new_live_blob_journal.end(), |
| 2094 ++journal_iter, |
| 2095 live_blob_journal.end()); // All the rest. |
| 2096 break; |
| 2097 } |
| 2098 } else { |
| 2099 new_live_blob_journal.push_back(*journal_iter); |
| 2100 } |
| 2101 } |
| 2102 if (all_blobs) { |
| 2103 primary_journal.push_back( |
| 2104 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); |
| 2105 } |
| 2106 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); |
| 2107 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); |
| 2108 transaction->Commit(); |
| 2109 // We could just do the deletions/cleaning here, but if there are a lot of |
| 2110 // blobs about to be garbage collected, it'd be better to wait and do them all |
| 2111 // at once. |
| 2112 StartJournalCleaningTimer(); |
| 2113 } |
| 2114 |
| 2115 // The this reference is a raw pointer that's declared Unretained inside the |
| 2116 // timer code, so this won't confuse IndexedDBFactory's check for |
| 2117 // HasLastBackingStoreReference. It's safe because if the backing store is |
| 2118 // deleted, the timer will automatically be canceled on destruction. |
| 2119 void IndexedDBBackingStore::StartJournalCleaningTimer() { |
| 2120 journal_cleaning_timer_.Start( |
| 2121 FROM_HERE, |
| 2122 base::TimeDelta::FromSeconds(5), |
| 2123 this, |
| 2124 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); |
| 2125 } |
| 2126 |
1937 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | 2127 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. |
1938 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { | 2128 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { |
1939 return GetBlobFileNameForKey(blob_path_, database_id, key); | 2129 return GetBlobFileNameForKey(blob_path_, database_id, key); |
1940 } | 2130 } |
1941 | 2131 |
1942 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2132 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
1943 const std::string& stop_key, | 2133 const std::string& stop_key, |
1944 int64 index_id, | 2134 int64 index_id, |
1945 unsigned char meta_data_type) { | 2135 unsigned char meta_data_type) { |
1946 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2136 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2058 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | 2248 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { |
2059 FilePath fileName = GetBlobFileName(database_id, key); | 2249 FilePath fileName = GetBlobFileName(database_id, key); |
2060 return base::DeleteFile(fileName, false); | 2250 return base::DeleteFile(fileName, false); |
2061 } | 2251 } |
2062 | 2252 |
2063 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | 2253 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { |
2064 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); | 2254 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); |
2065 return base::DeleteFile(dirName, true); | 2255 return base::DeleteFile(dirName, true); |
2066 } | 2256 } |
2067 | 2257 |
| 2258 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal( |
| 2259 const std::string& level_db_key) { |
| 2260 scoped_refptr<LevelDBTransaction> journal_transaction = |
| 2261 new LevelDBTransaction(db_.get()); |
| 2262 BlobJournalType journal; |
| 2263 leveldb::Status s = |
| 2264 GetBlobJournal(level_db_key, journal_transaction.get(), &journal); |
| 2265 if (!s.ok()) |
| 2266 return s; |
| 2267 if (!journal.size()) |
| 2268 return leveldb::Status::OK(); |
| 2269 BlobJournalType::iterator journal_iter; |
| 2270 for (journal_iter = journal.begin(); journal_iter != journal.end(); |
| 2271 ++journal_iter) { |
| 2272 int64 database_id = journal_iter->first; |
| 2273 int64 blob_key = journal_iter->second; |
| 2274 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
| 2275 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { |
| 2276 if (!RemoveBlobDirectory(database_id)) |
| 2277 return IOErrorStatus(); |
| 2278 } else { |
| 2279 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); |
| 2280 if (!RemoveBlobFile(database_id, blob_key)) |
| 2281 return IOErrorStatus(); |
| 2282 } |
| 2283 } |
| 2284 ClearBlobJournal(journal_transaction.get(), level_db_key); |
| 2285 return journal_transaction->Commit(); |
| 2286 } |
| 2287 |
| 2288 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { |
| 2289 CleanUpBlobJournal(BlobJournalKey::Encode()); |
| 2290 } |
| 2291 |
2068 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2292 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
2069 LevelDBTransaction* transaction, | 2293 LevelDBTransaction* transaction, |
2070 int64 database_id, | 2294 int64 database_id, |
2071 int64 object_store_id, | 2295 int64 object_store_id, |
2072 int64 index_id) { | 2296 int64 index_id) { |
2073 int64 max_index_id = -1; | 2297 int64 max_index_id = -1; |
2074 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2298 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
2075 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2299 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
2076 bool found = false; | 2300 bool found = false; |
2077 leveldb::Status s = | 2301 leveldb::Status s = |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2375 return InvalidDBKeyStatus(); | 2599 return InvalidDBKeyStatus(); |
2376 } | 2600 } |
2377 | 2601 |
2378 StringPiece slice(found_encoded_primary_key); | 2602 StringPiece slice(found_encoded_primary_key); |
2379 if (DecodeIDBKey(&slice, found_primary_key) && slice.empty()) | 2603 if (DecodeIDBKey(&slice, found_primary_key) && slice.empty()) |
2380 return s; | 2604 return s; |
2381 else | 2605 else |
2382 return InvalidDBKeyStatus(); | 2606 return InvalidDBKeyStatus(); |
2383 } | 2607 } |
2384 | 2608 |
2385 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, | |
2386 int64 blob_key) { | |
2387 // TODO(ericu) | |
2388 } | |
2389 | |
2390 IndexedDBBackingStore::Cursor::Cursor( | 2609 IndexedDBBackingStore::Cursor::Cursor( |
2391 const IndexedDBBackingStore::Cursor* other) | 2610 const IndexedDBBackingStore::Cursor* other) |
2392 : transaction_(other->transaction_), | 2611 : transaction_(other->transaction_), |
2393 cursor_options_(other->cursor_options_), | 2612 cursor_options_(other->cursor_options_), |
2394 current_key_(new IndexedDBKey(*other->current_key_)) { | 2613 current_key_(new IndexedDBKey(*other->current_key_)) { |
2395 if (other->iterator_) { | 2614 if (other->iterator_) { |
2396 iterator_ = transaction_->CreateIterator(); | 2615 iterator_ = transaction_->CreateIterator(); |
2397 | 2616 |
2398 if (other->iterator_->IsValid()) { | 2617 if (other->iterator_->IsValid()) { |
2399 leveldb::Status s = iterator_->Seek(other->iterator_->Key()); | 2618 leveldb::Status s = iterator_->Seek(other->iterator_->Key()); |
(...skipping 914 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3314 const GURL& url, | 3533 const GURL& url, |
3315 int64_t key) | 3534 int64_t key) |
3316 : is_file_(false), url_(url), key_(key) {} | 3535 : is_file_(false), url_(url), key_(key) {} |
3317 | 3536 |
3318 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | 3537 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
3319 const FilePath& file_path, | 3538 const FilePath& file_path, |
3320 int64_t key) | 3539 int64_t key) |
3321 : is_file_(true), file_path_(file_path), key_(key) {} | 3540 : is_file_(true), file_path_(file_path), key_(key) {} |
3322 | 3541 |
3323 } // namespace content | 3542 } // namespace content |
OLD | NEW |