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

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

Powered by Google App Engine
This is Rietveld 408576698