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/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/strings/stringprintf.h" | |
12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
14 #include "content/browser/child_process_security_policy_impl.h" | |
15 #include "content/browser/indexed_db/indexed_db_blob_info.h" | |
13 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 16 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
14 #include "content/browser/indexed_db/indexed_db_metadata.h" | 17 #include "content/browser/indexed_db/indexed_db_metadata.h" |
15 #include "content/browser/indexed_db/indexed_db_tracing.h" | 18 #include "content/browser/indexed_db/indexed_db_tracing.h" |
19 #include "content/browser/indexed_db/indexed_db_value.h" | |
16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 20 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" |
17 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 21 #include "content/browser/indexed_db/leveldb/leveldb_database.h" |
18 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 22 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" |
19 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 23 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
20 #include "content/common/indexed_db/indexed_db_key.h" | 24 #include "content/common/indexed_db/indexed_db_key.h" |
21 #include "content/common/indexed_db/indexed_db_key_path.h" | 25 #include "content/common/indexed_db/indexed_db_key_path.h" |
22 #include "content/common/indexed_db/indexed_db_key_range.h" | 26 #include "content/common/indexed_db/indexed_db_key_range.h" |
27 #include "content/public/browser/browser_thread.h" | |
28 #include "net/url_request/url_request_context.h" | |
23 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 29 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
24 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" | 30 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" |
25 #include "third_party/leveldatabase/env_chromium.h" | 31 #include "third_party/leveldatabase/env_chromium.h" |
32 #include "webkit/browser/blob/blob_data_handle.h" | |
33 #include "webkit/browser/fileapi/file_stream_writer.h" | |
34 #include "webkit/browser/fileapi/file_writer_delegate.h" | |
35 #include "webkit/browser/fileapi/local_file_stream_writer.h" | |
26 #include "webkit/common/database/database_identifier.h" | 36 #include "webkit/common/database/database_identifier.h" |
27 | 37 |
38 using base::FilePath; | |
28 using base::StringPiece; | 39 using base::StringPiece; |
40 using fileapi::FileWriterDelegate; | |
29 | 41 |
30 namespace content { | 42 namespace content { |
31 | 43 |
32 namespace { | 44 namespace { |
33 | 45 |
46 FilePath GetIDBBlobDirectoryName(const FilePath& pathBase, | |
jsbell
2013/12/18 23:04:40
Suggestion: Drop the 'IDB' in function names here
ericu
2013/12/19 05:19:11
Done.
| |
47 int64 database_id) { | |
jsbell
2013/12/18 23:04:40
Indentation... although I'm going to assume you'll
ericu
2013/12/19 05:19:11
Just tried git cl format for the first time. Awes
| |
48 return pathBase.AppendASCII(base::StringPrintf("%lx", database_id)); | |
49 } | |
50 | |
51 FilePath GetIDBBlobDirectoryNameForKey(const FilePath& pathBase, | |
52 int64 database_id, int64 key) { | |
53 FilePath path = GetIDBBlobDirectoryName(pathBase, database_id); | |
54 path = path.AppendASCII( | |
55 base::StringPrintf("%x", static_cast<int>(key & 0x0000ff00) >> 8)); | |
jsbell
2013/12/18 23:04:40
Would there be any disadvantage to using %02x so t
ericu
2013/12/19 05:19:11
Well, the first few will be bigger than they need
ericu
2014/02/25 21:19:44
Note that I haven't done this for the filenames or
| |
56 return path; | |
57 } | |
58 | |
59 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
60 bool MakeIDBBlobDirectory( | |
61 const FilePath& pathBase, int64 database_id, int64 key) { | |
62 FilePath path = | |
63 GetIDBBlobDirectoryNameForKey(pathBase, database_id, key); | |
64 return file_util::CreateDirectory(path); | |
65 } | |
66 | |
34 static std::string ComputeOriginIdentifier(const GURL& origin_url) { | 67 static std::string ComputeOriginIdentifier(const GURL& origin_url) { |
35 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; | 68 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; |
36 } | 69 } |
37 | 70 |
38 static base::FilePath ComputeFileName(const GURL& origin_url) { | 71 static base::FilePath ComputeFileName(const GURL& origin_url) { |
39 return base::FilePath() | 72 return base::FilePath() |
40 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | 73 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) |
41 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 74 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); |
42 } | 75 } |
43 | 76 |
77 static base::FilePath ComputeBlobPath(const GURL& origin_url) { | |
78 return base::FilePath() | |
79 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) | |
80 .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob")); | |
81 } | |
82 | |
44 } // namespace | 83 } // namespace |
45 | 84 |
46 static const int64 kKeyGeneratorInitialNumber = | 85 static const int64 kKeyGeneratorInitialNumber = |
47 1; // From the IndexedDB specification. | 86 1; // From the IndexedDB specification. |
48 | 87 |
49 enum IndexedDBBackingStoreErrorSource { | 88 enum IndexedDBBackingStoreErrorSource { |
50 // 0 - 2 are no longer used. | 89 // 0 - 2 are no longer used. |
51 FIND_KEY_IN_INDEX = 3, | 90 FIND_KEY_IN_INDEX = 3, |
52 GET_IDBDATABASE_METADATA, | 91 GET_IDBDATABASE_METADATA, |
53 GET_INDEXES, | 92 GET_INDEXES, |
54 GET_KEY_GENERATOR_CURRENT_NUMBER, | 93 GET_KEY_GENERATOR_CURRENT_NUMBER, |
55 GET_OBJECT_STORES, | 94 GET_OBJECT_STORES, |
56 GET_RECORD, | 95 GET_RECORD, |
57 KEY_EXISTS_IN_OBJECT_STORE, | 96 KEY_EXISTS_IN_OBJECT_STORE, |
58 LOAD_CURRENT_ROW, | 97 LOAD_CURRENT_ROW, |
59 SET_UP_METADATA, | 98 SET_UP_METADATA, |
60 GET_PRIMARY_KEY_VIA_INDEX, | 99 GET_PRIMARY_KEY_VIA_INDEX, |
61 KEY_EXISTS_IN_INDEX, | 100 KEY_EXISTS_IN_INDEX, |
62 VERSION_EXISTS, | 101 VERSION_EXISTS, |
63 DELETE_OBJECT_STORE, | 102 DELETE_OBJECT_STORE, |
64 SET_MAX_OBJECT_STORE_ID, | 103 SET_MAX_OBJECT_STORE_ID, |
65 SET_MAX_INDEX_ID, | 104 SET_MAX_INDEX_ID, |
66 GET_NEW_DATABASE_ID, | 105 GET_NEW_DATABASE_ID, |
67 GET_NEW_VERSION_NUMBER, | 106 GET_NEW_VERSION_NUMBER, |
68 CREATE_IDBDATABASE_METADATA, | 107 CREATE_IDBDATABASE_METADATA, |
69 DELETE_DATABASE, | 108 DELETE_DATABASE, |
70 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro | 109 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro |
110 GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER, | |
jsbell
2013/12/18 23:04:40
Need to append (after GET_DATABASE_NAMES) to retai
ericu
2013/12/19 05:19:11
Done.
| |
111 GET_BLOB_INFO_FOR_RECORD, | |
112 DECODE_BLOB_JOURNAL, | |
71 GET_DATABASE_NAMES, | 113 GET_DATABASE_NAMES, |
72 INTERNAL_ERROR_MAX, | 114 INTERNAL_ERROR_MAX, |
73 }; | 115 }; |
74 | 116 |
75 static void RecordInternalError(const char* type, | 117 static void RecordInternalError(const char* type, |
76 IndexedDBBackingStoreErrorSource location) { | 118 IndexedDBBackingStoreErrorSource location) { |
77 std::string name; | 119 std::string name; |
78 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 120 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); |
79 base::Histogram::FactoryGet(name, | 121 base::Histogram::FactoryGet(name, |
80 1, | 122 1, |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 | 277 |
236 if (db_data_version > latest_known_data_version) { | 278 if (db_data_version > latest_known_data_version) { |
237 *known = false; | 279 *known = false; |
238 return true; | 280 return true; |
239 } | 281 } |
240 | 282 |
241 *known = true; | 283 *known = true; |
242 return true; | 284 return true; |
243 } | 285 } |
244 | 286 |
245 WARN_UNUSED_RESULT static bool SetUpMetadata( | 287 WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() { |
jsbell
2013/12/18 23:04:40
Land separately?
ericu
2013/12/19 05:19:11
Sure; that's just there to help the unit test, so
| |
246 LevelDBDatabase* db, | |
247 const std::string& origin_identifier) { | |
248 const uint32 latest_known_data_version = | 288 const uint32 latest_known_data_version = |
249 blink::kSerializedScriptValueVersion; | 289 blink::kSerializedScriptValueVersion; |
250 const std::string schema_version_key = SchemaVersionKey::Encode(); | 290 const std::string schema_version_key = SchemaVersionKey::Encode(); |
251 const std::string data_version_key = DataVersionKey::Encode(); | 291 const std::string data_version_key = DataVersionKey::Encode(); |
252 | 292 |
253 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db); | 293 scoped_refptr<LevelDBTransaction> transaction = |
294 new LevelDBTransaction(db_.get()); | |
254 | 295 |
255 int64 db_schema_version = 0; | 296 int64 db_schema_version = 0; |
256 int64 db_data_version = 0; | 297 int64 db_data_version = 0; |
257 bool found = false; | 298 bool found = false; |
258 bool ok = | 299 bool ok = |
259 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); | 300 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); |
260 if (!ok) { | 301 if (!ok) { |
261 INTERNAL_READ_ERROR(SET_UP_METADATA); | 302 INTERNAL_READ_ERROR(SET_UP_METADATA); |
262 return false; | 303 return false; |
263 } | 304 } |
264 if (!found) { | 305 if (!found) { |
265 // Initialize new backing store. | 306 // Initialize new backing store. |
266 db_schema_version = kLatestKnownSchemaVersion; | 307 db_schema_version = kLatestKnownSchemaVersion; |
267 PutInt(transaction.get(), schema_version_key, db_schema_version); | 308 PutInt(transaction.get(), schema_version_key, db_schema_version); |
268 db_data_version = latest_known_data_version; | 309 db_data_version = latest_known_data_version; |
269 PutInt(transaction.get(), data_version_key, db_data_version); | 310 PutInt(transaction.get(), data_version_key, db_data_version); |
270 } else { | 311 } else { |
271 // Upgrade old backing store. | 312 // Upgrade old backing store. |
272 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); | 313 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); |
273 if (db_schema_version < 1) { | 314 if (db_schema_version < 1) { |
274 db_schema_version = 1; | 315 db_schema_version = 1; |
275 PutInt(transaction.get(), schema_version_key, db_schema_version); | 316 PutInt(transaction.get(), schema_version_key, db_schema_version); |
276 const std::string start_key = | 317 const std::string start_key = |
277 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier); | 318 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); |
278 const std::string stop_key = | 319 const std::string stop_key = |
279 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier); | 320 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); |
280 scoped_ptr<LevelDBIterator> it = db->CreateIterator(); | 321 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
281 for (it->Seek(start_key); | 322 for (it->Seek(start_key); |
282 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 323 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; |
283 it->Next()) { | 324 it->Next()) { |
284 int64 database_id = 0; | 325 int64 database_id = 0; |
285 found = false; | 326 found = false; |
286 bool ok = GetInt(transaction.get(), it->Key(), &database_id, &found); | 327 bool ok = GetInt(transaction.get(), it->Key(), &database_id, &found); |
287 if (!ok) { | 328 if (!ok) { |
288 INTERNAL_READ_ERROR(SET_UP_METADATA); | 329 INTERNAL_READ_ERROR(SET_UP_METADATA); |
289 return false; | 330 return false; |
290 } | 331 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
362 } | 403 } |
363 | 404 |
364 class DefaultLevelDBFactory : public LevelDBFactory { | 405 class DefaultLevelDBFactory : public LevelDBFactory { |
365 public: | 406 public: |
366 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, | 407 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, |
367 const LevelDBComparator* comparator, | 408 const LevelDBComparator* comparator, |
368 scoped_ptr<LevelDBDatabase>* db, | 409 scoped_ptr<LevelDBDatabase>* db, |
369 bool* is_disk_full) OVERRIDE { | 410 bool* is_disk_full) OVERRIDE { |
370 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 411 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
371 } | 412 } |
372 virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { | 413 virtual bool DestroyLevelDB(const FilePath& file_name) OVERRIDE { |
373 return LevelDBDatabase::Destroy(file_name); | 414 return LevelDBDatabase::Destroy(file_name); |
374 } | 415 } |
375 }; | 416 }; |
376 | 417 |
418 static bool GetBlobKeyGeneratorCurrentNumber( | |
419 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
420 int64& blob_key_generator_current_number) { | |
jsbell
2013/12/18 23:04:40
Non-const ref; use pointer instead.
ericu
2013/12/19 05:19:11
Done.
| |
421 const std::string key_gen_key = | |
422 DatabaseMetaDataKey::Encode( | |
423 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
424 | |
425 // Default to initial number if not found. | |
426 int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber; | |
427 std::string data; | |
428 | |
429 bool found = false; | |
430 bool ok = leveldb_transaction->Get(key_gen_key, &data, &found); | |
431 if (!ok) { | |
432 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
433 return false; | |
434 } | |
435 if (found) { | |
436 StringPiece slice(data); | |
437 if (!DecodeVarInt(&slice, &cur_number) || | |
jsbell
2013/12/18 23:04:40
Also test to see if the slice was completely consu
ericu
2013/12/19 05:19:11
Done. In GetDatabaseNames, CheckObjectStoreAndMet
jsbell
2013/12/20 00:59:28
Yes, yes, yes (although GetObjectStores is just te
ericu
2014/02/20 00:50:29
There's a weird mix of DCHECK, continue, and break
| |
438 !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) { | |
439 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
440 return false; | |
441 } | |
442 } | |
443 blob_key_generator_current_number = cur_number; | |
444 return true; | |
445 } | |
446 | |
447 static bool UpdateBlobKeyGeneratorCurrentNumber( | |
448 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
449 int64 blob_key_generator_current_number) { | |
450 #ifndef NDEBUG | |
451 int64 old_number; | |
452 if (!GetBlobKeyGeneratorCurrentNumber(leveldb_transaction, database_id, | |
453 old_number)) | |
454 return false; | |
455 DCHECK_LT(old_number, blob_key_generator_current_number); | |
456 #endif | |
457 DCHECK(DatabaseMetaDataKey::IsValidBlobKey( | |
458 blob_key_generator_current_number)); | |
459 const std::string key = | |
460 DatabaseMetaDataKey::Encode( | |
461 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
462 | |
463 PutInt(leveldb_transaction, key, blob_key_generator_current_number); | |
464 return true; | |
465 } | |
466 | |
467 static bool DecodeBlobJournal(const std::string& data, | |
468 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
jsbell
2013/12/18 23:04:40
non-const ref; should be a pointer
ericu
2013/12/19 05:19:11
Done.
| |
469 // TODO(ericu): Yell something on errors. If we persistently can't read the | |
470 // blob journal, the safe thing to do is to clear it and leak the blobs, | |
471 // though that may be costly. Still, database/directory deletion should always | |
472 // clean things up, and we can write an fsck that will do a full correction if | |
473 // need be. | |
474 IndexedDBBackingStore::Transaction::BlobJournalType output; | |
475 StringPiece slice(data); | |
476 while (!slice.empty()) { | |
477 int64 database_id = -1; | |
478 int64 blob_key = -1; | |
479 if (!DecodeVarInt(&slice, &database_id)) | |
480 return false; | |
481 else if (!KeyPrefix::IsValidDatabaseId(database_id)) | |
jsbell
2013/12/18 23:04:40
No need for 'else' here
ericu
2013/12/19 05:19:11
Done.
| |
482 return false; | |
483 if (!DecodeVarInt(&slice, &blob_key)) { | |
484 return false; | |
485 } else if (!DatabaseMetaDataKey::IsValidBlobKey(blob_key) && | |
486 (blob_key != DatabaseMetaDataKey::kAllBlobsKey)) { | |
487 return false; | |
488 } | |
489 output.push_back(std::make_pair(database_id, blob_key)); | |
490 } | |
491 journal.swap(output); | |
492 return true; | |
493 } | |
494 | |
495 static bool GetBlobJournalHelper( | |
496 bool ok, bool found, | |
497 const std::string& data, | |
498 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
jsbell
2013/12/18 23:04:40
non-const ref
ericu
2013/12/19 05:19:11
Done.
| |
499 if (!ok) { | |
500 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); | |
501 return false; | |
502 } | |
503 journal.clear(); | |
504 if (!found) | |
505 return true; | |
506 if (!data.size()) | |
507 return true; | |
508 if (!DecodeBlobJournal(data, journal)) { | |
509 INTERNAL_READ_ERROR(DECODE_BLOB_JOURNAL); | |
510 return false; | |
511 } | |
512 return true; | |
513 } | |
514 | |
515 static bool GetBlobJournal( | |
516 const StringPiece& leveldb_key, | |
517 LevelDBTransaction* leveldb_transaction, | |
518 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
jsbell
2013/12/18 23:04:40
non-const ref
ericu
2013/12/19 05:19:11
Done.
| |
519 std::string data; | |
520 bool found = false; | |
521 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); | |
522 return GetBlobJournalHelper(ok, found, data, journal); | |
523 } | |
524 | |
525 static bool GetBlobJournal( | |
jsbell
2013/12/18 23:04:40
Can GetBlobJournal be a template function? Looks l
ericu
2013/12/19 05:19:11
Done.
| |
526 const StringPiece& leveldb_key, | |
527 LevelDBUncachedTransaction* leveldb_transaction, | |
528 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
529 std::string data; | |
530 bool found = false; | |
531 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); | |
532 return GetBlobJournalHelper(ok, found, data, journal); | |
533 } | |
534 | |
535 static std::string EncodeBlobJournalWithBlobList( | |
jsbell
2013/12/18 23:04:40
Does "WithBlobList" add anything meaningful to the
ericu
2013/12/19 05:19:11
Not any more. Removed.
Below it's as opposed to
| |
536 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
537 std::string data; | |
538 if (journal.size()) { | |
jsbell
2013/12/18 23:04:40
Nit: Probably not worth the clutter to have this t
ericu
2013/12/19 05:19:11
Done.
| |
539 IndexedDBBackingStore::Transaction::BlobJournalType::const_iterator iter; | |
540 for (iter = journal.begin(); iter != journal.end(); ++iter) { | |
541 EncodeVarInt(iter->first, &data); | |
542 EncodeVarInt(iter->second, &data); | |
543 } | |
544 } | |
545 return data; | |
546 } | |
547 | |
548 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, | |
549 const std::string& level_db_key) { | |
550 leveldb_transaction->Remove(level_db_key); | |
551 } | |
552 | |
553 static void UpdatePrimaryJournalWithBlobList( | |
554 LevelDBTransaction* leveldb_transaction, | |
555 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
556 const std::string leveldbKey = BlobJournalKey::Encode(); | |
jsbell
2013/12/18 23:04:40
Nit: Don't use camelCase for locals/members.
ericu
2013/12/19 05:19:11
Done. This, like many of your other finds, is lef
jsbell
2013/12/20 00:59:28
I hear you. As you can see from my other patches,
| |
557 std::string data = EncodeBlobJournalWithBlobList(journal); | |
558 leveldb_transaction->Put(leveldbKey, &data); | |
559 } | |
560 | |
561 static void UpdateLiveBlobJournalWithBlobList( | |
562 LevelDBTransaction* leveldb_transaction, | |
563 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
564 const std::string leveldbKey = LiveBlobJournalKey::Encode(); | |
jsbell
2013/12/18 23:04:40
Ditto.
ericu
2013/12/19 05:19:11
Done.
| |
565 std::string data = EncodeBlobJournalWithBlobList(journal); | |
566 leveldb_transaction->Put(leveldbKey, &data); | |
567 } | |
568 | |
569 static bool MergeBlobsIntoLiveBlobJournal( | |
570 LevelDBTransaction* leveldb_transaction, | |
571 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
572 IndexedDBBackingStore::Transaction::BlobJournalType old_journal; | |
573 std::string key = LiveBlobJournalKey::Encode(); | |
574 if (!GetBlobJournal(key, leveldb_transaction, old_journal)) | |
575 return false; | |
576 | |
577 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); | |
578 | |
579 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); | |
580 return true; | |
581 } | |
582 | |
583 static void UpdateBlobJournalWithDatabase( | |
584 LevelDBUncachedTransaction* leveldb_transaction, int64 database_id) { | |
585 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
586 journal.push_back( | |
587 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
588 const std::string key = BlobJournalKey::Encode(); | |
589 std::string data = EncodeBlobJournalWithBlobList(journal); | |
590 leveldb_transaction->Put(key, &data); | |
591 } | |
592 | |
593 static bool MergeDatabaseIntoLiveBlobJournal( | |
594 LevelDBUncachedTransaction* leveldb_transaction, int64 database_id) { | |
595 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
596 std::string key = LiveBlobJournalKey::Encode(); | |
597 if (!GetBlobJournal(key, leveldb_transaction, journal)) | |
598 return false; | |
599 journal.push_back( | |
600 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
601 std::string data = EncodeBlobJournalWithBlobList(journal); | |
602 leveldb_transaction->Put(key, &data); | |
603 return true; | |
604 } | |
605 | |
606 // Blob Data is encoded as { is_file [bool], key [int64 as varInt], | |
jsbell
2013/12/18 23:04:40
Huh... I'm surprised that we need to distinguish f
ericu
2013/12/19 05:19:11
It's partly for spec correctness in a way I haven'
jsbell
2013/12/20 00:59:28
Thanks I hadn't considered that things other than
| |
607 // type [string-with-length, may be empty], then [for Blobs] size | |
608 // [int64 as varInt] or [for Files] fileName [string-with-length] } | |
609 static std::string EncodeBlobData( | |
610 const std::vector<IndexedDBBlobInfo*>& blob_info) { | |
611 std::string ret; | |
612 std::vector<IndexedDBBlobInfo*>::const_iterator iter; | |
613 for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) { | |
614 const IndexedDBBlobInfo& info = **iter; | |
615 EncodeBool(info.is_file(), &ret); | |
616 EncodeVarInt(info.key(), &ret); | |
617 EncodeStringWithLength(info.type(), &ret); | |
618 if (info.is_file()) | |
619 EncodeStringWithLength(info.file_name(), &ret); | |
620 else | |
621 EncodeVarInt(info.size(), &ret); | |
622 } | |
623 return ret; | |
624 } | |
625 | |
626 static bool DecodeBlobData( | |
627 const std::string& data, | |
628 std::vector<IndexedDBBlobInfo>* output) { | |
629 std::vector<IndexedDBBlobInfo> ret; | |
630 output->clear(); | |
631 StringPiece slice(data); | |
632 while (!slice.empty()) { | |
633 bool is_file; | |
634 int64 key; | |
635 string16 type; | |
636 int64 size; | |
637 string16 file_name; | |
638 | |
639 if (!DecodeBool(&slice, &is_file)) | |
640 return false; | |
641 if (!DecodeVarInt(&slice, &key) || | |
642 !DatabaseMetaDataKey::IsValidBlobKey(key)) | |
643 return false; | |
644 if (!DecodeStringWithLength(&slice, &type)) | |
645 return false; | |
646 if (is_file) { | |
647 if (!DecodeStringWithLength(&slice, &file_name)) | |
648 return false; | |
649 ret.push_back(IndexedDBBlobInfo(key, type, file_name)); | |
650 } else { | |
651 if (!DecodeVarInt(&slice, &size) || size < 0) | |
652 return false; | |
653 ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key)); | |
654 } | |
655 } | |
656 output->swap(ret); | |
657 | |
658 return true; | |
659 } | |
660 | |
377 IndexedDBBackingStore::IndexedDBBackingStore( | 661 IndexedDBBackingStore::IndexedDBBackingStore( |
662 IndexedDBFactory* indexed_db_factory, | |
378 const GURL& origin_url, | 663 const GURL& origin_url, |
664 const FilePath& blob_path, | |
665 net::URLRequestContext* request_context, | |
379 scoped_ptr<LevelDBDatabase> db, | 666 scoped_ptr<LevelDBDatabase> db, |
380 scoped_ptr<LevelDBComparator> comparator) | 667 scoped_ptr<LevelDBComparator> comparator, |
381 : origin_url_(origin_url), | 668 base::TaskRunner* task_runner) |
669 : indexed_db_factory_(indexed_db_factory), | |
670 origin_url_(origin_url), | |
382 origin_identifier_(ComputeOriginIdentifier(origin_url)), | 671 origin_identifier_(ComputeOriginIdentifier(origin_url)), |
672 blob_path_(blob_path), | |
673 request_context_(request_context), | |
674 task_runner_(task_runner), | |
383 db_(db.Pass()), | 675 db_(db.Pass()), |
384 comparator_(comparator.Pass()) {} | 676 comparator_(comparator.Pass()), |
677 active_blob_registry_(this) {} | |
385 | 678 |
386 IndexedDBBackingStore::~IndexedDBBackingStore() { | 679 IndexedDBBackingStore::~IndexedDBBackingStore() { |
680 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { | |
681 ChildProcessSecurityPolicyImpl* policy = | |
682 ChildProcessSecurityPolicyImpl::GetInstance(); | |
683 for (std::set<int>::iterator iter = child_process_ids_granted_.begin(); | |
684 iter != child_process_ids_granted_.end(); ++iter) { | |
685 policy->RevokeAllPermissionsForFile(*iter, blob_path_); | |
686 } | |
687 } | |
387 // db_'s destructor uses comparator_. The order of destruction is important. | 688 // db_'s destructor uses comparator_. The order of destruction is important. |
388 db_.reset(); | 689 db_.reset(); |
389 comparator_.reset(); | 690 comparator_.reset(); |
390 } | 691 } |
391 | 692 |
392 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( | 693 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( |
393 const std::string& primary_key, | 694 const std::string& primary_key, |
394 int64 version) | 695 int64 version) |
395 : primary_key_(primary_key), version_(version) { | 696 : primary_key_(primary_key), version_(version) { |
396 DCHECK(!primary_key.empty()); | 697 DCHECK(!primary_key.empty()); |
(...skipping 18 matching lines...) Expand all Loading... | |
415 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 716 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
416 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, | 717 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, |
417 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, | 718 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, |
418 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, | 719 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, |
419 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, | 720 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, |
420 INDEXED_DB_BACKING_STORE_OPEN_MAX, | 721 INDEXED_DB_BACKING_STORE_OPEN_MAX, |
421 }; | 722 }; |
422 | 723 |
423 // static | 724 // static |
424 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 725 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
726 IndexedDBFactory* indexed_db_factory, | |
425 const GURL& origin_url, | 727 const GURL& origin_url, |
426 const base::FilePath& path_base, | 728 const base::FilePath& path_base, |
729 net::URLRequestContext* request_context, | |
427 blink::WebIDBDataLoss* data_loss, | 730 blink::WebIDBDataLoss* data_loss, |
428 std::string* data_loss_message, | 731 std::string* data_loss_message, |
429 bool* disk_full) { | 732 bool* disk_full, |
733 base::TaskRunner* task_runner, | |
734 bool clean_journal) { | |
430 *data_loss = blink::WebIDBDataLossNone; | 735 *data_loss = blink::WebIDBDataLossNone; |
431 DefaultLevelDBFactory leveldb_factory; | 736 DefaultLevelDBFactory leveldb_factory; |
432 return IndexedDBBackingStore::Open(origin_url, | 737 return IndexedDBBackingStore::Open(indexed_db_factory, |
738 origin_url, | |
433 path_base, | 739 path_base, |
740 request_context, | |
434 data_loss, | 741 data_loss, |
435 data_loss_message, | 742 data_loss_message, |
436 disk_full, | 743 disk_full, |
437 &leveldb_factory); | 744 &leveldb_factory, |
745 task_runner, | |
746 clean_journal); | |
438 } | 747 } |
439 | 748 |
440 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { | 749 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { |
441 if (origin_url.host() == "docs.google.com") | 750 if (origin_url.host() == "docs.google.com") |
442 return ".Docs"; | 751 return ".Docs"; |
443 return std::string(); | 752 return std::string(); |
444 } | 753 } |
445 | 754 |
446 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, | 755 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, |
447 const GURL& origin_url) { | 756 const GURL& origin_url) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
488 min, | 797 min, |
489 max, | 798 max, |
490 num_buckets); | 799 num_buckets); |
491 return true; | 800 return true; |
492 } | 801 } |
493 return false; | 802 return false; |
494 } | 803 } |
495 | 804 |
496 // static | 805 // static |
497 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 806 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
807 IndexedDBFactory* indexed_db_factory, | |
498 const GURL& origin_url, | 808 const GURL& origin_url, |
499 const base::FilePath& path_base, | 809 const base::FilePath& path_base, |
810 net::URLRequestContext* request_context, | |
500 blink::WebIDBDataLoss* data_loss, | 811 blink::WebIDBDataLoss* data_loss, |
501 std::string* data_loss_message, | 812 std::string* data_loss_message, |
502 bool* is_disk_full, | 813 bool* is_disk_full, |
503 LevelDBFactory* leveldb_factory) { | 814 LevelDBFactory* leveldb_factory, |
815 base::TaskRunner* task_runner, | |
816 bool clean_journal) { | |
504 IDB_TRACE("IndexedDBBackingStore::Open"); | 817 IDB_TRACE("IndexedDBBackingStore::Open"); |
505 DCHECK(!path_base.empty()); | 818 DCHECK(!path_base.empty()); |
506 *data_loss = blink::WebIDBDataLossNone; | 819 *data_loss = blink::WebIDBDataLossNone; |
507 *data_loss_message = ""; | 820 *data_loss_message = ""; |
508 *is_disk_full = false; | 821 *is_disk_full = false; |
509 | 822 |
510 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 823 scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
511 | 824 |
512 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { | 825 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { |
513 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, | 826 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, |
514 origin_url); | 827 origin_url); |
515 } | 828 } |
516 if (!file_util::CreateDirectory(path_base)) { | 829 if (!file_util::CreateDirectory(path_base)) { |
517 LOG(ERROR) << "Unable to create IndexedDB database path " | 830 LOG(ERROR) << "Unable to create IndexedDB database path " |
518 << path_base.AsUTF8Unsafe(); | 831 << path_base.AsUTF8Unsafe(); |
519 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, | 832 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, |
520 origin_url); | 833 origin_url); |
521 return scoped_refptr<IndexedDBBackingStore>(); | 834 return scoped_refptr<IndexedDBBackingStore>(); |
522 } | 835 } |
523 | 836 |
524 const base::FilePath file_path = | 837 const base::FilePath file_path = |
525 path_base.Append(ComputeFileName(origin_url)); | 838 path_base.Append(ComputeFileName(origin_url)); |
839 const base::FilePath blob_path = | |
840 path_base.Append(ComputeBlobPath(origin_url)); | |
526 | 841 |
527 if (IsPathTooLong(file_path)) { | 842 if (IsPathTooLong(file_path)) { |
528 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, | 843 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, |
529 origin_url); | 844 origin_url); |
530 return scoped_refptr<IndexedDBBackingStore>(); | 845 return scoped_refptr<IndexedDBBackingStore>(); |
531 } | 846 } |
532 | 847 |
533 scoped_ptr<LevelDBDatabase> db; | 848 scoped_ptr<LevelDBDatabase> db; |
534 leveldb::Status status = leveldb_factory->OpenLevelDB( | 849 leveldb::Status status = leveldb_factory->OpenLevelDB( |
535 file_path, comparator.get(), &db, is_disk_full); | 850 file_path, comparator.get(), &db, is_disk_full); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 origin_url); | 915 origin_url); |
601 } | 916 } |
602 | 917 |
603 if (!db) { | 918 if (!db) { |
604 NOTREACHED(); | 919 NOTREACHED(); |
605 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, | 920 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, |
606 origin_url); | 921 origin_url); |
607 return scoped_refptr<IndexedDBBackingStore>(); | 922 return scoped_refptr<IndexedDBBackingStore>(); |
608 } | 923 } |
609 | 924 |
610 return Create(origin_url, db.Pass(), comparator.Pass()); | 925 scoped_refptr<IndexedDBBackingStore> backing_store = Create( |
926 indexed_db_factory, origin_url, blob_path, request_context, db.Pass(), | |
927 comparator.Pass(), task_runner); | |
928 | |
929 if (clean_journal && !backing_store->CleanUpBlobJournal( | |
930 LiveBlobJournalKey::Encode())) | |
931 return scoped_refptr<IndexedDBBackingStore>(); | |
932 return backing_store; | |
611 } | 933 } |
612 | 934 |
613 // static | 935 // static |
614 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 936 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
615 const GURL& origin_url) { | 937 const GURL& origin_url, base::TaskRunner* task_runner) { |
616 DefaultLevelDBFactory leveldb_factory; | 938 DefaultLevelDBFactory leveldb_factory; |
617 return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory); | 939 return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory, |
940 task_runner); | |
618 } | 941 } |
619 | 942 |
620 // static | 943 // static |
621 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 944 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
622 const GURL& origin_url, | 945 const GURL& origin_url, |
623 LevelDBFactory* leveldb_factory) { | 946 LevelDBFactory* leveldb_factory, |
947 base::TaskRunner* task_runner) { | |
624 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); | 948 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); |
625 | 949 |
626 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 950 scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
627 scoped_ptr<LevelDBDatabase> db = | 951 scoped_ptr<LevelDBDatabase> db = |
628 LevelDBDatabase::OpenInMemory(comparator.get()); | 952 LevelDBDatabase::OpenInMemory(comparator.get()); |
629 if (!db) { | 953 if (!db) { |
630 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; | 954 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; |
631 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, | 955 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
632 origin_url); | 956 origin_url); |
633 return scoped_refptr<IndexedDBBackingStore>(); | 957 return scoped_refptr<IndexedDBBackingStore>(); |
634 } | 958 } |
635 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); | 959 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); |
636 | 960 |
637 return Create(origin_url, db.Pass(), comparator.Pass()); | 961 return Create(NULL, origin_url, FilePath(), NULL, db.Pass(), |
962 comparator.Pass(), task_runner); | |
638 } | 963 } |
639 | 964 |
640 // static | 965 // static |
641 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 966 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( |
967 IndexedDBFactory* indexed_db_factory, | |
642 const GURL& origin_url, | 968 const GURL& origin_url, |
969 const FilePath& blob_path, | |
970 net::URLRequestContext* request_context, | |
643 scoped_ptr<LevelDBDatabase> db, | 971 scoped_ptr<LevelDBDatabase> db, |
644 scoped_ptr<LevelDBComparator> comparator) { | 972 scoped_ptr<LevelDBComparator> comparator, |
973 base::TaskRunner* task_runner) { | |
645 // TODO(jsbell): Handle comparator name changes. | 974 // TODO(jsbell): Handle comparator name changes. |
646 | |
647 scoped_refptr<IndexedDBBackingStore> backing_store( | 975 scoped_refptr<IndexedDBBackingStore> backing_store( |
648 new IndexedDBBackingStore(origin_url, db.Pass(), comparator.Pass())); | 976 new IndexedDBBackingStore(indexed_db_factory, origin_url, blob_path, |
649 if (!SetUpMetadata(backing_store->db_.get(), | 977 request_context, db.Pass(), comparator.Pass(), task_runner)); |
650 backing_store->origin_identifier_)) | 978 if (!backing_store->SetUpMetadata()) |
651 return scoped_refptr<IndexedDBBackingStore>(); | 979 return scoped_refptr<IndexedDBBackingStore>(); |
652 | 980 |
653 return backing_store; | 981 return backing_store; |
654 } | 982 } |
655 | 983 |
984 void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) { | |
985 if (!child_process_ids_granted_.count(child_process_id)) { | |
986 child_process_ids_granted_.insert(child_process_id); | |
987 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( | |
988 child_process_id, blob_path_); | |
989 } | |
990 } | |
991 | |
656 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { | 992 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { |
657 std::vector<string16> found_names; | 993 std::vector<string16> found_names; |
658 const std::string start_key = | 994 const std::string start_key = |
659 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); | 995 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); |
660 const std::string stop_key = | 996 const std::string stop_key = |
661 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); | 997 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); |
662 | 998 |
663 DCHECK(found_names.empty()); | 999 DCHECK(found_names.empty()); |
664 | 1000 |
665 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1001 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
723 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) | 1059 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) |
724 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | 1060 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; |
725 | 1061 |
726 ok = GetMaxObjectStoreId( | 1062 ok = GetMaxObjectStoreId( |
727 db_.get(), metadata->id, &metadata->max_object_store_id); | 1063 db_.get(), metadata->id, &metadata->max_object_store_id); |
728 if (!ok) { | 1064 if (!ok) { |
729 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | 1065 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
730 return false; | 1066 return false; |
731 } | 1067 } |
732 | 1068 |
1069 int64 blob_key_generator_current_number = | |
1070 DatabaseMetaDataKey::kInvalidBlobKey; | |
1071 | |
1072 ok = GetVarInt(db_.get(), | |
1073 DatabaseMetaDataKey::Encode( | |
1074 metadata->id, | |
1075 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
1076 &blob_key_generator_current_number, | |
1077 found); | |
1078 if (!ok) { | |
1079 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | |
1080 return false; | |
1081 } | |
1082 if (!*found) { | |
1083 // This database predates blob support. | |
1084 *found = true; | |
1085 } else if (!DatabaseMetaDataKey::IsValidBlobKey( | |
1086 blob_key_generator_current_number)) { | |
1087 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
1088 return false; | |
1089 } | |
1090 | |
733 return true; | 1091 return true; |
734 } | 1092 } |
735 | 1093 |
736 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBTransaction* transaction, | 1094 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBTransaction* transaction, |
737 int64* new_id) { | 1095 int64* new_id) { |
738 *new_id = -1; | 1096 *new_id = -1; |
739 int64 max_database_id = -1; | 1097 int64 max_database_id = -1; |
740 bool found = false; | 1098 bool found = false; |
741 bool ok = | 1099 bool ok = |
742 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); | 1100 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
774 DatabaseNameKey::Encode(origin_identifier_, name), | 1132 DatabaseNameKey::Encode(origin_identifier_, name), |
775 *row_id); | 1133 *row_id); |
776 PutString( | 1134 PutString( |
777 transaction.get(), | 1135 transaction.get(), |
778 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), | 1136 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), |
779 version); | 1137 version); |
780 PutVarInt(transaction.get(), | 1138 PutVarInt(transaction.get(), |
781 DatabaseMetaDataKey::Encode(*row_id, | 1139 DatabaseMetaDataKey::Encode(*row_id, |
782 DatabaseMetaDataKey::USER_INT_VERSION), | 1140 DatabaseMetaDataKey::USER_INT_VERSION), |
783 int_version); | 1141 int_version); |
1142 PutVarInt( | |
1143 transaction.get(), | |
1144 DatabaseMetaDataKey::Encode(*row_id, | |
1145 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
1146 DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber); | |
784 if (!transaction->Commit()) { | 1147 if (!transaction->Commit()) { |
785 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); | 1148 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); |
786 return false; | 1149 return false; |
787 } | 1150 } |
788 return true; | 1151 return true; |
789 } | 1152 } |
790 | 1153 |
791 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( | 1154 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( |
792 IndexedDBBackingStore::Transaction* transaction, | 1155 IndexedDBBackingStore::Transaction* transaction, |
793 int64 row_id, | 1156 int64 row_id, |
794 int64 int_version) { | 1157 int64 int_version) { |
795 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) | 1158 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) |
796 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; | 1159 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; |
797 DCHECK_GE(int_version, 0) << "int_version was " << int_version; | 1160 DCHECK_GE(int_version, 0) << "int_version was " << int_version; |
798 PutVarInt(transaction->transaction(), | 1161 PutVarInt(transaction->transaction(), |
799 DatabaseMetaDataKey::Encode(row_id, | 1162 DatabaseMetaDataKey::Encode(row_id, |
800 DatabaseMetaDataKey::USER_INT_VERSION), | 1163 DatabaseMetaDataKey::USER_INT_VERSION), |
801 int_version); | 1164 int_version); |
802 return true; | 1165 return true; |
803 } | 1166 } |
804 | 1167 |
805 static void DeleteRange(LevelDBTransaction* transaction, | 1168 // Note that if you're deleting a range that contains user keys that have blob |
806 const std::string& begin, | 1169 // info, this won't clean up the blobs. |
807 const std::string& end) { | 1170 static void DeleteRangeByKeys(LevelDBTransaction* transaction, |
1171 const std::string& begin, | |
1172 const std::string& end) { | |
808 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); | 1173 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); |
809 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; | 1174 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; |
810 it->Next()) | 1175 it->Next()) |
811 transaction->Remove(it->Key()); | 1176 transaction->Remove(it->Key()); |
812 } | 1177 } |
813 | 1178 |
1179 // For a whole-object-store deletion, we still use the one-blob-record-at-a-time | |
1180 // deletion mechanism designed for normal transactions. We could go with the | |
1181 // nuke-the-whole-directory method used for deleteDatabase if we structured the | |
1182 // directories accordingly, but that would complicate the kind of info we store | |
1183 // in the LevelDBTransaction and lengthen paths. | |
1184 static void DeleteBlobsInObjectStore( | |
1185 IndexedDBBackingStore::Transaction* transaction, | |
1186 int64 database_id, int64 object_store_id) { | |
1187 std::string start_key, end_key; | |
1188 start_key = | |
1189 BlobEntryKey::EncodeMinForObjectStore(database_id, object_store_id); | |
1190 end_key = | |
1191 BlobEntryKey::EncodeMaxForObjectStore(database_id, object_store_id); | |
1192 | |
1193 scoped_ptr<LevelDBIterator> it = | |
1194 transaction->transaction()->CreateIterator(); | |
1195 for (it->Seek(start_key); | |
1196 it->IsValid() && CompareKeys(it->Key(), end_key) < 0; it->Next()) { | |
1197 StringPiece key_piece(it->Key()); | |
1198 std::string user_key = | |
1199 BlobEntryKey::ReencodeToObjectStoreDataKey(&key_piece); | |
1200 if (user_key.size()) | |
1201 transaction->PutBlobInfo(database_id, object_store_id, user_key, NULL, | |
1202 NULL); | |
1203 else | |
1204 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
jsbell
2013/12/18 23:04:40
Intentionally keep going in case of error here?
M
ericu
2013/12/19 05:19:11
Actually, we should stop on error. Fixed.
| |
1205 } | |
1206 } | |
1207 | |
1208 static bool GetBlobInfoForRecord( | |
1209 IndexedDBBackingStore* backing_store, | |
1210 LevelDBTransaction* leveldb_transaction, | |
1211 int64 database_id, | |
1212 const std::string& leveldb_key, | |
1213 IndexedDBValue* value) { | |
1214 | |
1215 BlobEntryKey blob_entry_key; | |
1216 StringPiece leveldb_key_piece(leveldb_key); | |
1217 if (!BlobEntryKey::FromObjectStoreDataKey( | |
1218 &leveldb_key_piece, &blob_entry_key)) { | |
1219 NOTREACHED(); | |
1220 return false; | |
1221 } | |
1222 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); | |
1223 std::string encoded_key = blob_entry_key.Encode(); | |
1224 it->Seek(encoded_key); | |
1225 if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) { | |
1226 if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) { | |
1227 INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD); | |
1228 return false; | |
1229 } | |
1230 std::vector<IndexedDBBlobInfo>::iterator iter; | |
1231 for (iter = value->blob_info.begin(); iter != value->blob_info.end(); | |
1232 ++iter) { | |
1233 iter->set_file_path( | |
1234 backing_store->GetIDBBlobFileName(database_id, iter->key())); | |
1235 iter->set_mark_used_callback( | |
1236 backing_store->active_blob_registry()->GetAddBlobRefCallback( | |
1237 database_id, iter->key())); | |
1238 iter->set_release_callback( | |
1239 backing_store->active_blob_registry()->GetFinalReleaseCallback( | |
1240 database_id, iter->key())); | |
1241 if (iter->is_file()) { | |
1242 base::PlatformFileInfo info; | |
1243 if (file_util::GetFileInfo(iter->file_path(), &info)) { | |
1244 // This should always work, but it isn't fatal if it doesn't; it just | |
1245 // means a potential slow synchronous call from the renderer later. | |
1246 iter->set_last_modified(info.last_modified); | |
1247 iter->set_size(info.size); | |
1248 } | |
1249 } | |
1250 } | |
1251 } | |
1252 return true; | |
1253 } | |
1254 | |
814 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { | 1255 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { |
815 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); | 1256 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); |
816 scoped_ptr<LevelDBWriteOnlyTransaction> transaction = | 1257 scoped_ptr<LevelDBUncachedTransaction> transaction = |
817 LevelDBWriteOnlyTransaction::Create(db_.get()); | 1258 LevelDBUncachedTransaction::Create(db_.get()); |
1259 | |
1260 if (!CleanUpBlobJournal(BlobJournalKey::Encode())) | |
1261 return false; | |
818 | 1262 |
819 IndexedDBDatabaseMetadata metadata; | 1263 IndexedDBDatabaseMetadata metadata; |
820 bool success = false; | 1264 bool success = false; |
821 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); | 1265 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); |
822 if (!ok) | 1266 if (!ok) |
823 return false; | 1267 return false; |
824 if (!success) | 1268 if (!success) |
825 return true; | 1269 return true; |
826 | 1270 |
827 const std::string start_key = DatabaseMetaDataKey::Encode( | 1271 const std::string start_key = DatabaseMetaDataKey::Encode( |
828 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); | 1272 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); |
829 const std::string stop_key = DatabaseMetaDataKey::Encode( | 1273 const std::string stop_key = DatabaseMetaDataKey::Encode( |
830 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); | 1274 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); |
831 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1275 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
832 for (it->Seek(start_key); | 1276 for (it->Seek(start_key); |
833 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 1277 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; |
834 it->Next()) | 1278 it->Next()) |
835 transaction->Remove(it->Key()); | 1279 transaction->Remove(it->Key()); |
836 | 1280 |
837 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); | 1281 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); |
838 transaction->Remove(key); | 1282 transaction->Remove(key); |
839 | 1283 |
1284 bool need_cleanup = false; | |
1285 if (active_blob_registry()->MarkDeletedCheckIfUsed( | |
1286 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { | |
1287 if (!MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id)) | |
1288 return false; | |
1289 } else { | |
1290 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); | |
1291 need_cleanup = true; | |
1292 } | |
1293 | |
840 if (!transaction->Commit()) { | 1294 if (!transaction->Commit()) { |
841 INTERNAL_WRITE_ERROR(DELETE_DATABASE); | 1295 INTERNAL_WRITE_ERROR(DELETE_DATABASE); |
842 return false; | 1296 return false; |
843 } | 1297 } |
1298 | |
1299 if (need_cleanup) | |
1300 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
1301 | |
844 return true; | 1302 return true; |
845 } | 1303 } |
846 | 1304 |
847 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1305 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
848 const std::string& stop_key, | 1306 const std::string& stop_key, |
849 int64 object_store_id, | 1307 int64 object_store_id, |
850 int64 meta_data_type) { | 1308 int64 meta_data_type) { |
851 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1309 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
852 return false; | 1310 return false; |
853 | 1311 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
926 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1384 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
927 break; | 1385 break; |
928 } | 1386 } |
929 bool auto_increment; | 1387 bool auto_increment; |
930 { | 1388 { |
931 StringPiece slice(it->Value()); | 1389 StringPiece slice(it->Value()); |
932 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) | 1390 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) |
933 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1391 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
934 } | 1392 } |
935 | 1393 |
936 it->Next(); // Is evicatble. | 1394 it->Next(); // Is evictable. |
937 if (!CheckObjectStoreAndMetaDataType(it.get(), | 1395 if (!CheckObjectStoreAndMetaDataType(it.get(), |
938 stop_key, | 1396 stop_key, |
939 object_store_id, | 1397 object_store_id, |
940 ObjectStoreMetaDataKey::EVICTABLE)) { | 1398 ObjectStoreMetaDataKey::EVICTABLE)) { |
941 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1399 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
942 break; | 1400 break; |
943 } | 1401 } |
944 | 1402 |
945 it->Next(); // Last version. | 1403 it->Next(); // Last version. |
946 if (!CheckObjectStoreAndMetaDataType( | 1404 if (!CheckObjectStoreAndMetaDataType( |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1113 &found); | 1571 &found); |
1114 if (!ok) { | 1572 if (!ok) { |
1115 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); | 1573 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); |
1116 return false; | 1574 return false; |
1117 } | 1575 } |
1118 if (!found) { | 1576 if (!found) { |
1119 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); | 1577 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); |
1120 return false; | 1578 return false; |
1121 } | 1579 } |
1122 | 1580 |
1123 DeleteRange( | 1581 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); |
1582 DeleteRangeByKeys( | |
1124 leveldb_transaction, | 1583 leveldb_transaction, |
1125 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), | 1584 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), |
1126 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1585 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); |
1127 | 1586 |
1128 leveldb_transaction->Remove( | 1587 leveldb_transaction->Remove( |
1129 ObjectStoreNamesKey::Encode(database_id, object_store_name)); | 1588 ObjectStoreNamesKey::Encode(database_id, object_store_name)); |
1130 | 1589 |
1131 DeleteRange(leveldb_transaction, | 1590 DeleteRangeByKeys( |
1132 IndexFreeListKey::Encode(database_id, object_store_id, 0), | 1591 leveldb_transaction, |
1133 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); | 1592 IndexFreeListKey::Encode(database_id, object_store_id, 0), |
1134 DeleteRange(leveldb_transaction, | 1593 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); |
1135 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | 1594 DeleteRangeByKeys( |
1136 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1595 leveldb_transaction, |
1596 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | |
1597 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | |
1137 | 1598 |
1138 return ClearObjectStore(transaction, database_id, object_store_id); | 1599 return ClearObjectStore(transaction, database_id, object_store_id); |
1139 } | 1600 } |
1140 | 1601 |
1141 bool IndexedDBBackingStore::GetRecord( | 1602 bool IndexedDBBackingStore::GetRecord( |
1142 IndexedDBBackingStore::Transaction* transaction, | 1603 IndexedDBBackingStore::Transaction* transaction, |
1143 int64 database_id, | 1604 int64 database_id, |
1144 int64 object_store_id, | 1605 int64 object_store_id, |
1145 const IndexedDBKey& key, | 1606 const IndexedDBKey& key, |
1146 std::string* record) { | 1607 IndexedDBValue* record) { |
1147 IDB_TRACE("IndexedDBBackingStore::GetRecord"); | 1608 IDB_TRACE("IndexedDBBackingStore::GetRecord"); |
1148 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1609 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
1149 return false; | 1610 return false; |
1150 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1611 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
1151 | 1612 |
1152 const std::string leveldb_key = | 1613 const std::string leveldb_key = |
1153 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1614 ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
1154 std::string data; | 1615 std::string data; |
1155 | 1616 |
1156 record->clear(); | 1617 record->clear(); |
(...skipping 11 matching lines...) Expand all Loading... | |
1168 return false; | 1629 return false; |
1169 } | 1630 } |
1170 | 1631 |
1171 int64 version; | 1632 int64 version; |
1172 StringPiece slice(data); | 1633 StringPiece slice(data); |
1173 if (!DecodeVarInt(&slice, &version)) { | 1634 if (!DecodeVarInt(&slice, &version)) { |
1174 INTERNAL_READ_ERROR(GET_RECORD); | 1635 INTERNAL_READ_ERROR(GET_RECORD); |
1175 return false; | 1636 return false; |
1176 } | 1637 } |
1177 | 1638 |
1178 *record = slice.as_string(); | 1639 record->bits = slice.as_string(); |
1179 return true; | 1640 return GetBlobInfoForRecord( |
1641 this, leveldb_transaction, database_id, leveldb_key, record); | |
1180 } | 1642 } |
1181 | 1643 |
1182 WARN_UNUSED_RESULT static bool GetNewVersionNumber( | 1644 WARN_UNUSED_RESULT static bool GetNewVersionNumber( |
1183 LevelDBTransaction* transaction, | 1645 LevelDBTransaction* transaction, |
1184 int64 database_id, | 1646 int64 database_id, |
1185 int64 object_store_id, | 1647 int64 object_store_id, |
1186 int64* new_version_number) { | 1648 int64* new_version_number) { |
1187 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( | 1649 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( |
1188 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); | 1650 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); |
1189 | 1651 |
(...skipping 18 matching lines...) Expand all Loading... | |
1208 | 1670 |
1209 *new_version_number = version; | 1671 *new_version_number = version; |
1210 return true; | 1672 return true; |
1211 } | 1673 } |
1212 | 1674 |
1213 bool IndexedDBBackingStore::PutRecord( | 1675 bool IndexedDBBackingStore::PutRecord( |
1214 IndexedDBBackingStore::Transaction* transaction, | 1676 IndexedDBBackingStore::Transaction* transaction, |
1215 int64 database_id, | 1677 int64 database_id, |
1216 int64 object_store_id, | 1678 int64 object_store_id, |
1217 const IndexedDBKey& key, | 1679 const IndexedDBKey& key, |
1218 const std::string& value, | 1680 IndexedDBValue& value, |
1681 ScopedVector<webkit_blob::BlobDataHandle>* handles, | |
1219 RecordIdentifier* record_identifier) { | 1682 RecordIdentifier* record_identifier) { |
1220 IDB_TRACE("IndexedDBBackingStore::PutRecord"); | 1683 IDB_TRACE("IndexedDBBackingStore::PutRecord"); |
1221 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1684 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
1222 return false; | 1685 return false; |
1223 DCHECK(key.IsValid()); | 1686 DCHECK(key.IsValid()); |
1224 | 1687 |
1225 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1688 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
1226 int64 version = -1; | 1689 int64 version = -1; |
1227 bool ok = GetNewVersionNumber( | 1690 bool ok = GetNewVersionNumber( |
1228 leveldb_transaction, database_id, object_store_id, &version); | 1691 leveldb_transaction, database_id, object_store_id, &version); |
1229 if (!ok) | 1692 if (!ok) |
1230 return false; | 1693 return false; |
1231 DCHECK_GE(version, 0); | 1694 DCHECK_GE(version, 0); |
1232 const std::string object_storedata_key = | 1695 const std::string object_store_data_key = |
1233 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1696 ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
1234 | 1697 |
1235 std::string v; | 1698 std::string v; |
1236 EncodeVarInt(version, &v); | 1699 EncodeVarInt(version, &v); |
1237 v.append(value); | 1700 v.append(value.bits); |
1238 | 1701 |
1239 leveldb_transaction->Put(object_storedata_key, &v); | 1702 leveldb_transaction->Put(object_store_data_key, &v); |
1703 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
1704 &value.blob_info, handles); | |
1705 DCHECK(!handles->size()); | |
1240 | 1706 |
1241 const std::string exists_entry_key = | 1707 const std::string exists_entry_key = |
1242 ExistsEntryKey::Encode(database_id, object_store_id, key); | 1708 ExistsEntryKey::Encode(database_id, object_store_id, key); |
1243 std::string version_encoded; | 1709 std::string version_encoded; |
1244 EncodeInt(version, &version_encoded); | 1710 EncodeInt(version, &version_encoded); |
1245 leveldb_transaction->Put(exists_entry_key, &version_encoded); | 1711 leveldb_transaction->Put(exists_entry_key, &version_encoded); |
1246 | 1712 |
1247 std::string key_encoded; | 1713 std::string key_encoded; |
1248 EncodeIDBKey(key, &key_encoded); | 1714 EncodeIDBKey(key, &key_encoded); |
1249 record_identifier->Reset(key_encoded, version); | 1715 record_identifier->Reset(key_encoded, version); |
1250 return true; | 1716 return true; |
1251 } | 1717 } |
1252 | 1718 |
1253 bool IndexedDBBackingStore::ClearObjectStore( | 1719 bool IndexedDBBackingStore::ClearObjectStore( |
1254 IndexedDBBackingStore::Transaction* transaction, | 1720 IndexedDBBackingStore::Transaction* transaction, |
1255 int64 database_id, | 1721 int64 database_id, |
1256 int64 object_store_id) { | 1722 int64 object_store_id) { |
1257 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); | 1723 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); |
1258 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1724 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
1259 return false; | 1725 return false; |
1260 const std::string start_key = | 1726 const std::string start_key = |
1261 KeyPrefix(database_id, object_store_id).Encode(); | 1727 KeyPrefix(database_id, object_store_id).Encode(); |
1262 const std::string stop_key = | 1728 const std::string stop_key = |
1263 KeyPrefix(database_id, object_store_id + 1).Encode(); | 1729 KeyPrefix(database_id, object_store_id + 1).Encode(); |
1264 | 1730 |
1265 DeleteRange(transaction->transaction(), start_key, stop_key); | 1731 DeleteRangeByKeys(transaction->transaction(), start_key, stop_key); |
1732 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); | |
1266 return true; | 1733 return true; |
1267 } | 1734 } |
1268 | 1735 |
1269 bool IndexedDBBackingStore::DeleteRecord( | 1736 bool IndexedDBBackingStore::DeleteRecord( |
1270 IndexedDBBackingStore::Transaction* transaction, | 1737 IndexedDBBackingStore::Transaction* transaction, |
1271 int64 database_id, | 1738 int64 database_id, |
1272 int64 object_store_id, | 1739 int64 object_store_id, |
1273 const RecordIdentifier& record_identifier) { | 1740 const RecordIdentifier& record_identifier) { |
1274 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); | 1741 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); |
1275 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1742 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
1276 return false; | 1743 return false; |
1277 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1744 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
1278 | 1745 |
1279 const std::string object_store_data_key = ObjectStoreDataKey::Encode( | 1746 const std::string object_store_data_key = ObjectStoreDataKey::Encode( |
1280 database_id, object_store_id, record_identifier.primary_key()); | 1747 database_id, object_store_id, record_identifier.primary_key()); |
1281 leveldb_transaction->Remove(object_store_data_key); | 1748 leveldb_transaction->Remove(object_store_data_key); |
1749 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
1750 NULL, NULL); | |
1282 | 1751 |
1283 const std::string exists_entry_key = ExistsEntryKey::Encode( | 1752 const std::string exists_entry_key = ExistsEntryKey::Encode( |
1284 database_id, object_store_id, record_identifier.primary_key()); | 1753 database_id, object_store_id, record_identifier.primary_key()); |
1285 leveldb_transaction->Remove(exists_entry_key); | 1754 leveldb_transaction->Remove(exists_entry_key); |
1286 return true; | 1755 return true; |
1287 } | 1756 } |
1288 | 1757 |
1758 bool IndexedDBBackingStore::DeleteRange( | |
1759 IndexedDBBackingStore::Transaction* transaction, | |
1760 int64 database_id, | |
1761 int64 object_store_id, | |
1762 const IndexedDBKeyRange& key_range) { | |
1763 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
1764 OpenObjectStoreCursor(transaction, database_id, object_store_id, | |
1765 key_range, indexed_db::CURSOR_NEXT); | |
1766 // TODO(ericu): This does a PutBlobInfo for every record, even if it doesn't | |
1767 // have any blobs associated with it. We could skip that, and just scan | |
1768 // through the blob table to see which ones we need to remove. That might | |
1769 // take a little more time here, but would also potentially allocate a lot | |
1770 // fewer BlobChangeRecords, shrink the eventual WriteBatch, and do a lot fewer | |
1771 // seeks in CollectBlobFilesToRemove. | |
1772 if (backing_store_cursor) { | |
1773 do { | |
1774 if (!DeleteRecord( | |
1775 transaction, database_id, object_store_id, | |
1776 backing_store_cursor->record_identifier())) | |
1777 return false; | |
1778 } while (backing_store_cursor->Continue()); | |
1779 } | |
1780 return true; | |
1781 } | |
1782 | |
1289 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( | 1783 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( |
1290 IndexedDBBackingStore::Transaction* transaction, | 1784 IndexedDBBackingStore::Transaction* transaction, |
1291 int64 database_id, | 1785 int64 database_id, |
1292 int64 object_store_id, | 1786 int64 object_store_id, |
1293 int64* key_generator_current_number) { | 1787 int64* key_generator_current_number) { |
1294 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1788 if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
1295 return false; | 1789 return false; |
1296 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 1790 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
1297 | 1791 |
1298 const std::string key_generator_current_number_key = | 1792 const std::string key_generator_current_number_key = |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1414 StringPiece slice(data); | 1908 StringPiece slice(data); |
1415 if (!DecodeVarInt(&slice, &version)) | 1909 if (!DecodeVarInt(&slice, &version)) |
1416 return false; | 1910 return false; |
1417 | 1911 |
1418 std::string encoded_key; | 1912 std::string encoded_key; |
1419 EncodeIDBKey(key, &encoded_key); | 1913 EncodeIDBKey(key, &encoded_key); |
1420 found_record_identifier->Reset(encoded_key, version); | 1914 found_record_identifier->Reset(encoded_key, version); |
1421 return true; | 1915 return true; |
1422 } | 1916 } |
1423 | 1917 |
1918 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl : public | |
1919 IndexedDBBackingStore::Transaction::ChainedBlobWriter { | |
1920 public: | |
1921 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec | |
1922 WriteDescriptorVec; | |
1923 ChainedBlobWriterImpl( | |
1924 int64 database_id, | |
1925 IndexedDBBackingStore* backingStore, | |
1926 WriteDescriptorVec& blobs, | |
1927 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) | |
1928 : waiting_for_callback_(false), | |
1929 database_id_(database_id), | |
1930 backing_store_(backingStore), | |
1931 callback_(callback), | |
1932 aborted_(false) { | |
1933 blobs_.swap(blobs); | |
1934 iter_ = blobs_.begin(); | |
1935 WriteNextFile(); | |
1936 } | |
1937 | |
1938 void set_delegate(scoped_ptr<FileWriterDelegate> delegate) { | |
1939 delegate_.reset(delegate.release()); | |
1940 } | |
1941 | |
1942 void ReportWriteCompletion(bool succeeded, int64 bytes_written) { | |
1943 // TODO(ericu): Check bytes_written against the blob's snapshot value. | |
1944 DCHECK(waiting_for_callback_); | |
1945 DCHECK(!succeeded || bytes_written >= 0); | |
1946 waiting_for_callback_ = false; | |
1947 content::BrowserThread::DeleteSoon( | |
1948 content::BrowserThread::IO, FROM_HERE, | |
1949 delegate_.release()); | |
1950 if (aborted_) { | |
1951 self_ref_ = NULL; | |
1952 return; | |
1953 } | |
1954 if (succeeded) | |
1955 WriteNextFile(); | |
1956 else | |
1957 callback_->didFail(); | |
1958 } | |
1959 | |
1960 void Abort() { | |
1961 if (!waiting_for_callback_) | |
1962 return; | |
1963 self_ref_ = this; | |
1964 aborted_ = true; | |
1965 } | |
1966 | |
1967 private: | |
1968 void WriteNextFile() { | |
1969 DCHECK(!waiting_for_callback_); | |
1970 DCHECK(!aborted_); | |
1971 if (iter_ == blobs_.end()) { | |
1972 DCHECK(!self_ref_); | |
1973 callback_->didSucceed(); | |
1974 return; | |
1975 } else { | |
1976 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { | |
1977 callback_->didFail(); | |
1978 return; | |
1979 } | |
1980 waiting_for_callback_ = true; | |
1981 ++iter_; | |
1982 } | |
1983 } | |
1984 | |
1985 bool waiting_for_callback_; | |
1986 scoped_refptr<ChainedBlobWriterImpl> self_ref_; | |
1987 WriteDescriptorVec blobs_; | |
1988 WriteDescriptorVec::const_iterator iter_; | |
1989 int64 database_id_; | |
1990 IndexedDBBackingStore* backing_store_; | |
1991 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; | |
1992 scoped_ptr<FileWriterDelegate> delegate_; | |
1993 bool aborted_; | |
1994 }; | |
1995 | |
1996 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, | |
1997 public base::RefCounted<LocalWriteClosure> { | |
1998 public: | |
1999 LocalWriteClosure( | |
2000 IndexedDBBackingStore::Transaction::ChainedBlobWriter* | |
2001 chained_blob_writer_, | |
2002 base::TaskRunner* task_runner) | |
2003 : chained_blob_writer_(chained_blob_writer_), | |
2004 task_runner_(task_runner), | |
2005 bytes_written_(-1) { | |
2006 } | |
2007 | |
2008 void Run( | |
2009 base::PlatformFileError rv, | |
2010 int64 bytes, | |
2011 FileWriterDelegate::WriteProgressStatus write_status) { | |
2012 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) | |
2013 return; // We don't care about progress events. | |
2014 if (rv == base::PLATFORM_FILE_OK) { | |
2015 DCHECK(bytes >= 0); | |
2016 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); | |
2017 bytes_written_ = bytes; | |
2018 } else { | |
2019 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || | |
2020 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); | |
2021 } | |
2022 task_runner_->PostTask( | |
2023 FROM_HERE, | |
2024 base::Bind( | |
2025 &LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, this, | |
2026 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); | |
2027 } | |
2028 | |
2029 void writeBlobToFileOnIOThread( | |
2030 const FilePath& file_path, const GURL& blob_url, | |
2031 net::URLRequestContext* request_context) { | |
2032 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
2033 scoped_ptr<fileapi::FileStreamWriter> writer( | |
2034 fileapi::FileStreamWriter::CreateForLocalFile( | |
2035 task_runner_, file_path, 0, false)); | |
2036 scoped_ptr<FileWriterDelegate> delegate( | |
2037 new FileWriterDelegate(writer.Pass())); | |
2038 | |
2039 DCHECK(blob_url.is_valid()); | |
2040 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( | |
2041 blob_url, net::DEFAULT_PRIORITY, delegate.get())); | |
2042 | |
2043 delegate->Start(blob_request.Pass(), | |
2044 base::Bind(&LocalWriteClosure::Run, this)); | |
2045 chained_blob_writer_->set_delegate(delegate.Pass()); | |
2046 } | |
2047 | |
2048 private: | |
2049 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { | |
2050 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
2051 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); | |
2052 } | |
2053 | |
2054 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; | |
2055 base::TaskRunner* task_runner_; | |
2056 int64 bytes_written_; | |
2057 }; | |
2058 | |
2059 bool IndexedDBBackingStore::WriteBlobFile( | |
2060 int64 database_id, | |
2061 const Transaction::WriteDescriptor& descriptor, | |
2062 Transaction::ChainedBlobWriter* chained_blob_writer) { | |
2063 | |
2064 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) | |
2065 return false; | |
2066 | |
2067 FilePath path = GetIDBBlobFileName(database_id, descriptor.key()); | |
2068 | |
2069 if (descriptor.is_file()) { | |
2070 DCHECK(!descriptor.file_path().empty()); | |
2071 if (!base::CopyFile(descriptor.file_path(), path)) | |
2072 return false; | |
2073 | |
2074 base::PlatformFileInfo info; | |
2075 if (file_util::GetFileInfo(descriptor.file_path(), &info)) { | |
2076 // TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor | |
2077 // to include snapshot date and file size, and check both. | |
2078 if (!file_util::TouchFile(path, info.last_accessed, info.last_modified)) | |
2079 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
2080 } else { | |
2081 ; // TODO(ericu): Complain quietly; timestamp's probably not vital. | |
2082 } | |
2083 | |
2084 task_runner_->PostTask( | |
2085 FROM_HERE, | |
2086 base::Bind( | |
2087 &Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
2088 chained_blob_writer, true, info.size)); | |
2089 } else { | |
2090 DCHECK(descriptor.url().is_valid()); | |
2091 scoped_refptr<LocalWriteClosure> write_closure( | |
2092 new LocalWriteClosure(chained_blob_writer, task_runner_)); | |
2093 content::BrowserThread::PostTask( | |
2094 content::BrowserThread::IO, FROM_HERE, | |
2095 base::Bind( | |
2096 &LocalWriteClosure::writeBlobToFileOnIOThread, write_closure.get(), | |
2097 path, descriptor.url(), request_context_)); | |
2098 } | |
2099 return true; | |
2100 } | |
2101 | |
2102 void IndexedDBBackingStore::ReportBlobUnused( | |
2103 int64 database_id, | |
2104 int64 blob_key) { | |
2105 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
2106 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
2107 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
2108 scoped_refptr<LevelDBTransaction> transaction = | |
2109 new LevelDBTransaction(db_.get()); | |
2110 | |
2111 std::string live_blob_key = LiveBlobJournalKey::Encode(); | |
2112 IndexedDBBackingStore::Transaction::BlobJournalType live_blob_journal; | |
2113 if (!GetBlobJournal(live_blob_key, transaction.get(), live_blob_journal)) | |
2114 return; | |
2115 DCHECK(live_blob_journal.size()); | |
2116 | |
2117 std::string primary_key = BlobJournalKey::Encode(); | |
2118 IndexedDBBackingStore::Transaction::BlobJournalType primary_journal; | |
2119 if (!GetBlobJournal(primary_key, transaction.get(), primary_journal)) | |
2120 return; | |
2121 | |
2122 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
2123 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to | |
2124 // remove all entries with database_id from the live_blob journal and add only | |
2125 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) | |
2126 // and we hit kAllBlobsKey for the right database_id in the journal, we leave | |
2127 // the kAllBlobsKey entry in the live_blob journal but add the specific blob | |
2128 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a | |
2129 // matching (database_id, blob_key) tuple, we should move it to the primary | |
2130 // journal. | |
2131 IndexedDBBackingStore::Transaction::BlobJournalType new_live_blob_journal; | |
2132 for (journal_iter = live_blob_journal.begin(); | |
2133 journal_iter != live_blob_journal.end(); ++journal_iter) { | |
2134 int64 current_database_id = journal_iter->first; | |
2135 int64 current_blob_key = journal_iter->second; | |
2136 bool current_all_blobs = | |
2137 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
2138 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || | |
2139 current_all_blobs); | |
2140 if (current_database_id == database_id && (all_blobs || | |
2141 current_all_blobs || blob_key == current_blob_key)) { | |
2142 if (!all_blobs) { | |
2143 primary_journal.push_back( | |
2144 std::make_pair(database_id, current_blob_key)); | |
2145 if (current_all_blobs) | |
2146 new_live_blob_journal.push_back(*journal_iter); | |
2147 new_live_blob_journal.insert(new_live_blob_journal.end(), | |
2148 ++journal_iter, live_blob_journal.end()); // All the rest. | |
2149 break; | |
2150 } | |
2151 } else { | |
2152 new_live_blob_journal.push_back(*journal_iter); | |
2153 } | |
2154 } | |
2155 if (all_blobs) { | |
2156 primary_journal.push_back(std::make_pair( | |
2157 database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
2158 } | |
2159 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); | |
2160 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); | |
2161 transaction->Commit(); | |
2162 // We could just do the deletions/cleaning here, but if there are a lot of | |
2163 // blobs about to be garbage collected, it'd be better to wait and do them all | |
2164 // at once. | |
2165 StartJournalCleaningTimer(); | |
2166 } | |
2167 | |
2168 void IndexedDBBackingStore::StartJournalCleaningTimer() { | |
2169 journal_cleaning_timer_.Start( | |
2170 FROM_HERE, base::TimeDelta::FromSeconds(5), this, | |
jsbell
2013/12/18 23:04:40
Need to rationalize this time with the "lazy close
ericu
2013/12/19 05:19:11
Yeah, this is kind of arbitrary here. Also, if th
| |
2171 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); | |
2172 } | |
2173 | |
2174 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
2175 FilePath IndexedDBBackingStore::GetIDBBlobFileName( | |
2176 int64 database_id, int64 key) { | |
2177 FilePath path = GetIDBBlobDirectoryNameForKey(blob_path_, database_id, key); | |
2178 path = path.AppendASCII(base::StringPrintf("%lx", key)); | |
2179 return path; | |
2180 } | |
2181 | |
1424 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2182 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
1425 const std::string& stop_key, | 2183 const std::string& stop_key, |
1426 int64 index_id, | 2184 int64 index_id, |
1427 unsigned char meta_data_type) { | 2185 unsigned char meta_data_type) { |
1428 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2186 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) |
1429 return false; | 2187 return false; |
1430 | 2188 |
1431 StringPiece slice(it->Key()); | 2189 StringPiece slice(it->Key()); |
1432 IndexMetaDataKey meta_data_key; | 2190 IndexMetaDataKey meta_data_key; |
1433 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 2191 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1516 | 2274 |
1517 it->Next(); | 2275 it->Next(); |
1518 } | 2276 } |
1519 | 2277 |
1520 (*indexes)[index_id] = IndexedDBIndexMetadata( | 2278 (*indexes)[index_id] = IndexedDBIndexMetadata( |
1521 index_name, index_id, key_path, index_unique, index_multi_entry); | 2279 index_name, index_id, key_path, index_unique, index_multi_entry); |
1522 } | 2280 } |
1523 return true; | 2281 return true; |
1524 } | 2282 } |
1525 | 2283 |
2284 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | |
2285 FilePath fileName = GetIDBBlobFileName(database_id, key); | |
2286 return base::DeleteFile(fileName, false); | |
2287 } | |
2288 | |
2289 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | |
2290 FilePath dirName = GetIDBBlobDirectoryName(blob_path_, database_id); | |
2291 return base::DeleteFile(dirName, true); | |
2292 } | |
2293 | |
2294 bool IndexedDBBackingStore::CleanUpBlobJournal( | |
2295 const std::string& level_db_key) { | |
2296 scoped_refptr<LevelDBTransaction> journal_transaction = | |
2297 new LevelDBTransaction(db_.get()); | |
2298 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
2299 if (!GetBlobJournal(level_db_key, journal_transaction.get(), | |
2300 journal)) { | |
2301 return false; | |
2302 } | |
2303 if (!journal.size()) { | |
2304 return true; | |
2305 } | |
2306 if (journal.size()) { | |
jsbell
2013/12/18 23:04:40
Redundant with above check.
ericu
2013/12/19 05:19:11
Done.
| |
2307 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
2308 for (journal_iter = journal.begin(); journal_iter != journal.end(); | |
2309 ++journal_iter) { | |
2310 int64 database_id = journal_iter->first; | |
2311 int64 blob_key = journal_iter->second; | |
2312 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
2313 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { | |
2314 RemoveBlobDirectory(database_id); | |
2315 } else { | |
2316 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
2317 RemoveBlobFile(database_id, blob_key); | |
2318 } | |
2319 } | |
2320 } | |
2321 ClearBlobJournal(journal_transaction.get(), level_db_key); | |
2322 return journal_transaction->Commit(); | |
2323 } | |
2324 | |
2325 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { | |
2326 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
2327 } | |
2328 | |
1526 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, | 2329 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, |
1527 int64 database_id, | 2330 int64 database_id, |
1528 int64 object_store_id, | 2331 int64 object_store_id, |
1529 int64 index_id) { | 2332 int64 index_id) { |
1530 int64 max_index_id = -1; | 2333 int64 max_index_id = -1; |
1531 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2334 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( |
1532 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2335 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
1533 bool found = false; | 2336 bool found = false; |
1534 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); | 2337 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); |
1535 if (!ok) { | 2338 if (!ok) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1588 int64 index_id) { | 2391 int64 index_id) { |
1589 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); | 2392 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); |
1590 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) | 2393 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
1591 return false; | 2394 return false; |
1592 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 2395 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
1593 | 2396 |
1594 const std::string index_meta_data_start = | 2397 const std::string index_meta_data_start = |
1595 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); | 2398 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); |
1596 const std::string index_meta_data_end = | 2399 const std::string index_meta_data_end = |
1597 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2400 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
1598 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); | 2401 DeleteRangeByKeys(leveldb_transaction, index_meta_data_start, |
2402 index_meta_data_end); | |
1599 | 2403 |
1600 const std::string index_data_start = | 2404 const std::string index_data_start = |
1601 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); | 2405 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); |
1602 const std::string index_data_end = | 2406 const std::string index_data_end = |
1603 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2407 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
1604 DeleteRange(leveldb_transaction, index_data_start, index_data_end); | 2408 DeleteRangeByKeys(leveldb_transaction, index_data_start, index_data_end); |
1605 return true; | 2409 return true; |
1606 } | 2410 } |
1607 | 2411 |
1608 bool IndexedDBBackingStore::PutIndexDataForRecord( | 2412 bool IndexedDBBackingStore::PutIndexDataForRecord( |
1609 IndexedDBBackingStore::Transaction* transaction, | 2413 IndexedDBBackingStore::Transaction* transaction, |
1610 int64 database_id, | 2414 int64 database_id, |
1611 int64 object_store_id, | 2415 int64 object_store_id, |
1612 int64 index_id, | 2416 int64 index_id, |
1613 const IndexedDBKey& key, | 2417 const IndexedDBKey& key, |
1614 const RecordIdentifier& record_identifier) { | 2418 const RecordIdentifier& record_identifier) { |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1811 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); | 2615 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); |
1812 return false; | 2616 return false; |
1813 } | 2617 } |
1814 | 2618 |
1815 StringPiece slice(found_encoded_primary_key); | 2619 StringPiece slice(found_encoded_primary_key); |
1816 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); | 2620 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); |
1817 } | 2621 } |
1818 | 2622 |
1819 IndexedDBBackingStore::Cursor::Cursor( | 2623 IndexedDBBackingStore::Cursor::Cursor( |
1820 const IndexedDBBackingStore::Cursor* other) | 2624 const IndexedDBBackingStore::Cursor* other) |
1821 : transaction_(other->transaction_), | 2625 : backing_store_(other->backing_store_), |
2626 transaction_(other->transaction_), | |
2627 database_id_(other->database_id_), | |
1822 cursor_options_(other->cursor_options_), | 2628 cursor_options_(other->cursor_options_), |
1823 current_key_(new IndexedDBKey(*other->current_key_)) { | 2629 current_key_(new IndexedDBKey(*other->current_key_)) { |
1824 if (other->iterator_) { | 2630 if (other->iterator_) { |
1825 iterator_ = transaction_->CreateIterator(); | 2631 iterator_ = transaction_->CreateIterator(); |
1826 | 2632 |
1827 if (other->iterator_->IsValid()) { | 2633 if (other->iterator_->IsValid()) { |
1828 iterator_->Seek(other->iterator_->Key()); | 2634 iterator_->Seek(other->iterator_->Key()); |
1829 DCHECK(iterator_->IsValid()); | 2635 DCHECK(iterator_->IsValid()); |
1830 } | 2636 } |
1831 } | 2637 } |
1832 } | 2638 } |
1833 | 2639 |
1834 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, | 2640 IndexedDBBackingStore::Cursor::Cursor( |
1835 const CursorOptions& cursor_options) | 2641 scoped_refptr<IndexedDBBackingStore> backing_store, |
jsbell
2013/12/18 23:04:40
This is an interesting new arc in the ownership di
ericu
2013/12/19 05:19:11
OK.
| |
1836 : transaction_(transaction), cursor_options_(cursor_options) {} | 2642 LevelDBTransaction* transaction, |
2643 int64 database_id, | |
2644 const CursorOptions& cursor_options) | |
2645 : backing_store_(backing_store), | |
2646 transaction_(transaction), | |
2647 database_id_(database_id), | |
2648 cursor_options_(cursor_options) { | |
2649 } | |
1837 IndexedDBBackingStore::Cursor::~Cursor() {} | 2650 IndexedDBBackingStore::Cursor::~Cursor() {} |
1838 | 2651 |
1839 bool IndexedDBBackingStore::Cursor::FirstSeek() { | 2652 bool IndexedDBBackingStore::Cursor::FirstSeek() { |
1840 iterator_ = transaction_->CreateIterator(); | 2653 iterator_ = transaction_->CreateIterator(); |
1841 if (cursor_options_.forward) | 2654 if (cursor_options_.forward) |
1842 iterator_->Seek(cursor_options_.low_key); | 2655 iterator_->Seek(cursor_options_.low_key); |
1843 else | 2656 else |
1844 iterator_->Seek(cursor_options_.high_key); | 2657 iterator_->Seek(cursor_options_.high_key); |
1845 | 2658 |
1846 return Continue(0, READY); | 2659 return Continue(0, READY); |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2006 } | 2819 } |
2007 | 2820 |
2008 const IndexedDBBackingStore::RecordIdentifier& | 2821 const IndexedDBBackingStore::RecordIdentifier& |
2009 IndexedDBBackingStore::Cursor::record_identifier() const { | 2822 IndexedDBBackingStore::Cursor::record_identifier() const { |
2010 return record_identifier_; | 2823 return record_identifier_; |
2011 } | 2824 } |
2012 | 2825 |
2013 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 2826 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
2014 public: | 2827 public: |
2015 ObjectStoreKeyCursorImpl( | 2828 ObjectStoreKeyCursorImpl( |
2829 scoped_refptr<IndexedDBBackingStore> backing_store, | |
2016 LevelDBTransaction* transaction, | 2830 LevelDBTransaction* transaction, |
2831 int64 database_id, | |
2017 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2832 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
2018 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2833 : IndexedDBBackingStore::Cursor( |
2834 backing_store, transaction, database_id, cursor_options) {} | |
2019 | 2835 |
2020 virtual Cursor* Clone() OVERRIDE { | 2836 virtual Cursor* Clone() OVERRIDE { |
2021 return new ObjectStoreKeyCursorImpl(this); | 2837 return new ObjectStoreKeyCursorImpl(this); |
2022 } | 2838 } |
2023 | 2839 |
2024 // IndexedDBBackingStore::Cursor | 2840 // IndexedDBBackingStore::Cursor |
2025 virtual std::string* Value() OVERRIDE { | 2841 virtual IndexedDBValue* Value() OVERRIDE { |
2026 NOTREACHED(); | 2842 NOTREACHED(); |
2027 return NULL; | 2843 return NULL; |
2028 } | 2844 } |
2029 virtual bool LoadCurrentRow() OVERRIDE; | 2845 virtual bool LoadCurrentRow() OVERRIDE; |
2030 | 2846 |
2031 protected: | 2847 protected: |
2032 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2848 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
2033 return ObjectStoreDataKey::Encode( | 2849 return ObjectStoreDataKey::Encode( |
2034 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2850 cursor_options_.database_id, cursor_options_.object_store_id, key); |
2035 } | 2851 } |
(...skipping 29 matching lines...) Expand all Loading... | |
2065 std::string encoded_key; | 2881 std::string encoded_key; |
2066 EncodeIDBKey(*current_key_, &encoded_key); | 2882 EncodeIDBKey(*current_key_, &encoded_key); |
2067 record_identifier_.Reset(encoded_key, version); | 2883 record_identifier_.Reset(encoded_key, version); |
2068 | 2884 |
2069 return true; | 2885 return true; |
2070 } | 2886 } |
2071 | 2887 |
2072 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { | 2888 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { |
2073 public: | 2889 public: |
2074 ObjectStoreCursorImpl( | 2890 ObjectStoreCursorImpl( |
2891 scoped_refptr<IndexedDBBackingStore> backing_store, | |
2075 LevelDBTransaction* transaction, | 2892 LevelDBTransaction* transaction, |
2893 int64 database_id, | |
2076 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2894 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
2077 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2895 : IndexedDBBackingStore::Cursor( |
2896 backing_store, transaction, database_id, cursor_options) {} | |
2078 | 2897 |
2079 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } | 2898 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } |
2080 | 2899 |
2081 // IndexedDBBackingStore::Cursor | 2900 // IndexedDBBackingStore::Cursor |
2082 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 2901 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } |
2083 virtual bool LoadCurrentRow() OVERRIDE; | 2902 virtual bool LoadCurrentRow() OVERRIDE; |
2084 | 2903 |
2085 protected: | 2904 protected: |
2086 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2905 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
2087 return ObjectStoreDataKey::Encode( | 2906 return ObjectStoreDataKey::Encode( |
2088 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2907 cursor_options_.database_id, cursor_options_.object_store_id, key); |
2089 } | 2908 } |
2090 virtual std::string EncodeKey(const IndexedDBKey& key, | 2909 virtual std::string EncodeKey(const IndexedDBKey& key, |
2091 const IndexedDBKey& primary_key) OVERRIDE { | 2910 const IndexedDBKey& primary_key) OVERRIDE { |
2092 NOTREACHED(); | 2911 NOTREACHED(); |
2093 return std::string(); | 2912 return std::string(); |
2094 } | 2913 } |
2095 | 2914 |
2096 private: | 2915 private: |
2097 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) | 2916 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) |
2098 : IndexedDBBackingStore::Cursor(other), | 2917 : IndexedDBBackingStore::Cursor(other), |
2099 current_value_(other->current_value_) {} | 2918 current_value_(other->current_value_) {} |
2100 | 2919 |
2101 std::string current_value_; | 2920 IndexedDBValue current_value_; |
2102 }; | 2921 }; |
2103 | 2922 |
2104 bool ObjectStoreCursorImpl::LoadCurrentRow() { | 2923 bool ObjectStoreCursorImpl::LoadCurrentRow() { |
2105 StringPiece slice(iterator_->Key()); | 2924 StringPiece key_slice(iterator_->Key()); |
2106 ObjectStoreDataKey object_store_data_key; | 2925 ObjectStoreDataKey object_store_data_key; |
2107 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { | 2926 if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) { |
2108 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 2927 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2109 return false; | 2928 return false; |
2110 } | 2929 } |
2111 | 2930 |
2112 current_key_ = object_store_data_key.user_key(); | 2931 current_key_ = object_store_data_key.user_key(); |
2113 | 2932 |
2114 int64 version; | 2933 int64 version; |
2115 slice = StringPiece(iterator_->Value()); | 2934 StringPiece value_slice = StringPiece(iterator_->Value()); |
2116 if (!DecodeVarInt(&slice, &version)) { | 2935 if (!DecodeVarInt(&value_slice, &version)) { |
2117 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 2936 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2118 return false; | 2937 return false; |
2119 } | 2938 } |
2120 | 2939 |
2121 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. | 2940 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. |
2122 std::string encoded_key; | 2941 std::string encoded_key; |
2123 EncodeIDBKey(*current_key_, &encoded_key); | 2942 EncodeIDBKey(*current_key_, &encoded_key); |
2124 record_identifier_.Reset(encoded_key, version); | 2943 record_identifier_.Reset(encoded_key, version); |
2125 | 2944 |
2126 current_value_ = slice.as_string(); | 2945 if (!GetBlobInfoForRecord(backing_store_, transaction_, database_id_, |
2946 iterator_->Key().as_string(), ¤t_value_)) { | |
2947 return false; | |
2948 } | |
2949 current_value_.bits = value_slice.as_string(); | |
2127 return true; | 2950 return true; |
2128 } | 2951 } |
2129 | 2952 |
2130 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 2953 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
2131 public: | 2954 public: |
2132 IndexKeyCursorImpl( | 2955 IndexKeyCursorImpl( |
2956 scoped_refptr<IndexedDBBackingStore> backing_store, | |
2133 LevelDBTransaction* transaction, | 2957 LevelDBTransaction* transaction, |
2958 int64 database_id, | |
2134 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2959 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
2135 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2960 : IndexedDBBackingStore::Cursor( |
2961 backing_store, transaction, database_id, cursor_options) {} | |
2136 | 2962 |
2137 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } | 2963 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } |
2138 | 2964 |
2139 // IndexedDBBackingStore::Cursor | 2965 // IndexedDBBackingStore::Cursor |
2140 virtual std::string* Value() OVERRIDE { | 2966 virtual IndexedDBValue* Value() OVERRIDE { |
2141 NOTREACHED(); | 2967 NOTREACHED(); |
2142 return NULL; | 2968 return NULL; |
2143 } | 2969 } |
2144 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 2970 virtual const IndexedDBKey& primary_key() const OVERRIDE { |
2145 return *primary_key_; | 2971 return *primary_key_; |
2146 } | 2972 } |
2147 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 2973 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() |
2148 const { | 2974 const OVERRIDE { |
2149 NOTREACHED(); | 2975 NOTREACHED(); |
2150 return record_identifier_; | 2976 return record_identifier_; |
2151 } | 2977 } |
2152 virtual bool LoadCurrentRow() OVERRIDE; | 2978 virtual bool LoadCurrentRow() OVERRIDE; |
2153 | 2979 |
2154 protected: | 2980 protected: |
2155 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2981 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
2156 return IndexDataKey::Encode(cursor_options_.database_id, | 2982 return IndexDataKey::Encode(cursor_options_.database_id, |
2157 cursor_options_.object_store_id, | 2983 cursor_options_.object_store_id, |
2158 cursor_options_.index_id, | 2984 cursor_options_.index_id, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2230 transaction_->Remove(iterator_->Key()); | 3056 transaction_->Remove(iterator_->Key()); |
2231 return false; | 3057 return false; |
2232 } | 3058 } |
2233 | 3059 |
2234 return true; | 3060 return true; |
2235 } | 3061 } |
2236 | 3062 |
2237 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { | 3063 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { |
2238 public: | 3064 public: |
2239 IndexCursorImpl( | 3065 IndexCursorImpl( |
3066 scoped_refptr<IndexedDBBackingStore> backing_store, | |
2240 LevelDBTransaction* transaction, | 3067 LevelDBTransaction* transaction, |
3068 int64 database_id, | |
2241 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 3069 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
2242 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 3070 : IndexedDBBackingStore::Cursor( |
3071 backing_store, transaction, database_id, cursor_options) {} | |
2243 | 3072 |
2244 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } | 3073 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } |
2245 | 3074 |
2246 // IndexedDBBackingStore::Cursor | 3075 // IndexedDBBackingStore::Cursor |
2247 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 3076 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } |
2248 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 3077 virtual const IndexedDBKey& primary_key() const OVERRIDE { |
2249 return *primary_key_; | 3078 return *primary_key_; |
2250 } | 3079 } |
2251 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 3080 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() |
2252 const { | 3081 const OVERRIDE { |
2253 NOTREACHED(); | 3082 NOTREACHED(); |
2254 return record_identifier_; | 3083 return record_identifier_; |
2255 } | 3084 } |
2256 virtual bool LoadCurrentRow() OVERRIDE; | 3085 virtual bool LoadCurrentRow() OVERRIDE; |
2257 | 3086 |
2258 protected: | 3087 protected: |
2259 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 3088 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { |
2260 return IndexDataKey::Encode(cursor_options_.database_id, | 3089 return IndexDataKey::Encode(cursor_options_.database_id, |
2261 cursor_options_.object_store_id, | 3090 cursor_options_.object_store_id, |
2262 cursor_options_.index_id, | 3091 cursor_options_.index_id, |
2263 key); | 3092 key); |
2264 } | 3093 } |
2265 virtual std::string EncodeKey(const IndexedDBKey& key, | 3094 virtual std::string EncodeKey(const IndexedDBKey& key, |
2266 const IndexedDBKey& primary_key) OVERRIDE { | 3095 const IndexedDBKey& primary_key) OVERRIDE { |
2267 return IndexDataKey::Encode(cursor_options_.database_id, | 3096 return IndexDataKey::Encode(cursor_options_.database_id, |
2268 cursor_options_.object_store_id, | 3097 cursor_options_.object_store_id, |
2269 cursor_options_.index_id, | 3098 cursor_options_.index_id, |
2270 key, | 3099 key, |
2271 primary_key); | 3100 primary_key); |
2272 } | 3101 } |
2273 | 3102 |
2274 private: | 3103 private: |
2275 explicit IndexCursorImpl(const IndexCursorImpl* other) | 3104 explicit IndexCursorImpl(const IndexCursorImpl* other) |
2276 : IndexedDBBackingStore::Cursor(other), | 3105 : IndexedDBBackingStore::Cursor(other), |
2277 primary_key_(new IndexedDBKey(*other->primary_key_)), | 3106 primary_key_(new IndexedDBKey(*other->primary_key_)), |
2278 current_value_(other->current_value_), | 3107 current_value_(other->current_value_), |
2279 primary_leveldb_key_(other->primary_leveldb_key_) {} | 3108 primary_leveldb_key_(other->primary_leveldb_key_) {} |
2280 | 3109 |
2281 scoped_ptr<IndexedDBKey> primary_key_; | 3110 scoped_ptr<IndexedDBKey> primary_key_; |
2282 std::string current_value_; | 3111 IndexedDBValue current_value_; |
2283 std::string primary_leveldb_key_; | 3112 std::string primary_leveldb_key_; |
2284 }; | 3113 }; |
2285 | 3114 |
2286 bool IndexCursorImpl::LoadCurrentRow() { | 3115 bool IndexCursorImpl::LoadCurrentRow() { |
2287 StringPiece slice(iterator_->Key()); | 3116 StringPiece slice(iterator_->Key()); |
2288 IndexDataKey index_data_key; | 3117 IndexDataKey index_data_key; |
2289 if (!IndexDataKey::Decode(&slice, &index_data_key)) { | 3118 if (!IndexDataKey::Decode(&slice, &index_data_key)) { |
2290 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3119 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2291 return false; | 3120 return false; |
2292 } | 3121 } |
2293 | 3122 |
2294 current_key_ = index_data_key.user_key(); | 3123 current_key_ = index_data_key.user_key(); |
2295 DCHECK(current_key_); | 3124 DCHECK(current_key_); |
2296 | 3125 |
2297 slice = StringPiece(iterator_->Value()); | 3126 slice = StringPiece(iterator_->Value()); |
2298 int64 index_data_version; | 3127 int64 index_data_version; |
2299 if (!DecodeVarInt(&slice, &index_data_version)) { | 3128 if (!DecodeVarInt(&slice, &index_data_version)) { |
2300 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3129 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2301 return false; | 3130 return false; |
2302 } | 3131 } |
2303 if (!DecodeIDBKey(&slice, &primary_key_)) { | 3132 if (!DecodeIDBKey(&slice, &primary_key_)) { |
2304 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3133 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2305 return false; | 3134 return false; |
2306 } | 3135 } |
2307 | 3136 |
3137 DCHECK_EQ(index_data_key.DatabaseId(), database_id_); | |
2308 primary_leveldb_key_ = | 3138 primary_leveldb_key_ = |
2309 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), | 3139 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), |
2310 index_data_key.ObjectStoreId(), | 3140 index_data_key.ObjectStoreId(), |
2311 *primary_key_); | 3141 *primary_key_); |
2312 | 3142 |
2313 std::string result; | 3143 std::string result; |
2314 bool found = false; | 3144 bool found = false; |
2315 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); | 3145 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); |
2316 if (!ok) { | 3146 if (!ok) { |
2317 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3147 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
(...skipping 13 matching lines...) Expand all Loading... | |
2331 if (!DecodeVarInt(&slice, &object_store_data_version)) { | 3161 if (!DecodeVarInt(&slice, &object_store_data_version)) { |
2332 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3162 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
2333 return false; | 3163 return false; |
2334 } | 3164 } |
2335 | 3165 |
2336 if (object_store_data_version != index_data_version) { | 3166 if (object_store_data_version != index_data_version) { |
2337 transaction_->Remove(iterator_->Key()); | 3167 transaction_->Remove(iterator_->Key()); |
2338 return false; | 3168 return false; |
2339 } | 3169 } |
2340 | 3170 |
2341 current_value_ = slice.as_string(); | 3171 current_value_.bits = slice.as_string(); |
2342 return true; | 3172 return GetBlobInfoForRecord(backing_store_, transaction_, database_id_, |
3173 primary_leveldb_key_, ¤t_value_); | |
2343 } | 3174 } |
2344 | 3175 |
2345 bool ObjectStoreCursorOptions( | 3176 bool ObjectStoreCursorOptions( |
2346 LevelDBTransaction* transaction, | 3177 LevelDBTransaction* transaction, |
2347 int64 database_id, | 3178 int64 database_id, |
2348 int64 object_store_id, | 3179 int64 object_store_id, |
2349 const IndexedDBKeyRange& range, | 3180 const IndexedDBKeyRange& range, |
2350 indexed_db::CursorDirection direction, | 3181 indexed_db::CursorDirection direction, |
2351 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { | 3182 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { |
2352 cursor_options->database_id = database_id; | 3183 cursor_options->database_id = database_id; |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2489 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3320 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
2490 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3321 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
2491 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3322 if (!ObjectStoreCursorOptions(leveldb_transaction, |
2492 database_id, | 3323 database_id, |
2493 object_store_id, | 3324 object_store_id, |
2494 range, | 3325 range, |
2495 direction, | 3326 direction, |
2496 &cursor_options)) | 3327 &cursor_options)) |
2497 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3328 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2498 scoped_ptr<ObjectStoreCursorImpl> cursor( | 3329 scoped_ptr<ObjectStoreCursorImpl> cursor( |
2499 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); | 3330 new ObjectStoreCursorImpl( |
3331 this, leveldb_transaction, database_id, cursor_options)); | |
2500 if (!cursor->FirstSeek()) | 3332 if (!cursor->FirstSeek()) |
2501 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3333 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2502 | 3334 |
2503 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3335 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
2504 } | 3336 } |
2505 | 3337 |
2506 scoped_ptr<IndexedDBBackingStore::Cursor> | 3338 scoped_ptr<IndexedDBBackingStore::Cursor> |
2507 IndexedDBBackingStore::OpenObjectStoreKeyCursor( | 3339 IndexedDBBackingStore::OpenObjectStoreKeyCursor( |
2508 IndexedDBBackingStore::Transaction* transaction, | 3340 IndexedDBBackingStore::Transaction* transaction, |
2509 int64 database_id, | 3341 int64 database_id, |
2510 int64 object_store_id, | 3342 int64 object_store_id, |
2511 const IndexedDBKeyRange& range, | 3343 const IndexedDBKeyRange& range, |
2512 indexed_db::CursorDirection direction) { | 3344 indexed_db::CursorDirection direction) { |
2513 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); | 3345 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); |
2514 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3346 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
2515 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3347 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
2516 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3348 if (!ObjectStoreCursorOptions(leveldb_transaction, |
2517 database_id, | 3349 database_id, |
2518 object_store_id, | 3350 object_store_id, |
2519 range, | 3351 range, |
2520 direction, | 3352 direction, |
2521 &cursor_options)) | 3353 &cursor_options)) |
2522 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3354 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2523 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( | 3355 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( |
2524 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); | 3356 new ObjectStoreKeyCursorImpl( |
3357 this, leveldb_transaction, database_id, cursor_options)); | |
2525 if (!cursor->FirstSeek()) | 3358 if (!cursor->FirstSeek()) |
2526 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3359 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2527 | 3360 |
2528 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3361 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
2529 } | 3362 } |
2530 | 3363 |
2531 scoped_ptr<IndexedDBBackingStore::Cursor> | 3364 scoped_ptr<IndexedDBBackingStore::Cursor> |
2532 IndexedDBBackingStore::OpenIndexKeyCursor( | 3365 IndexedDBBackingStore::OpenIndexKeyCursor( |
2533 IndexedDBBackingStore::Transaction* transaction, | 3366 IndexedDBBackingStore::Transaction* transaction, |
2534 int64 database_id, | 3367 int64 database_id, |
2535 int64 object_store_id, | 3368 int64 object_store_id, |
2536 int64 index_id, | 3369 int64 index_id, |
2537 const IndexedDBKeyRange& range, | 3370 const IndexedDBKeyRange& range, |
2538 indexed_db::CursorDirection direction) { | 3371 indexed_db::CursorDirection direction) { |
2539 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); | 3372 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); |
2540 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3373 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
2541 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3374 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
2542 if (!IndexCursorOptions(leveldb_transaction, | 3375 if (!IndexCursorOptions(leveldb_transaction, |
2543 database_id, | 3376 database_id, |
2544 object_store_id, | 3377 object_store_id, |
2545 index_id, | 3378 index_id, |
2546 range, | 3379 range, |
2547 direction, | 3380 direction, |
2548 &cursor_options)) | 3381 &cursor_options)) |
2549 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3382 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2550 scoped_ptr<IndexKeyCursorImpl> cursor( | 3383 scoped_ptr<IndexKeyCursorImpl> cursor( |
2551 new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); | 3384 new IndexKeyCursorImpl( |
3385 this, leveldb_transaction, database_id, cursor_options)); | |
2552 if (!cursor->FirstSeek()) | 3386 if (!cursor->FirstSeek()) |
2553 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3387 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2554 | 3388 |
2555 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3389 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
2556 } | 3390 } |
2557 | 3391 |
2558 scoped_ptr<IndexedDBBackingStore::Cursor> | 3392 scoped_ptr<IndexedDBBackingStore::Cursor> |
2559 IndexedDBBackingStore::OpenIndexCursor( | 3393 IndexedDBBackingStore::OpenIndexCursor( |
2560 IndexedDBBackingStore::Transaction* transaction, | 3394 IndexedDBBackingStore::Transaction* transaction, |
2561 int64 database_id, | 3395 int64 database_id, |
2562 int64 object_store_id, | 3396 int64 object_store_id, |
2563 int64 index_id, | 3397 int64 index_id, |
2564 const IndexedDBKeyRange& range, | 3398 const IndexedDBKeyRange& range, |
2565 indexed_db::CursorDirection direction) { | 3399 indexed_db::CursorDirection direction) { |
2566 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); | 3400 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); |
2567 LevelDBTransaction* leveldb_transaction = transaction->transaction(); | 3401 LevelDBTransaction* leveldb_transaction = transaction->transaction(); |
2568 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3402 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
2569 if (!IndexCursorOptions(leveldb_transaction, | 3403 if (!IndexCursorOptions(leveldb_transaction, |
2570 database_id, | 3404 database_id, |
2571 object_store_id, | 3405 object_store_id, |
2572 index_id, | 3406 index_id, |
2573 range, | 3407 range, |
2574 direction, | 3408 direction, |
2575 &cursor_options)) | 3409 &cursor_options)) |
2576 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3410 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2577 scoped_ptr<IndexCursorImpl> cursor( | 3411 scoped_ptr<IndexCursorImpl> cursor( |
2578 new IndexCursorImpl(leveldb_transaction, cursor_options)); | 3412 new IndexCursorImpl( |
3413 this, leveldb_transaction, database_id, cursor_options)); | |
2579 if (!cursor->FirstSeek()) | 3414 if (!cursor->FirstSeek()) |
2580 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3415 return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
2581 | 3416 |
2582 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3417 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
2583 } | 3418 } |
2584 | 3419 |
2585 IndexedDBBackingStore::Transaction::Transaction( | 3420 IndexedDBBackingStore::Transaction::Transaction( |
2586 IndexedDBBackingStore* backing_store) | 3421 IndexedDBBackingStore* backing_store) |
2587 : backing_store_(backing_store) {} | 3422 : backing_store_(backing_store), |
3423 database_id_(-1) { | |
3424 } | |
2588 | 3425 |
2589 IndexedDBBackingStore::Transaction::~Transaction() {} | 3426 IndexedDBBackingStore::Transaction::~Transaction() { |
3427 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
3428 for (; iter != blob_change_map_.end(); ++iter) { | |
3429 delete iter->second; | |
3430 } | |
3431 } | |
2590 | 3432 |
2591 void IndexedDBBackingStore::Transaction::Begin() { | 3433 void IndexedDBBackingStore::Transaction::Begin() { |
2592 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); | 3434 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); |
2593 DCHECK(!transaction_.get()); | 3435 DCHECK(!transaction_.get()); |
2594 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); | 3436 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); |
2595 } | 3437 } |
2596 | 3438 |
2597 bool IndexedDBBackingStore::Transaction::Commit() { | 3439 static GURL getURLFromUUID(const string& uuid) { |
2598 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3440 return GURL("blob:uuid/" + uuid); |
2599 DCHECK(transaction_.get()); | 3441 } |
3442 | |
3443 void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetBlobInfo( | |
3444 std::vector<IndexedDBBlobInfo>* blob_info) { | |
3445 blob_info_.clear(); | |
3446 if (blob_info) | |
3447 blob_info_.swap(*blob_info); | |
3448 } | |
3449 | |
3450 void IndexedDBBackingStore::Transaction::BlobChangeRecord::SetHandles( | |
3451 ScopedVector<webkit_blob::BlobDataHandle>* handles) { | |
3452 handles_.clear(); | |
3453 if (handles) | |
3454 handles_.swap(*handles); | |
3455 } | |
3456 | |
3457 bool IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( | |
3458 BlobEntryKeyValuePairVec* new_blob_entries, | |
3459 WriteDescriptorVec* new_files_to_write) { | |
3460 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
3461 new_blob_entries->clear(); | |
3462 new_files_to_write->clear(); | |
3463 if (iter != blob_change_map_.end()) { | |
3464 // Create LevelDBTransaction for the name generator seed and add-journal. | |
3465 scoped_refptr<LevelDBTransaction> pre_transaction = | |
3466 new LevelDBTransaction(backing_store_->db_.get()); | |
3467 BlobJournalType journal; | |
3468 for (; iter != blob_change_map_.end(); ++iter) { | |
3469 std::vector<IndexedDBBlobInfo>::iterator info_iter; | |
3470 std::vector<IndexedDBBlobInfo*> new_blob_keys; | |
3471 for (info_iter = iter->second->mutable_blob_info().begin(); | |
3472 info_iter != iter->second->mutable_blob_info().end(); ++info_iter) { | |
3473 int64 next_blob_key = -1; | |
3474 bool result = GetBlobKeyGeneratorCurrentNumber( | |
3475 pre_transaction.get(), database_id_, next_blob_key); | |
3476 if (!result || next_blob_key < 0) | |
3477 return false; | |
3478 BlobJournalEntryType journal_entry = | |
3479 std::make_pair(database_id_, next_blob_key); | |
3480 journal.push_back(journal_entry); | |
3481 if (info_iter->is_file()) { | |
3482 new_files_to_write->push_back( | |
3483 WriteDescriptor(info_iter->file_path(), next_blob_key)); | |
3484 } else { | |
3485 new_files_to_write->push_back( | |
3486 WriteDescriptor( | |
3487 getURLFromUUID(info_iter->uuid()), next_blob_key)); | |
3488 } | |
3489 info_iter->set_key(next_blob_key); | |
3490 new_blob_keys.push_back(&*info_iter); | |
3491 result = UpdateBlobKeyGeneratorCurrentNumber( | |
3492 pre_transaction.get(), database_id_, next_blob_key + 1); | |
3493 if (!result) | |
3494 return result; | |
3495 } | |
3496 BlobEntryKey blob_entry_key; | |
3497 StringPiece key_piece(iter->second->key()); | |
3498 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
3499 NOTREACHED(); | |
3500 return false; | |
3501 } | |
3502 new_blob_entries->push_back(std::make_pair(blob_entry_key, | |
3503 EncodeBlobData(new_blob_keys))); | |
3504 } | |
3505 UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal); | |
3506 if (!pre_transaction->Commit()) | |
3507 return false; | |
3508 } | |
3509 return true; | |
3510 } | |
3511 | |
3512 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { | |
3513 BlobChangeMap::iterator iter = blob_change_map_.begin(); | |
3514 // Look up all old files to remove as part of the transaction, store their | |
3515 // names in blobs_to_remove_, and remove their old blob data entries. | |
3516 if (iter != blob_change_map_.end()) { | |
3517 scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator(); | |
3518 for (; iter != blob_change_map_.end(); ++iter) { | |
3519 BlobEntryKey blob_entry_key; | |
3520 StringPiece key_piece(iter->second->key()); | |
3521 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
3522 NOTREACHED(); | |
3523 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
3524 transaction_ = NULL; | |
3525 return false; | |
3526 } | |
3527 if (database_id_ < 0) | |
3528 database_id_ = blob_entry_key.database_id(); | |
3529 else | |
3530 DCHECK_EQ(database_id_, blob_entry_key.database_id()); | |
3531 std::string blob_entry_key_bytes = blob_entry_key.Encode(); | |
3532 db_iter->Seek(blob_entry_key_bytes); | |
3533 if (db_iter->IsValid() && | |
3534 !CompareKeys(db_iter->Key(), blob_entry_key_bytes)) { | |
3535 std::vector<IndexedDBBlobInfo> blob_info; | |
3536 if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) { | |
3537 INTERNAL_READ_ERROR(TRANSACTION_COMMIT_METHOD); | |
3538 transaction_ = NULL; | |
3539 return false; | |
3540 } | |
3541 std::vector<IndexedDBBlobInfo>::iterator blob_info_iter; | |
3542 for (blob_info_iter = blob_info.begin(); | |
3543 blob_info_iter != blob_info.end(); ++blob_info_iter) | |
3544 blobs_to_remove_.push_back( | |
3545 std::make_pair(database_id_, blob_info_iter->key())); | |
3546 transaction_->Remove(blob_entry_key_bytes); | |
3547 } | |
3548 } | |
3549 } | |
3550 return true; | |
3551 } | |
3552 | |
3553 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper : | |
3554 public IndexedDBBackingStore::BlobWriteCallback { | |
3555 public: | |
3556 BlobWriteCallbackWrapper( | |
3557 IndexedDBBackingStore::Transaction* transaction, | |
3558 scoped_refptr<BlobWriteCallback> callback) | |
3559 : transaction_(transaction), | |
3560 callback_(callback) { | |
3561 } | |
3562 virtual void didSucceed() { | |
3563 callback_->didSucceed(); | |
3564 transaction_->chained_blob_writer_ = NULL; | |
3565 } | |
3566 virtual void didFail() { | |
3567 callback_->didFail(); | |
3568 transaction_->chained_blob_writer_ = NULL; | |
3569 } | |
3570 private: | |
3571 IndexedDBBackingStore::Transaction* transaction_; | |
3572 scoped_refptr<BlobWriteCallback> callback_; | |
3573 }; | |
3574 | |
3575 void IndexedDBBackingStore::Transaction::WriteNewBlobs( | |
3576 BlobEntryKeyValuePairVec& new_blob_entries, | |
3577 WriteDescriptorVec& new_files_to_write, | |
3578 scoped_refptr<BlobWriteCallback> callback) { | |
3579 DCHECK_GT(new_files_to_write.size(), 0UL); | |
3580 DCHECK_GT(database_id_, 0); | |
3581 BlobEntryKeyValuePairVec::iterator blob_entry_iter; | |
3582 for (blob_entry_iter = new_blob_entries.begin(); | |
3583 blob_entry_iter != new_blob_entries.end(); ++blob_entry_iter) { | |
3584 // Add the new blob-table entry for each blob to the main transaction, or | |
3585 // remove any entry that may exist if there's no new one. | |
3586 if (!blob_entry_iter->second.size()) | |
3587 transaction_->Remove(blob_entry_iter->first.Encode()); | |
3588 else | |
3589 transaction_->Put(blob_entry_iter->first.Encode(), | |
3590 &blob_entry_iter->second); | |
3591 } | |
3592 // Creating the writer will start it going asynchronously. | |
3593 chained_blob_writer_ = new ChainedBlobWriterImpl(database_id_, backing_store_, | |
3594 new_files_to_write, new BlobWriteCallbackWrapper(this, callback)); | |
3595 } | |
3596 | |
3597 bool IndexedDBBackingStore::Transaction::SortBlobsToRemove() { | |
3598 IndexedDBActiveBlobRegistry* registry = | |
3599 backing_store_->active_blob_registry(); | |
3600 BlobJournalType::iterator iter; | |
3601 BlobJournalType primary_journal, live_blob_journal; | |
3602 for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end(); | |
3603 ++iter) { | |
3604 if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second)) | |
3605 live_blob_journal.push_back(*iter); | |
3606 else | |
3607 primary_journal.push_back(*iter); | |
3608 } | |
3609 UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal); | |
3610 if (!MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal)) | |
3611 return false; | |
3612 // To signal how many blobs need attention right now. | |
3613 blobs_to_remove_.swap(primary_journal); | |
3614 return true; | |
3615 } | |
3616 | |
3617 bool IndexedDBBackingStore::Transaction::CommitPhaseOne( | |
3618 scoped_refptr<BlobWriteCallback> callback) { | |
3619 IDB_TRACE("IndexedDBBackingStore::Transaction::commit"); | |
3620 DCHECK(transaction_); | |
3621 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); | |
3622 | |
3623 if (!backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode())) { | |
3624 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
3625 transaction_ = NULL; | |
3626 return false; | |
3627 } | |
3628 | |
3629 BlobEntryKeyValuePairVec new_blob_entries; | |
3630 WriteDescriptorVec new_files_to_write; | |
3631 // This commits the journal of blob files we're about to add, if any. | |
3632 if (!HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write)) { | |
3633 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
3634 transaction_ = NULL; | |
3635 return false; | |
3636 } | |
3637 | |
3638 DCHECK(!new_files_to_write.size() || | |
3639 KeyPrefix::IsValidDatabaseId(database_id_)); | |
3640 if (!CollectBlobFilesToRemove()) { | |
3641 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
3642 transaction_ = NULL; | |
3643 return false; | |
3644 } | |
3645 | |
3646 if (new_files_to_write.size()) { | |
3647 // This kicks off the writes of the new blobs, if any. | |
3648 // This call will zero out new_blob_entries and new_files_to_write. | |
3649 WriteNewBlobs(new_blob_entries, new_files_to_write, callback); | |
3650 // Remove the add journal, if any; once the blobs are written, and we | |
3651 // commit, this will do the cleanup. | |
3652 ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode()); | |
3653 } else { | |
3654 callback->didSucceed(); | |
3655 } | |
3656 | |
3657 return true; | |
3658 } | |
3659 | |
3660 bool IndexedDBBackingStore::Transaction::CommitPhaseTwo() { | |
3661 if (blobs_to_remove_.size()) | |
3662 if (!SortBlobsToRemove()) { | |
3663 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
3664 transaction_ = NULL; | |
3665 return false; | |
3666 } | |
3667 | |
2600 bool result = transaction_->Commit(); | 3668 bool result = transaction_->Commit(); |
2601 transaction_ = NULL; | 3669 transaction_ = NULL; |
3670 | |
2602 if (!result) | 3671 if (!result) |
2603 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | 3672 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); |
3673 else if (blobs_to_remove_.size()) | |
3674 backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); | |
3675 | |
2604 return result; | 3676 return result; |
2605 } | 3677 } |
2606 | 3678 |
2607 void IndexedDBBackingStore::Transaction::Rollback() { | 3679 void IndexedDBBackingStore::Transaction::Rollback() { |
2608 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3680 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); |
2609 DCHECK(transaction_.get()); | 3681 DCHECK(transaction_.get()); |
3682 if (chained_blob_writer_) { | |
3683 chained_blob_writer_->Abort(); | |
3684 chained_blob_writer_ = NULL; | |
3685 } | |
2610 transaction_->Rollback(); | 3686 transaction_->Rollback(); |
2611 transaction_ = NULL; | 3687 transaction_ = NULL; |
2612 } | 3688 } |
2613 | 3689 |
3690 // This is storing an info, even if empty, even if the previous key had no blob | |
3691 // info that we know of. It duplicates a bunch of information stored in the | |
3692 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the | |
3693 // changes to exists or index keys here. | |
3694 void IndexedDBBackingStore::Transaction::PutBlobInfo( | |
3695 int64 database_id, | |
3696 int64 object_store_id, | |
3697 const std::string& key, | |
3698 std::vector<IndexedDBBlobInfo>* blob_info, | |
3699 ScopedVector<webkit_blob::BlobDataHandle>* handles) { | |
3700 DCHECK_GT(key.size(), 0UL); | |
3701 if (database_id_ < 0) | |
3702 database_id_ = database_id; | |
3703 DCHECK_EQ(database_id_, database_id); | |
3704 | |
3705 BlobChangeMap::iterator it = blob_change_map_.find(key); | |
3706 BlobChangeRecord *record = NULL; | |
3707 if (it == blob_change_map_.end()) { | |
3708 record = new BlobChangeRecord(); | |
3709 blob_change_map_[key] = record; | |
3710 record->set_key(key); | |
3711 record->set_object_store_id(object_store_id); | |
3712 } else { | |
3713 record = it->second; | |
3714 } | |
3715 DCHECK_EQ(record->object_store_id(), object_store_id); | |
3716 record->SetBlobInfo(blob_info); | |
3717 record->SetHandles(handles); | |
3718 DCHECK(!handles || !handles->size()); | |
3719 } | |
3720 | |
3721 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
3722 const GURL& url, int64_t key) | |
3723 : is_file_(false), | |
3724 url_(url), | |
3725 key_(key) | |
3726 { | |
3727 } | |
3728 | |
3729 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
3730 const FilePath& file_path, int64_t key) | |
3731 : is_file_(true), | |
3732 file_path_(file_path), | |
3733 key_(key) | |
3734 { | |
3735 } | |
3736 | |
2614 } // namespace content | 3737 } // namespace content |
OLD | NEW |