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 DECODE_BLOB_JOURNAL, | |
129 INTERNAL_ERROR_MAX, | 130 INTERNAL_ERROR_MAX, |
130 }; | 131 }; |
131 | 132 |
132 static void RecordInternalError(const char* type, | 133 static void RecordInternalError(const char* type, |
133 IndexedDBBackingStoreErrorSource location) { | 134 IndexedDBBackingStoreErrorSource location) { |
134 std::string name; | 135 std::string name; |
135 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 136 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); |
136 base::Histogram::FactoryGet(name, | 137 base::Histogram::FactoryGet(name, |
137 1, | 138 1, |
138 INTERNAL_ERROR_MAX, | 139 INTERNAL_ERROR_MAX, |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 scoped_ptr<LevelDBDatabase>* db, | 468 scoped_ptr<LevelDBDatabase>* db, |
468 bool* is_disk_full) OVERRIDE { | 469 bool* is_disk_full) OVERRIDE { |
469 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 470 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
470 } | 471 } |
471 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) | 472 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) |
472 OVERRIDE { | 473 OVERRIDE { |
473 return LevelDBDatabase::Destroy(file_name); | 474 return LevelDBDatabase::Destroy(file_name); |
474 } | 475 } |
475 }; | 476 }; |
476 | 477 |
478 // TODO(ericu): Error recovery. If we persistently can't read the | |
479 // blob journal, the safe thing to do is to clear it and leak the blobs, | |
480 // though that may be costly. Still, database/directory deletion should always | |
481 // clean things up, and we can write an fsck that will do a full correction if | |
482 // need be. | |
483 template <typename T> | |
484 static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key, | |
485 T* leveldb_transaction, | |
486 BlobJournalType* journal) { | |
487 std::string data; | |
488 bool found = false; | |
489 leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found); | |
490 if (!s.ok()) { | |
491 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); | |
cmumford
2014/04/30 21:29:30
INTERNAL_READ_ERROR_UNTESTED assuming you don't ha
ericu
2014/04/30 22:16:10
I made the quick fix; no test yet.
cmumford
2014/04/30 22:40:09
Unfortunately all corruptions are not detectable a
| |
492 return s; | |
493 } | |
494 journal->clear(); | |
495 if (!found) | |
cmumford
2014/04/30 21:29:30
why not just (if !found || !data.size())?
ericu
2014/04/30 22:16:10
Done.
| |
496 return leveldb::Status::OK(); | |
497 if (!data.size()) | |
498 return leveldb::Status::OK(); | |
499 StringPiece slice(data); | |
500 if (!DecodeBlobJournal(&slice, journal)) { | |
501 INTERNAL_READ_ERROR(DECODE_BLOB_JOURNAL); | |
502 s = InternalInconsistencyStatus(); | |
503 } | |
504 return s; | |
505 } | |
506 | |
507 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, | |
508 const std::string& level_db_key) { | |
509 leveldb_transaction->Remove(level_db_key); | |
cmumford
2014/04/30 21:29:30
A one line function doesn't seem worth the added c
ericu
2014/04/30 22:16:10
No, there's just the one line, called in two place
jsbell
2014/04/30 22:21:45
I like abstracting it.
| |
510 } | |
511 | |
512 static void UpdatePrimaryJournalWithBlobList( | |
513 LevelDBTransaction* leveldb_transaction, | |
514 const BlobJournalType& journal) { | |
515 const std::string leveldb_key = BlobJournalKey::Encode(); | |
516 std::string data; | |
517 EncodeBlobJournal(journal, &data); | |
518 leveldb_transaction->Put(leveldb_key, &data); | |
519 } | |
520 | |
521 static void UpdateLiveBlobJournalWithBlobList( | |
522 LevelDBTransaction* leveldb_transaction, | |
523 const BlobJournalType& journal) { | |
524 const std::string leveldb_key = LiveBlobJournalKey::Encode(); | |
525 std::string data; | |
526 EncodeBlobJournal(journal, &data); | |
527 leveldb_transaction->Put(leveldb_key, &data); | |
528 } | |
529 | |
530 static leveldb::Status MergeBlobsIntoLiveBlobJournal( | |
531 LevelDBTransaction* leveldb_transaction, | |
532 const BlobJournalType& journal) { | |
533 BlobJournalType old_journal; | |
534 std::string key = LiveBlobJournalKey::Encode(); | |
535 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal); | |
536 if (!s.ok()) | |
537 return s; | |
538 | |
539 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); | |
540 | |
541 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); | |
542 return leveldb::Status::OK(); | |
543 } | |
544 | |
545 static void UpdateBlobJournalWithDatabase( | |
546 LevelDBDirectTransaction* leveldb_transaction, | |
547 int64 database_id) { | |
548 BlobJournalType journal; | |
549 journal.push_back( | |
550 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
551 const std::string key = BlobJournalKey::Encode(); | |
552 std::string data; | |
553 EncodeBlobJournal(journal, &data); | |
554 leveldb_transaction->Put(key, &data); | |
555 } | |
556 | |
557 static leveldb::Status MergeDatabaseIntoLiveBlobJournal( | |
558 LevelDBDirectTransaction* leveldb_transaction, | |
559 int64 database_id) { | |
560 BlobJournalType journal; | |
561 std::string key = LiveBlobJournalKey::Encode(); | |
cmumford
2014/04/30 21:29:30
nit: I see that sometimes you use a const string f
ericu
2014/04/30 22:16:10
Nope; just an oversight. Fixed.
| |
562 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal); | |
563 if (!s.ok()) | |
564 return s; | |
565 journal.push_back( | |
566 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
567 std::string data; | |
568 EncodeBlobJournal(journal, &data); | |
569 leveldb_transaction->Put(key, &data); | |
570 return leveldb::Status::OK(); | |
571 } | |
572 | |
477 IndexedDBBackingStore::IndexedDBBackingStore( | 573 IndexedDBBackingStore::IndexedDBBackingStore( |
478 IndexedDBFactory* indexed_db_factory, | 574 IndexedDBFactory* indexed_db_factory, |
479 const GURL& origin_url, | 575 const GURL& origin_url, |
480 const base::FilePath& blob_path, | 576 const base::FilePath& blob_path, |
481 net::URLRequestContext* request_context, | 577 net::URLRequestContext* request_context, |
482 scoped_ptr<LevelDBDatabase> db, | 578 scoped_ptr<LevelDBDatabase> db, |
483 scoped_ptr<LevelDBComparator> comparator, | 579 scoped_ptr<LevelDBComparator> comparator, |
484 base::TaskRunner* task_runner) | 580 base::TaskRunner* task_runner) |
485 : indexed_db_factory_(indexed_db_factory), | 581 : indexed_db_factory_(indexed_db_factory), |
486 origin_url_(origin_url), | 582 origin_url_(origin_url), |
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1091 s = it->Next()) | 1187 s = it->Next()) |
1092 transaction->Remove(it->Key()); | 1188 transaction->Remove(it->Key()); |
1093 if (!s.ok()) { | 1189 if (!s.ok()) { |
1094 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); | 1190 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); |
1095 return s; | 1191 return s; |
1096 } | 1192 } |
1097 | 1193 |
1098 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); | 1194 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); |
1099 transaction->Remove(key); | 1195 transaction->Remove(key); |
1100 | 1196 |
1197 // TODO(ericu): Put the real calls to the blob journal code here. For now, | |
1198 // I've inserted fake calls so that we don't get "you didn't use this static | |
1199 // function" compiler errors. | |
1200 if (false) { | |
1201 scoped_refptr<LevelDBTransaction> fake_transaction = | |
1202 new LevelDBTransaction(NULL); | |
1203 BlobJournalType fake_journal; | |
1204 MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id); | |
1205 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); | |
1206 MergeBlobsIntoLiveBlobJournal(fake_transaction.get(), fake_journal); | |
1207 } | |
1208 | |
1101 s = transaction->Commit(); | 1209 s = transaction->Commit(); |
1102 if (!s.ok()) { | 1210 if (!s.ok()) { |
1103 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); | 1211 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); |
1104 return s; | 1212 return s; |
1105 } | 1213 } |
1106 db_->Compact(start_key, stop_key); | 1214 db_->Compact(start_key, stop_key); |
1107 return s; | 1215 return s; |
1108 } | 1216 } |
1109 | 1217 |
1110 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1218 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1927 FROM_HERE, | 2035 FROM_HERE, |
1928 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, | 2036 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, |
1929 write_closure.get(), | 2037 write_closure.get(), |
1930 path, | 2038 path, |
1931 descriptor.url(), | 2039 descriptor.url(), |
1932 request_context_)); | 2040 request_context_)); |
1933 } | 2041 } |
1934 return true; | 2042 return true; |
1935 } | 2043 } |
1936 | 2044 |
2045 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, | |
2046 int64 blob_key) { | |
2047 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
2048 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
2049 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
2050 scoped_refptr<LevelDBTransaction> transaction = | |
2051 new LevelDBTransaction(db_.get()); | |
2052 | |
2053 std::string live_blob_key = LiveBlobJournalKey::Encode(); | |
2054 BlobJournalType live_blob_journal; | |
2055 if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal) | |
2056 .ok()) | |
2057 return; | |
2058 DCHECK(live_blob_journal.size()); | |
2059 | |
2060 std::string primary_key = BlobJournalKey::Encode(); | |
2061 BlobJournalType primary_journal; | |
2062 if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok()) | |
2063 return; | |
2064 | |
2065 BlobJournalType::iterator journal_iter; | |
jsbell
2014/04/30 21:18:05
nit: move into the for()'s init clause, since the
ericu
2014/04/30 21:21:14
Yeah, good point.
| |
2066 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to | |
2067 // remove all entries with database_id from the live_blob journal and add only | |
2068 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) | |
2069 // and we hit kAllBlobsKey for the right database_id in the journal, we leave | |
2070 // the kAllBlobsKey entry in the live_blob journal but add the specific blob | |
2071 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a | |
2072 // matching (database_id, blob_key) tuple, we should move it to the primary | |
2073 // journal. | |
2074 BlobJournalType new_live_blob_journal; | |
2075 for (journal_iter = live_blob_journal.begin(); | |
2076 journal_iter != live_blob_journal.end(); | |
2077 ++journal_iter) { | |
2078 int64 current_database_id = journal_iter->first; | |
2079 int64 current_blob_key = journal_iter->second; | |
2080 bool current_all_blobs = | |
2081 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
2082 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || | |
2083 current_all_blobs); | |
2084 if (current_database_id == database_id && | |
2085 (all_blobs || current_all_blobs || blob_key == current_blob_key)) { | |
2086 if (!all_blobs) { | |
2087 primary_journal.push_back( | |
2088 std::make_pair(database_id, current_blob_key)); | |
2089 if (current_all_blobs) | |
2090 new_live_blob_journal.push_back(*journal_iter); | |
2091 new_live_blob_journal.insert(new_live_blob_journal.end(), | |
2092 ++journal_iter, | |
2093 live_blob_journal.end()); // All the rest. | |
2094 break; | |
2095 } | |
2096 } else { | |
2097 new_live_blob_journal.push_back(*journal_iter); | |
2098 } | |
2099 } | |
2100 if (all_blobs) { | |
2101 primary_journal.push_back( | |
2102 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
2103 } | |
2104 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); | |
2105 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); | |
2106 transaction->Commit(); | |
2107 // We could just do the deletions/cleaning here, but if there are a lot of | |
2108 // blobs about to be garbage collected, it'd be better to wait and do them all | |
2109 // at once. | |
2110 StartJournalCleaningTimer(); | |
2111 } | |
2112 | |
2113 // The this reference is a raw pointer that's declared Unretained inside the | |
2114 // timer code, so this won't confuse IndexedDBFactory's check for | |
2115 // HasLastBackingStoreReference. It's safe because if the backing store is | |
2116 // deleted, the timer will automatically be canceled on destruction. | |
2117 void IndexedDBBackingStore::StartJournalCleaningTimer() { | |
2118 journal_cleaning_timer_.Start( | |
2119 FROM_HERE, | |
2120 base::TimeDelta::FromSeconds(5), | |
2121 this, | |
2122 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); | |
2123 } | |
2124 | |
1937 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. | 2125 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. |
1938 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { | 2126 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { |
1939 return GetBlobFileNameForKey(blob_path_, database_id, key); | 2127 return GetBlobFileNameForKey(blob_path_, database_id, key); |
1940 } | 2128 } |
1941 | 2129 |
1942 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2130 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
1943 const std::string& stop_key, | 2131 const std::string& stop_key, |
1944 int64 index_id, | 2132 int64 index_id, |
1945 unsigned char meta_data_type) { | 2133 unsigned char meta_data_type) { |
1946 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2134 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) { | 2246 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { |
2059 FilePath fileName = GetBlobFileName(database_id, key); | 2247 FilePath fileName = GetBlobFileName(database_id, key); |
2060 return base::DeleteFile(fileName, false); | 2248 return base::DeleteFile(fileName, false); |
2061 } | 2249 } |
2062 | 2250 |
2063 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | 2251 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { |
2064 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); | 2252 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); |
2065 return base::DeleteFile(dirName, true); | 2253 return base::DeleteFile(dirName, true); |
2066 } | 2254 } |
2067 | 2255 |
2256 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal( | |
2257 const std::string& level_db_key) { | |
2258 scoped_refptr<LevelDBTransaction> journal_transaction = | |
2259 new LevelDBTransaction(db_.get()); | |
2260 BlobJournalType journal; | |
2261 leveldb::Status s = | |
2262 GetBlobJournal(level_db_key, journal_transaction.get(), &journal); | |
2263 if (!s.ok()) | |
2264 return s; | |
2265 if (!journal.size()) | |
2266 return leveldb::Status::OK(); | |
cmumford
2014/04/30 21:29:30
No need to worry about journal_transaction->Commit
ericu
2014/04/30 22:16:10
I'm not sure what you mean. It's discarded on exi
cmumford
2014/04/30 22:32:33
I misread it - thought transaction was a param - m
| |
2267 BlobJournalType::iterator journal_iter; | |
2268 for (journal_iter = journal.begin(); journal_iter != journal.end(); | |
2269 ++journal_iter) { | |
2270 int64 database_id = journal_iter->first; | |
2271 int64 blob_key = journal_iter->second; | |
2272 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
2273 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { | |
2274 RemoveBlobDirectory(database_id); | |
2275 } else { | |
2276 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
2277 RemoveBlobFile(database_id, blob_key); | |
cmumford
2014/04/30 21:29:30
Since this returns false on error can we at least
ericu
2014/04/30 22:16:10
Actually, we should do more than that. Changed to
| |
2278 } | |
2279 } | |
2280 ClearBlobJournal(journal_transaction.get(), level_db_key); | |
2281 return journal_transaction->Commit(); | |
2282 } | |
2283 | |
2284 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { | |
2285 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
2286 } | |
2287 | |
2068 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( | 2288 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( |
2069 LevelDBTransaction* transaction, | 2289 LevelDBTransaction* transaction, |
2070 int64 database_id, | 2290 int64 database_id, |
2071 int64 object_store_id, | 2291 int64 object_store_id, |
2072 int64 index_id) { | 2292 int64 index_id) { |
2073 int64 max_index_id = -1; | 2293 int64 max_index_id = -1; |
2074 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2294 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
2075 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2295 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
2076 bool found = false; | 2296 bool found = false; |
2077 leveldb::Status s = | 2297 leveldb::Status s = |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2375 return InvalidDBKeyStatus(); | 2595 return InvalidDBKeyStatus(); |
2376 } | 2596 } |
2377 | 2597 |
2378 StringPiece slice(found_encoded_primary_key); | 2598 StringPiece slice(found_encoded_primary_key); |
2379 if (DecodeIDBKey(&slice, found_primary_key) && slice.empty()) | 2599 if (DecodeIDBKey(&slice, found_primary_key) && slice.empty()) |
2380 return s; | 2600 return s; |
2381 else | 2601 else |
2382 return InvalidDBKeyStatus(); | 2602 return InvalidDBKeyStatus(); |
2383 } | 2603 } |
2384 | 2604 |
2385 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, | |
2386 int64 blob_key) { | |
2387 // TODO(ericu) | |
2388 } | |
2389 | |
2390 IndexedDBBackingStore::Cursor::Cursor( | 2605 IndexedDBBackingStore::Cursor::Cursor( |
2391 const IndexedDBBackingStore::Cursor* other) | 2606 const IndexedDBBackingStore::Cursor* other) |
2392 : transaction_(other->transaction_), | 2607 : transaction_(other->transaction_), |
2393 cursor_options_(other->cursor_options_), | 2608 cursor_options_(other->cursor_options_), |
2394 current_key_(new IndexedDBKey(*other->current_key_)) { | 2609 current_key_(new IndexedDBKey(*other->current_key_)) { |
2395 if (other->iterator_) { | 2610 if (other->iterator_) { |
2396 iterator_ = transaction_->CreateIterator(); | 2611 iterator_ = transaction_->CreateIterator(); |
2397 | 2612 |
2398 if (other->iterator_->IsValid()) { | 2613 if (other->iterator_->IsValid()) { |
2399 leveldb::Status s = iterator_->Seek(other->iterator_->Key()); | 2614 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, | 3529 const GURL& url, |
3315 int64_t key) | 3530 int64_t key) |
3316 : is_file_(false), url_(url), key_(key) {} | 3531 : is_file_(false), url_(url), key_(key) {} |
3317 | 3532 |
3318 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | 3533 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( |
3319 const FilePath& file_path, | 3534 const FilePath& file_path, |
3320 int64_t key) | 3535 int64_t key) |
3321 : is_file_(true), file_path_(file_path), key_(key) {} | 3536 : is_file_(true), file_path_(file_path), key_(key) {} |
3322 | 3537 |
3323 } // namespace content | 3538 } // namespace content |
OLD | NEW |