Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: content/browser/indexed_db/indexed_db_backing_store.cc

Issue 18023022: Blob support for IDB [Chromium] (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use ScopedVector and stl_utils for BlobDataHandles. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 &current_value_; } 2901 virtual IndexedDBValue* Value() OVERRIDE { return &current_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(), &current_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
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 &current_value_; } 3076 virtual IndexedDBValue* Value() OVERRIDE { return &current_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
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_, &current_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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698