 Chromium Code Reviews
 Chromium Code Reviews Issue 18023022:
  Blob support for IDB [Chromium]  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 18023022:
  Blob support for IDB [Chromium]  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" | 
| 6 | 6 | 
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" | 
| 8 #include "base/logging.h" | 8 #include "base/logging.h" | 
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" | 
| 10 #include "base/strings/string_piece.h" | 10 #include "base/strings/string_piece.h" | 
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" | 
| 12 #include "base/strings/stringprintf.h" | |
| 12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" | 
| 14 #include "content/browser/child_process_security_policy_impl.h" | |
| 15 #include "content/browser/indexed_db/indexed_db_blob_info.h" | |
| 13 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 16 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 
| 14 #include "content/browser/indexed_db/indexed_db_metadata.h" | 17 #include "content/browser/indexed_db/indexed_db_metadata.h" | 
| 15 #include "content/browser/indexed_db/indexed_db_tracing.h" | 18 #include "content/browser/indexed_db/indexed_db_tracing.h" | 
| 19 #include "content/browser/indexed_db/indexed_db_value.h" | |
| 16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 20 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" | 
| 17 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 21 #include "content/browser/indexed_db/leveldb/leveldb_database.h" | 
| 18 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 22 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" | 
| 19 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 23 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" | 
| 20 #include "content/common/indexed_db/indexed_db_key.h" | 24 #include "content/common/indexed_db/indexed_db_key.h" | 
| 21 #include "content/common/indexed_db/indexed_db_key_path.h" | 25 #include "content/common/indexed_db/indexed_db_key_path.h" | 
| 22 #include "content/common/indexed_db/indexed_db_key_range.h" | 26 #include "content/common/indexed_db/indexed_db_key_range.h" | 
| 27 #include "content/public/browser/browser_thread.h" | |
| 28 #include "net/url_request/url_request_context.h" | |
| 23 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 29 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 
| 24 #include "third_party/leveldatabase/env_chromium.h" | 30 #include "third_party/leveldatabase/env_chromium.h" | 
| 31 #include "webkit/browser/fileapi/file_writer_delegate.h" | |
| 32 #include "webkit/browser/fileapi/local_file_stream_writer.h" | |
| 25 | 33 | 
| 34 using base::FilePath; | |
| 26 using base::StringPiece; | 35 using base::StringPiece; | 
| 36 using fileapi::FileWriterDelegate; | |
| 27 | 37 | 
| 28 // TODO(jsbell): Make blink push the version during the open() call. | 38 // TODO(jsbell): Make blink push the version during the open() call. | 
| 29 static const uint32 kWireVersion = 2; | 39 static const uint32 kWireVersion = 2; | 
| 30 | 40 | 
| 31 namespace content { | 41 namespace content { | 
| 32 | 42 | 
| 43 namespace { | |
| 44 | |
| 45 FilePath GetIDBBlobDirectoryName(const FilePath& pathBase, | |
| 46 int64 database_id) { | |
| 47 return pathBase.AppendASCII(base::StringPrintf("%lx", database_id)); | |
| 48 } | |
| 49 | |
| 50 FilePath GetIDBBlobDirectoryNameForKey(const FilePath& pathBase, | |
| 51 int64 database_id, int64 key) { | |
| 52 FilePath path = GetIDBBlobDirectoryName(pathBase, database_id); | |
| 53 path = path.AppendASCII( | |
| 54 base::StringPrintf("%x", static_cast<int>(key & 0x0000ff00) >> 8)); | |
| 55 return path; | |
| 56 } | |
| 57 | |
| 58 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
| 59 bool MakeIDBBlobDirectory( | |
| 60 const FilePath& pathBase, int64 database_id, int64 key) { | |
| 61 FilePath path = | |
| 62 GetIDBBlobDirectoryNameForKey(pathBase, database_id, key); | |
| 63 return file_util::CreateDirectory(path); | |
| 64 } | |
| 65 | |
| 66 } // anonymous namespace | |
| 67 | |
| 33 static const int64 kKeyGeneratorInitialNumber = | 68 static const int64 kKeyGeneratorInitialNumber = | 
| 34 1; // From the IndexedDB specification. | 69 1; // From the IndexedDB specification. | 
| 35 | 70 | 
| 36 enum IndexedDBBackingStoreErrorSource { | 71 enum IndexedDBBackingStoreErrorSource { | 
| 37 // 0 - 2 are no longer used. | 72 // 0 - 2 are no longer used. | 
| 38 FIND_KEY_IN_INDEX = 3, | 73 FIND_KEY_IN_INDEX = 3, | 
| 39 GET_IDBDATABASE_METADATA, | 74 GET_IDBDATABASE_METADATA, | 
| 40 GET_INDEXES, | 75 GET_INDEXES, | 
| 41 GET_KEY_GENERATOR_CURRENT_NUMBER, | 76 GET_KEY_GENERATOR_CURRENT_NUMBER, | 
| 42 GET_OBJECT_STORES, | 77 GET_OBJECT_STORES, | 
| 43 GET_RECORD, | 78 GET_RECORD, | 
| 44 KEY_EXISTS_IN_OBJECT_STORE, | 79 KEY_EXISTS_IN_OBJECT_STORE, | 
| 45 LOAD_CURRENT_ROW, | 80 LOAD_CURRENT_ROW, | 
| 46 SET_UP_METADATA, | 81 SET_UP_METADATA, | 
| 47 GET_PRIMARY_KEY_VIA_INDEX, | 82 GET_PRIMARY_KEY_VIA_INDEX, | 
| 48 KEY_EXISTS_IN_INDEX, | 83 KEY_EXISTS_IN_INDEX, | 
| 49 VERSION_EXISTS, | 84 VERSION_EXISTS, | 
| 50 DELETE_OBJECT_STORE, | 85 DELETE_OBJECT_STORE, | 
| 51 SET_MAX_OBJECT_STORE_ID, | 86 SET_MAX_OBJECT_STORE_ID, | 
| 52 SET_MAX_INDEX_ID, | 87 SET_MAX_INDEX_ID, | 
| 53 GET_NEW_DATABASE_ID, | 88 GET_NEW_DATABASE_ID, | 
| 54 GET_NEW_VERSION_NUMBER, | 89 GET_NEW_VERSION_NUMBER, | 
| 55 CREATE_IDBDATABASE_METADATA, | 90 CREATE_IDBDATABASE_METADATA, | 
| 56 DELETE_DATABASE, | 91 DELETE_DATABASE, | 
| 57 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro | 92 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro | 
| 93 GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER, | |
| 94 GET_BLOB_INFO_FOR_RECORD, | |
| 95 DECODE_BLOB_JOURNAL, | |
| 58 GET_DATABASE_NAMES, | 96 GET_DATABASE_NAMES, | 
| 59 INTERNAL_ERROR_MAX, | 97 INTERNAL_ERROR_MAX, | 
| 60 }; | 98 }; | 
| 61 | 99 | 
| 62 static void RecordInternalError(const char* type, | 100 static void RecordInternalError(const char* type, | 
| 63 IndexedDBBackingStoreErrorSource location) { | 101 IndexedDBBackingStoreErrorSource location) { | 
| 64 std::string name; | 102 std::string name; | 
| 65 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 103 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); | 
| 66 base::Histogram::FactoryGet(name, | 104 base::Histogram::FactoryGet(name, | 
| 67 1, | 105 1, | 
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 } | 385 } | 
| 348 | 386 | 
| 349 class DefaultLevelDBFactory : public LevelDBFactory { | 387 class DefaultLevelDBFactory : public LevelDBFactory { | 
| 350 public: | 388 public: | 
| 351 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, | 389 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, | 
| 352 const LevelDBComparator* comparator, | 390 const LevelDBComparator* comparator, | 
| 353 scoped_ptr<LevelDBDatabase>* db, | 391 scoped_ptr<LevelDBDatabase>* db, | 
| 354 bool* is_disk_full) OVERRIDE { | 392 bool* is_disk_full) OVERRIDE { | 
| 355 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 393 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | 
| 356 } | 394 } | 
| 357 virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { | 395 virtual bool DestroyLevelDB(const FilePath& file_name) OVERRIDE { | 
| 358 return LevelDBDatabase::Destroy(file_name); | 396 return LevelDBDatabase::Destroy(file_name); | 
| 359 } | 397 } | 
| 360 }; | 398 }; | 
| 361 | 399 | 
| 400 static bool GetBlobKeyGeneratorCurrentNumber( | |
| 401 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
| 402 int64& blob_key_generator_current_number) { | |
| 403 const std::string key_gen_key = | |
| 404 DatabaseMetaDataKey::Encode( | |
| 405 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 406 | |
| 407 // Default to initial number if not found. | |
| 408 int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber; | |
| 409 std::string data; | |
| 410 | |
| 411 bool found = false; | |
| 412 bool ok = leveldb_transaction->Get(key_gen_key, &data, &found); | |
| 413 if (!ok) { | |
| 414 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 415 return false; | |
| 416 } | |
| 417 if (found) { | |
| 418 StringPiece slice(data); | |
| 419 if (!DecodeVarInt(&slice, &cur_number) || | |
| 420 !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) { | |
| 421 INTERNAL_READ_ERROR(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 422 return false; | |
| 423 } | |
| 424 } | |
| 425 blob_key_generator_current_number = cur_number; | |
| 426 return true; | |
| 427 } | |
| 428 | |
| 429 static bool UpdateBlobKeyGeneratorCurrentNumber( | |
| 430 LevelDBTransaction* leveldb_transaction, int64 database_id, | |
| 431 int64 blob_key_generator_current_number) { | |
| 432 #ifndef NDEBUG | |
| 433 int64 old_number; | |
| 434 if (!GetBlobKeyGeneratorCurrentNumber(leveldb_transaction, database_id, | |
| 435 old_number)) | |
| 436 return false; | |
| 437 DCHECK_LT(old_number, blob_key_generator_current_number); | |
| 438 #endif | |
| 439 DCHECK(DatabaseMetaDataKey::IsValidBlobKey( | |
| 440 blob_key_generator_current_number)); | |
| 441 const std::string key = | |
| 442 DatabaseMetaDataKey::Encode( | |
| 443 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); | |
| 444 | |
| 445 PutInt(leveldb_transaction, key, blob_key_generator_current_number); | |
| 446 return true; | |
| 447 } | |
| 448 | |
| 449 static bool DecodeBlobJournal(const std::string& data, | |
| 450 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 451 // TODO(ericu): Yell something on errors. If we persistently can't read the | |
| 452 // blob journal, the safe thing to do is to clear it and leak the blobs, | |
| 453 // though that may be costly. Still, database/directory deletion should always | |
| 454 // clean things up, and we can write an fsck that will do a full correction if | |
| 455 // need be. | |
| 456 IndexedDBBackingStore::Transaction::BlobJournalType output; | |
| 457 StringPiece slice(data); | |
| 458 while (!slice.empty()) { | |
| 459 int64 database_id = -1; | |
| 460 int64 blob_key = -1; | |
| 461 if (!DecodeVarInt(&slice, &database_id)) | |
| 462 return false; | |
| 463 else if (!KeyPrefix::IsValidDatabaseId(database_id)) | |
| 464 return false; | |
| 465 if (!DecodeVarInt(&slice, &blob_key)) { | |
| 466 return false; | |
| 467 } else if (!DatabaseMetaDataKey::IsValidBlobKey(blob_key) && | |
| 468 (blob_key != DatabaseMetaDataKey::kAllBlobsKey)) { | |
| 469 return false; | |
| 470 } | |
| 471 output.push_back(std::make_pair(database_id, blob_key)); | |
| 472 } | |
| 473 journal.swap(output); | |
| 474 return true; | |
| 475 } | |
| 476 | |
| 477 static bool GetBlobJournalHelper( | |
| 478 bool ok, bool found, | |
| 479 const std::string& data, | |
| 480 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 481 if (!ok) { | |
| 482 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); | |
| 483 return false; | |
| 484 } | |
| 485 journal.clear(); | |
| 486 if (!found) | |
| 487 return true; | |
| 488 if (!data.size()) | |
| 489 return true; | |
| 490 if (!DecodeBlobJournal(data, journal)) { | |
| 491 INTERNAL_READ_ERROR(DECODE_BLOB_JOURNAL); | |
| 492 return false; | |
| 493 } | |
| 494 return true; | |
| 495 } | |
| 496 | |
| 497 static bool GetBlobJournal( | |
| 498 const StringPiece& leveldb_key, | |
| 499 LevelDBTransaction* 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 return GetBlobJournalHelper(ok, found, data, journal); | |
| 505 } | |
| 506 | |
| 507 static bool GetBlobJournal( | |
| 508 const StringPiece& leveldb_key, | |
| 509 LevelDBWriteOnlyTransaction* leveldb_transaction, | |
| 510 IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 511 std::string data; | |
| 512 bool found = false; | |
| 513 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); | |
| 514 return GetBlobJournalHelper(ok, found, data, journal); | |
| 515 } | |
| 516 | |
| 517 static std::string EncodeBlobJournalWithBlobList( | |
| 518 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 519 std::string data; | |
| 520 if (journal.size()) { | |
| 521 IndexedDBBackingStore::Transaction::BlobJournalType::const_iterator iter; | |
| 522 for (iter = journal.begin(); iter != journal.end(); ++iter) { | |
| 523 EncodeVarInt(iter->first, &data); | |
| 524 EncodeVarInt(iter->second, &data); | |
| 525 } | |
| 526 } | |
| 527 return data; | |
| 528 } | |
| 529 | |
| 530 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, | |
| 531 const std::string& level_db_key) { | |
| 532 leveldb_transaction->Remove(level_db_key); | |
| 533 } | |
| 534 | |
| 535 static void UpdatePrimaryJournalWithBlobList( | |
| 536 LevelDBTransaction* leveldb_transaction, | |
| 537 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 538 const std::string leveldbKey = BlobJournalKey::Encode(); | |
| 539 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 540 leveldb_transaction->Put(leveldbKey, &data); | |
| 541 } | |
| 542 | |
| 543 static void UpdateSecondaryJournalWithBlobList( | |
| 544 LevelDBTransaction* leveldb_transaction, | |
| 545 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 546 const std::string leveldbKey = LiveBlobJournalKey::Encode(); | |
| 547 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 548 leveldb_transaction->Put(leveldbKey, &data); | |
| 549 } | |
| 550 | |
| 551 static bool MergeBlobsIntoSecondaryJournal( | |
| 552 LevelDBTransaction* leveldb_transaction, | |
| 553 const IndexedDBBackingStore::Transaction::BlobJournalType& journal) { | |
| 554 IndexedDBBackingStore::Transaction::BlobJournalType old_journal; | |
| 555 std::string key = LiveBlobJournalKey::Encode(); | |
| 556 if (!GetBlobJournal(key, leveldb_transaction, old_journal)) | |
| 557 return false; | |
| 558 | |
| 559 fprintf(stderr, "ERICU: Secondary: old %lu entries, new %lu entries.\n", | |
| 560 old_journal.size(), journal.size()); | |
| 561 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); | |
| 562 fprintf(stderr, "ERICU: final %lu entries.\n", old_journal.size()); | |
| 563 | |
| 564 UpdateSecondaryJournalWithBlobList(leveldb_transaction, old_journal); | |
| 565 return true; | |
| 566 } | |
| 567 | |
| 568 static void UpdateBlobJournalWithDatabase( | |
| 569 LevelDBWriteOnlyTransaction* leveldb_transaction, int64 database_id) { | |
| 570 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
| 571 journal.push_back( | |
| 572 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 573 const std::string key = BlobJournalKey::Encode(); | |
| 574 std::string data = EncodeBlobJournalWithBlobList(journal); | |
| 575 leveldb_transaction->Put(key, &data); | |
| 576 } | |
| 577 | |
| 578 static bool MergeDatabaseIntoSecondaryJournal( | |
| 579 LevelDBWriteOnlyTransaction* leveldb_transaction, 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 = EncodeBlobJournalWithBlobList(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( | |
| 612 const std::string& data, | |
| 613 std::vector<IndexedDBBlobInfo>* output) { | |
| 614 std::vector<IndexedDBBlobInfo> ret; | |
| 615 output->clear(); | |
| 616 StringPiece slice(data); | |
| 617 while (!slice.empty()) { | |
| 618 bool is_file; | |
| 619 int64 key; | |
| 620 string16 type; | |
| 621 int64 size; | |
| 622 string16 file_name; | |
| 623 | |
| 624 if (!DecodeBool(&slice, &is_file)) | |
| 625 return false; | |
| 626 if (!DecodeVarInt(&slice, &key) || | |
| 627 !DatabaseMetaDataKey::IsValidBlobKey(key)) | |
| 628 return false; | |
| 629 if (!DecodeStringWithLength(&slice, &type)) | |
| 630 return false; | |
| 631 if (is_file) { | |
| 632 if (!DecodeStringWithLength(&slice, &file_name)) | |
| 633 return false; | |
| 634 ret.push_back(IndexedDBBlobInfo(type, file_name, key)); | |
| 635 } else { | |
| 636 if (!DecodeVarInt(&slice, &size) || size < 0) | |
| 637 return false; | |
| 638 ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key)); | |
| 639 } | |
| 640 } | |
| 641 output->swap(ret); | |
| 642 | |
| 643 return true; | |
| 644 } | |
| 645 | |
| 362 IndexedDBBackingStore::IndexedDBBackingStore( | 646 IndexedDBBackingStore::IndexedDBBackingStore( | 
| 363 const std::string& identifier, | 647 const std::string& identifier, | 
| 648 const FilePath& blob_path, | |
| 649 net::URLRequestContext* request_context, | |
| 364 scoped_ptr<LevelDBDatabase> db, | 650 scoped_ptr<LevelDBDatabase> db, | 
| 365 scoped_ptr<LevelDBComparator> comparator) | 651 scoped_ptr<LevelDBComparator> comparator, | 
| 652 base::TaskRunner* task_runner) | |
| 366 : identifier_(identifier), | 653 : identifier_(identifier), | 
| 654 blob_path_(blob_path), | |
| 655 request_context_(request_context), | |
| 656 task_runner_(task_runner), | |
| 367 db_(db.Pass()), | 657 db_(db.Pass()), | 
| 368 comparator_(comparator.Pass()), | 658 comparator_(comparator.Pass()), | 
| 369 weak_factory_(this) {} | 659 active_blob_registry_(this), | 
| 660 weak_factory_(this) { | |
| 661 } | |
| 370 | 662 | 
| 371 IndexedDBBackingStore::~IndexedDBBackingStore() { | 663 IndexedDBBackingStore::~IndexedDBBackingStore() { | 
| 664 if (!blob_path_.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(); ++iter) { | |
| 669 policy->RevokeAllPermissionsForFile(*iter, blob_path_); | |
| 670 } | |
| 671 } | |
| 372 // db_'s destructor uses comparator_. The order of destruction is important. | 672 // db_'s destructor uses comparator_. The order of destruction is important. | 
| 373 db_.reset(); | 673 db_.reset(); | 
| 374 comparator_.reset(); | 674 comparator_.reset(); | 
| 375 } | 675 } | 
| 376 | 676 | 
| 377 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( | 677 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( | 
| 378 const std::string& primary_key, | 678 const std::string& primary_key, | 
| 379 int64 version) | 679 int64 version) | 
| 380 : primary_key_(primary_key), version_(version) { | 680 : primary_key_(primary_key), version_(version) { | 
| 381 DCHECK(!primary_key.empty()); | 681 DCHECK(!primary_key.empty()); | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 435 } | 735 } | 
| 436 } | 736 } | 
| 437 default: | 737 default: | 
| 438 return true; | 738 return true; | 
| 439 } | 739 } | 
| 440 return true; | 740 return true; | 
| 441 } | 741 } | 
| 442 | 742 | 
| 443 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 743 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 
| 444 const std::string& origin_identifier, | 744 const std::string& origin_identifier, | 
| 445 const base::FilePath& path_base, | 745 const FilePath& path_base, | 
| 446 const std::string& file_identifier, | 746 const std::string& file_identifier, | 
| 447 WebKit::WebIDBCallbacks::DataLoss* data_loss) { | 747 net::URLRequestContext* request_context, | 
| 748 WebKit::WebIDBCallbacks::DataLoss* data_loss, | |
| 749 base::TaskRunner* task_runner, | |
| 750 bool clean_journal) { | |
| 448 *data_loss = WebKit::WebIDBCallbacks::DataLossNone; | 751 *data_loss = WebKit::WebIDBCallbacks::DataLossNone; | 
| 449 DefaultLevelDBFactory leveldb_factory; | 752 DefaultLevelDBFactory leveldb_factory; | 
| 450 return IndexedDBBackingStore::Open(origin_identifier, | 753 return IndexedDBBackingStore::Open(origin_identifier, | 
| 451 path_base, | 754 path_base, | 
| 452 file_identifier, | 755 file_identifier, | 
| 756 request_context, | |
| 453 data_loss, | 757 data_loss, | 
| 454 &leveldb_factory); | 758 &leveldb_factory, | 
| 759 task_runner, | |
| 760 clean_journal); | |
| 455 } | 761 } | 
| 456 | 762 | 
| 457 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 763 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( | 
| 458 const std::string& origin_identifier, | 764 const std::string& origin_identifier, | 
| 459 const base::FilePath& path_base, | 765 const FilePath& path_base, | 
| 460 const std::string& file_identifier, | 766 const std::string& file_identifier, | 
| 767 net::URLRequestContext* request_context, | |
| 461 WebKit::WebIDBCallbacks::DataLoss* data_loss, | 768 WebKit::WebIDBCallbacks::DataLoss* data_loss, | 
| 462 LevelDBFactory* leveldb_factory) { | 769 LevelDBFactory* leveldb_factory, | 
| 770 base::TaskRunner* task_runner, | |
| 771 bool clean_journal) { | |
| 463 IDB_TRACE("IndexedDBBackingStore::Open"); | 772 IDB_TRACE("IndexedDBBackingStore::Open"); | 
| 464 DCHECK(!path_base.empty()); | 773 DCHECK(!path_base.empty()); | 
| 465 *data_loss = WebKit::WebIDBCallbacks::DataLossNone; | 774 *data_loss = WebKit::WebIDBCallbacks::DataLossNone; | 
| 466 | 775 | 
| 467 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 776 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | 
| 468 | 777 | 
| 469 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { | 778 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { | 
| 470 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 779 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 
| 471 1, | 780 1, | 
| 472 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 781 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 
| 473 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 782 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 
| 474 base::HistogramBase::kUmaTargetedHistogramFlag) | 783 base::HistogramBase::kUmaTargetedHistogramFlag) | 
| 475 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII); | 784 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII); | 
| 476 } | 785 } | 
| 477 if (!file_util::CreateDirectory(path_base)) { | 786 if (!file_util::CreateDirectory(path_base)) { | 
| 478 LOG(ERROR) << "Unable to create IndexedDB database path " | 787 LOG(ERROR) << "Unable to create IndexedDB database path " | 
| 479 << path_base.AsUTF8Unsafe(); | 788 << path_base.AsUTF8Unsafe(); | 
| 480 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 789 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 
| 481 1, | 790 1, | 
| 482 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 791 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 
| 483 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 792 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 
| 484 base::HistogramBase::kUmaTargetedHistogramFlag) | 793 base::HistogramBase::kUmaTargetedHistogramFlag) | 
| 485 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY); | 794 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY); | 
| 486 return scoped_refptr<IndexedDBBackingStore>(); | 795 return scoped_refptr<IndexedDBBackingStore>(); | 
| 487 } | 796 } | 
| 488 | 797 | 
| 489 base::FilePath identifier_path = | 798 base::FilePath db_dir_name = | 
| 490 base::FilePath().AppendASCII(origin_identifier) | 799 FilePath().AppendASCII(origin_identifier). | 
| 491 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 800 AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); | 
| 801 base::FilePath blob_dir_name = | |
| 802 FilePath().AppendASCII(origin_identifier). | |
| 803 AddExtension(FILE_PATH_LITERAL(".indexeddb.blob")); | |
| 492 | 804 | 
| 493 int limit = file_util::GetMaximumPathComponentLength(path_base); | 805 int limit = file_util::GetMaximumPathComponentLength(path_base); | 
| 494 if (limit == -1) { | 806 if (limit == -1) { | 
| 495 DLOG(WARNING) << "GetMaximumPathComponentLength returned -1"; | 807 DLOG(WARNING) << "GetMaximumPathComponentLength returned -1"; | 
| 496 // In limited testing, ChromeOS returns 143, other OSes 255. | 808 // In limited testing, ChromeOS returns 143, other OSes 255. | 
| 497 #if defined(OS_CHROMEOS) | 809 #if defined(OS_CHROMEOS) | 
| 498 limit = 143; | 810 limit = 143; | 
| 499 #else | 811 #else | 
| 500 limit = 255; | 812 limit = 255; | 
| 501 #endif | 813 #endif | 
| 502 } | 814 } | 
| 503 if (identifier_path.value().length() > static_cast<uint32_t>(limit)) { | 815 if (db_dir_name.value().length() > static_cast<uint32_t>(limit)) { | 
| 504 DLOG(WARNING) << "Path component length (" | 816 DLOG(WARNING) << "Path component length (" | 
| 505 << identifier_path.value().length() << ") exceeds maximum (" | 817 << db_dir_name.value().length() << ") exceeds maximum (" | 
| 506 << limit << ") allowed by this filesystem."; | 818 << limit << ") allowed by this filesystem."; | 
| 507 const int min = 140; | 819 const int min = 140; | 
| 508 const int max = 300; | 820 const int max = 300; | 
| 509 const int num_buckets = 12; | 821 const int num_buckets = 12; | 
| 510 // TODO(dgrogan): Remove WebCore from these histogram names. | 822 // TODO(dgrogan): Remove WebCore from these histogram names. | 
| 511 UMA_HISTOGRAM_CUSTOM_COUNTS( | 823 UMA_HISTOGRAM_CUSTOM_COUNTS( | 
| 512 "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength", | 824 "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength", | 
| 513 identifier_path.value().length(), | 825 db_dir_name.value().length(), | 
| 514 min, | 826 min, | 
| 515 max, | 827 max, | 
| 516 num_buckets); | 828 num_buckets); | 
| 517 // TODO(dgrogan): Translate the FactoryGet calls to | 829 // TODO(dgrogan): Translate the FactoryGet calls to | 
| 518 // UMA_HISTOGRAM_ENUMERATION. FactoryGet was the most direct translation | 830 // UMA_HISTOGRAM_ENUMERATION. FactoryGet was the most direct translation | 
| 519 // from the WebCore code. | 831 // from the WebCore code. | 
| 520 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 832 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 
| 521 1, | 833 1, | 
| 522 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 834 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 
| 523 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 835 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 
| 524 base::HistogramBase::kUmaTargetedHistogramFlag) | 836 base::HistogramBase::kUmaTargetedHistogramFlag) | 
| 525 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG); | 837 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG); | 
| 526 return scoped_refptr<IndexedDBBackingStore>(); | 838 return scoped_refptr<IndexedDBBackingStore>(); | 
| 527 } | 839 } | 
| 528 | 840 | 
| 529 base::FilePath file_path = path_base.Append(identifier_path); | 841 FilePath file_path = path_base.Append(db_dir_name); | 
| 842 FilePath blob_path = path_base.Append(blob_dir_name); | |
| 530 | 843 | 
| 531 bool is_disk_full = false; | 844 bool is_disk_full = false; | 
| 532 scoped_ptr<LevelDBDatabase> db; | 845 scoped_ptr<LevelDBDatabase> db; | 
| 533 leveldb::Status status = leveldb_factory->OpenLevelDB( | 846 leveldb::Status status = leveldb_factory->OpenLevelDB( | 
| 534 file_path, comparator.get(), &db, &is_disk_full); | 847 file_path, comparator.get(), &db, &is_disk_full); | 
| 535 | 848 | 
| 536 if (db) { | 849 if (db) { | 
| 537 bool known = false; | 850 bool known = false; | 
| 538 bool ok = IsSchemaKnown(db.get(), &known); | 851 bool ok = IsSchemaKnown(db.get(), &known); | 
| 539 if (!ok) { | 852 if (!ok) { | 
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 NOTREACHED(); | 941 NOTREACHED(); | 
| 629 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 942 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 
| 630 1, | 943 1, | 
| 631 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 944 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 
| 632 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 945 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 
| 633 base::HistogramBase::kUmaTargetedHistogramFlag) | 946 base::HistogramBase::kUmaTargetedHistogramFlag) | 
| 634 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR); | 947 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR); | 
| 635 return scoped_refptr<IndexedDBBackingStore>(); | 948 return scoped_refptr<IndexedDBBackingStore>(); | 
| 636 } | 949 } | 
| 637 | 950 | 
| 638 return Create(file_identifier, db.Pass(), comparator.Pass()); | 951 scoped_refptr<IndexedDBBackingStore> backing_store = Create( | 
| 952 file_identifier, blob_path, request_context, db.Pass(), comparator.Pass(), | |
| 953 task_runner); | |
| 954 | |
| 955 if (clean_journal) | |
| 956 fprintf(stderr, "ERICU: first open of DB since boot.\n"); | |
| 957 if (clean_journal && !backing_store->CleanUpBlobJournal( | |
| 958 LiveBlobJournalKey::Encode())) | |
| 959 return scoped_refptr<IndexedDBBackingStore>(); | |
| 960 return backing_store; | |
| 639 } | 961 } | 
| 640 | 962 | 
| 641 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 963 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 
| 642 const std::string& file_identifier) { | 964 const std::string& file_identifier) { | 
| 643 DefaultLevelDBFactory leveldb_factory; | 965 DefaultLevelDBFactory leveldb_factory; | 
| 644 return IndexedDBBackingStore::OpenInMemory(file_identifier, &leveldb_factory); | 966 return IndexedDBBackingStore::OpenInMemory(file_identifier, &leveldb_factory); | 
| 645 } | 967 } | 
| 646 | 968 | 
| 647 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 969 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( | 
| 648 const std::string& file_identifier, | 970 const std::string& file_identifier, | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 662 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED); | 984 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED); | 
| 663 return scoped_refptr<IndexedDBBackingStore>(); | 985 return scoped_refptr<IndexedDBBackingStore>(); | 
| 664 } | 986 } | 
| 665 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 987 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", | 
| 666 1, | 988 1, | 
| 667 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 989 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, | 
| 668 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 990 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, | 
| 669 base::HistogramBase::kUmaTargetedHistogramFlag) | 991 base::HistogramBase::kUmaTargetedHistogramFlag) | 
| 670 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS); | 992 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS); | 
| 671 | 993 | 
| 672 return Create(file_identifier, db.Pass(), comparator.Pass()); | 994 return Create(file_identifier, FilePath(), NULL, db.Pass(), | 
| 995 comparator.Pass(), NULL); | |
| 673 } | 996 } | 
| 674 | 997 | 
| 675 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 998 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( | 
| 676 const std::string& identifier, | 999 const std::string& identifier, | 
| 1000 const FilePath& blob_path, | |
| 1001 net::URLRequestContext* request_context, | |
| 677 scoped_ptr<LevelDBDatabase> db, | 1002 scoped_ptr<LevelDBDatabase> db, | 
| 678 scoped_ptr<LevelDBComparator> comparator) { | 1003 scoped_ptr<LevelDBComparator> comparator, | 
| 1004 base::TaskRunner* task_runner) { | |
| 679 // TODO(jsbell): Handle comparator name changes. | 1005 // TODO(jsbell): Handle comparator name changes. | 
| 680 scoped_refptr<IndexedDBBackingStore> backing_store( | 1006 scoped_refptr<IndexedDBBackingStore> backing_store( | 
| 681 new IndexedDBBackingStore(identifier, db.Pass(), comparator.Pass())); | 1007 new IndexedDBBackingStore(identifier, blob_path, request_context, | 
| 1008 db.Pass(), comparator.Pass(), task_runner)); | |
| 682 | 1009 | 
| 683 if (!SetUpMetadata(backing_store->db_.get(), identifier)) | 1010 if (!SetUpMetadata(backing_store->db_.get(), identifier)) | 
| 684 return scoped_refptr<IndexedDBBackingStore>(); | 1011 return scoped_refptr<IndexedDBBackingStore>(); | 
| 685 | 1012 | 
| 686 return backing_store; | 1013 return backing_store; | 
| 687 } | 1014 } | 
| 688 | 1015 | 
| 1016 void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) { | |
| 1017 if (!child_process_ids_granted_.count(child_process_id)) { | |
| 1018 child_process_ids_granted_.insert(child_process_id); | |
| 1019 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadDirectory( | |
| 1020 child_process_id, blob_path_); | |
| 1021 } | |
| 1022 } | |
| 1023 | |
| 689 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { | 1024 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { | 
| 690 std::vector<string16> found_names; | 1025 std::vector<string16> found_names; | 
| 691 const std::string start_key = | 1026 const std::string start_key = | 
| 692 DatabaseNameKey::EncodeMinKeyForOrigin(identifier_); | 1027 DatabaseNameKey::EncodeMinKeyForOrigin(identifier_); | 
| 693 const std::string stop_key = | 1028 const std::string stop_key = | 
| 694 DatabaseNameKey::EncodeStopKeyForOrigin(identifier_); | 1029 DatabaseNameKey::EncodeStopKeyForOrigin(identifier_); | 
| 695 | 1030 | 
| 696 DCHECK(found_names.empty()); | 1031 DCHECK(found_names.empty()); | 
| 697 | 1032 | 
| 698 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1033 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) | 1091 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) | 
| 757 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | 1092 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; | 
| 758 | 1093 | 
| 759 ok = GetMaxObjectStoreId( | 1094 ok = GetMaxObjectStoreId( | 
| 760 db_.get(), metadata->id, &metadata->max_object_store_id); | 1095 db_.get(), metadata->id, &metadata->max_object_store_id); | 
| 761 if (!ok) { | 1096 if (!ok) { | 
| 762 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | 1097 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | 
| 763 return false; | 1098 return false; | 
| 764 } | 1099 } | 
| 765 | 1100 | 
| 1101 int64 blob_key_generator_current_number = | |
| 1102 DatabaseMetaDataKey::kInvalidBlobKey; | |
| 1103 | |
| 1104 ok = GetVarInt(db_.get(), | |
| 1105 DatabaseMetaDataKey::Encode( | |
| 1106 metadata->id, | |
| 1107 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
| 1108 &blob_key_generator_current_number, | |
| 1109 found); | |
| 1110 if (!ok) { | |
| 1111 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); | |
| 1112 return false; | |
| 1113 } | |
| 1114 if (!*found || | |
| 1115 !DatabaseMetaDataKey::IsValidBlobKey(blob_key_generator_current_number)) { | |
| 1116 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
| 1117 // TODO(ericu): If BLOB_KEY_GENERATOR_CURRENT_NUMBER isn't present, | |
| 1118 // initialize it to kBlobKeyGeneratorInitialNumber. We may also want to | |
| 1119 // verify that this object store predates blob support, or that there | |
| 1120 // aren't any blobs on disk. | |
| 1121 // This would be a read-modify-write, so we'd need a transaction, | |
| 1122 // and to double-check. It might just be easier to write it lazily | |
| 1123 // when we first try to increment it. | |
| 1124 return false; | |
| 1125 } | |
| 1126 | |
| 766 return true; | 1127 return true; | 
| 767 } | 1128 } | 
| 768 | 1129 | 
| 769 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBDatabase* db, | 1130 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBDatabase* db, | 
| 770 int64* new_id) { | 1131 int64* new_id) { | 
| 771 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db); | 1132 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db); | 
| 772 | 1133 | 
| 773 *new_id = -1; | 1134 *new_id = -1; | 
| 774 int64 max_database_id = -1; | 1135 int64 max_database_id = -1; | 
| 775 bool found = false; | 1136 bool found = false; | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 811 PutInt( | 1172 PutInt( | 
| 812 transaction.get(), DatabaseNameKey::Encode(identifier_, name), *row_id); | 1173 transaction.get(), DatabaseNameKey::Encode(identifier_, name), *row_id); | 
| 813 PutString( | 1174 PutString( | 
| 814 transaction.get(), | 1175 transaction.get(), | 
| 815 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), | 1176 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), | 
| 816 version); | 1177 version); | 
| 817 PutVarInt(transaction.get(), | 1178 PutVarInt(transaction.get(), | 
| 818 DatabaseMetaDataKey::Encode(*row_id, | 1179 DatabaseMetaDataKey::Encode(*row_id, | 
| 819 DatabaseMetaDataKey::USER_INT_VERSION), | 1180 DatabaseMetaDataKey::USER_INT_VERSION), | 
| 820 int_version); | 1181 int_version); | 
| 1182 PutVarInt( | |
| 1183 transaction.get(), | |
| 1184 DatabaseMetaDataKey::Encode(*row_id, | |
| 1185 DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), | |
| 1186 DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber); | |
| 821 if (!transaction->Commit()) { | 1187 if (!transaction->Commit()) { | 
| 822 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); | 1188 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); | 
| 823 return false; | 1189 return false; | 
| 824 } | 1190 } | 
| 825 return true; | 1191 return true; | 
| 826 } | 1192 } | 
| 827 | 1193 | 
| 828 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( | 1194 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( | 
| 829 IndexedDBBackingStore::Transaction* transaction, | 1195 IndexedDBBackingStore::Transaction* transaction, | 
| 830 int64 row_id, | 1196 int64 row_id, | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 843 IndexedDBBackingStore::Transaction* transaction, | 1209 IndexedDBBackingStore::Transaction* transaction, | 
| 844 int64 row_id, | 1210 int64 row_id, | 
| 845 const string16& version) { | 1211 const string16& version) { | 
| 846 PutString( | 1212 PutString( | 
| 847 Transaction::LevelDBTransactionFrom(transaction), | 1213 Transaction::LevelDBTransactionFrom(transaction), | 
| 848 DatabaseMetaDataKey::Encode(row_id, DatabaseMetaDataKey::USER_VERSION), | 1214 DatabaseMetaDataKey::Encode(row_id, DatabaseMetaDataKey::USER_VERSION), | 
| 849 version); | 1215 version); | 
| 850 return true; | 1216 return true; | 
| 851 } | 1217 } | 
| 852 | 1218 | 
| 853 static void DeleteRange(LevelDBTransaction* transaction, | 1219 // Note that if you're deleting a range that contains user keys that have blob | 
| 854 const std::string& begin, | 1220 // info, this won't clean up the blobs. | 
| 855 const std::string& end) { | 1221 static void DeleteRangeHelper(LevelDBTransaction* transaction, | 
| 1222 const std::string& begin, | |
| 1223 const std::string& end) { | |
| 856 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); | 1224 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); | 
| 857 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; | 1225 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; | 
| 858 it->Next()) | 1226 it->Next()) | 
| 859 transaction->Remove(it->Key()); | 1227 transaction->Remove(it->Key()); | 
| 860 } | 1228 } | 
| 861 | 1229 | 
| 1230 // For a whole-object-store deletion, we still use the one-blob-record-at-a-time | |
| 1231 // deletion mechanism designed for normal transactions. We could go with the | |
| 1232 // nuke-the-whole-directory method used for deleteDatabase, but that would | |
| 1233 // complicate the kind of info we store in the LevelDBTransaction. | |
| 1234 static void DeleteBlobsInObjectStore( | |
| 1235 IndexedDBBackingStore::Transaction* transaction, | |
| 1236 int64 database_id, int64 object_store_id) { | |
| 1237 fprintf(stderr, "ERICU: DeleteBlobsInObjectStore.\n"); | |
| 1238 std::string start_key, end_key; | |
| 1239 start_key = | |
| 1240 BlobEntryKey::EncodeMinForObjectStore(database_id, object_store_id); | |
| 1241 end_key = | |
| 1242 BlobEntryKey::EncodeMaxForObjectStore(database_id, object_store_id); | |
| 1243 | |
| 1244 scoped_ptr<LevelDBIterator> it = | |
| 1245 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom( | |
| 1246 transaction)->CreateIterator(); | |
| 1247 for (it->Seek(start_key); | |
| 1248 it->IsValid() && CompareKeys(it->Key(), end_key) < 0; it->Next()) { | |
| 1249 StringPiece key_piece(it->Key()); | |
| 1250 std::string user_key = BlobEntryKey::EncodeToObjectStoreDataKey(&key_piece); | |
| 1251 if (user_key.size()) | |
| 1252 transaction->PutBlobInfo(database_id, object_store_id, user_key, NULL); | |
| 1253 else | |
| 1254 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 1258 static bool GetBlobInfoForRecord( | |
| 1259 IndexedDBBackingStore* backing_store, | |
| 1260 LevelDBTransaction* leveldb_transaction, | |
| 1261 int64 database_id, | |
| 1262 const std::string& leveldb_key, | |
| 1263 IndexedDBValue* value) { | |
| 1264 | |
| 1265 BlobEntryKey blob_entry_key; | |
| 1266 StringPiece leveldb_key_piece(leveldb_key); | |
| 1267 if (!BlobEntryKey::FromObjectStoreDataKey( | |
| 1268 &leveldb_key_piece, &blob_entry_key)) { | |
| 1269 NOTREACHED(); | |
| 1270 return false; | |
| 1271 } | |
| 1272 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); | |
| 1273 std::string encoded_key = blob_entry_key.Encode(); | |
| 1274 it->Seek(encoded_key); | |
| 1275 if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) { | |
| 1276 if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) { | |
| 1277 INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD); | |
| 1278 return false; | |
| 1279 } | |
| 1280 std::vector<IndexedDBBlobInfo>::iterator iter; | |
| 1281 for (iter = value->blob_info.begin(); iter != value->blob_info.end(); | |
| 1282 ++iter) { | |
| 1283 iter->set_file_path( | |
| 1284 backing_store->GetIDBBlobFileName(database_id, iter->key())); | |
| 1285 iter->set_mark_used_callback( | |
| 1286 backing_store->active_blob_registry()->GetMarkUsedCallback( | |
| 1287 database_id, iter->key())); | |
| 1288 iter->set_release_callback( | |
| 1289 backing_store->active_blob_registry()->GetReleaseCallback( | |
| 1290 database_id, iter->key())); | |
| 1291 if (iter->is_file()) { | |
| 1292 base::PlatformFileInfo info; | |
| 1293 if (file_util::GetFileInfo(iter->file_path(), &info)) { | |
| 1294 // This should always work, but it isn't fatal if it doesn't; it just | |
| 1295 // means a potential slow synchronous call from the renderer later. | |
| 1296 iter->set_last_modified(info.last_modified); | |
| 1297 iter->set_size(info.size); | |
| 1298 } | |
| 1299 } | |
| 1300 } | |
| 1301 } | |
| 1302 return true; | |
| 1303 } | |
| 1304 | |
| 862 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { | 1305 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { | 
| 863 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); | 1306 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); | 
| 864 scoped_ptr<LevelDBWriteOnlyTransaction> transaction = | 1307 scoped_ptr<LevelDBWriteOnlyTransaction> transaction = | 
| 865 LevelDBWriteOnlyTransaction::Create(db_.get()); | 1308 LevelDBWriteOnlyTransaction::Create(db_.get()); | 
| 866 | 1309 | 
| 1310 if (!CleanUpBlobJournal(BlobJournalKey::Encode())) | |
| 1311 return false; | |
| 1312 | |
| 867 IndexedDBDatabaseMetadata metadata; | 1313 IndexedDBDatabaseMetadata metadata; | 
| 868 bool success = false; | 1314 bool success = false; | 
| 869 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); | 1315 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); | 
| 870 if (!ok) | 1316 if (!ok) | 
| 871 return false; | 1317 return false; | 
| 872 if (!success) | 1318 if (!success) | 
| 873 return true; | 1319 return true; | 
| 874 | 1320 | 
| 875 const std::string start_key = DatabaseMetaDataKey::Encode( | 1321 const std::string start_key = DatabaseMetaDataKey::Encode( | 
| 876 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); | 1322 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); | 
| 877 const std::string stop_key = DatabaseMetaDataKey::Encode( | 1323 const std::string stop_key = DatabaseMetaDataKey::Encode( | 
| 878 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); | 1324 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); | 
| 879 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 1325 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); | 
| 880 for (it->Seek(start_key); | 1326 for (it->Seek(start_key); | 
| 881 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 1327 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; | 
| 882 it->Next()) | 1328 it->Next()) | 
| 883 transaction->Remove(it->Key()); | 1329 transaction->Remove(it->Key()); | 
| 884 | 1330 | 
| 885 const std::string key = DatabaseNameKey::Encode(identifier_, name); | 1331 const std::string key = DatabaseNameKey::Encode(identifier_, name); | 
| 886 transaction->Remove(key); | 1332 transaction->Remove(key); | 
| 887 | 1333 | 
| 1334 bool need_cleanup = false; | |
| 1335 if (active_blob_registry()->MarkDeletedCheckIfUsed( | |
| 1336 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { | |
| 1337 if (!MergeDatabaseIntoSecondaryJournal(transaction.get(), metadata.id)) | |
| 1338 return false; | |
| 1339 } else { | |
| 1340 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); | |
| 1341 need_cleanup = true; | |
| 1342 } | |
| 1343 | |
| 888 if (!transaction->Commit()) { | 1344 if (!transaction->Commit()) { | 
| 889 INTERNAL_WRITE_ERROR(DELETE_DATABASE); | 1345 INTERNAL_WRITE_ERROR(DELETE_DATABASE); | 
| 890 return false; | 1346 return false; | 
| 891 } | 1347 } | 
| 1348 | |
| 1349 if (need_cleanup) | |
| 1350 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 1351 | |
| 892 return true; | 1352 return true; | 
| 893 } | 1353 } | 
| 894 | 1354 | 
| 895 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 1355 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, | 
| 896 const std::string& stop_key, | 1356 const std::string& stop_key, | 
| 897 int64 object_store_id, | 1357 int64 object_store_id, | 
| 898 int64 meta_data_type) { | 1358 int64 meta_data_type) { | 
| 899 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 1359 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 
| 900 return false; | 1360 return false; | 
| 901 | 1361 | 
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 974 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1434 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 
| 975 break; | 1435 break; | 
| 976 } | 1436 } | 
| 977 bool auto_increment; | 1437 bool auto_increment; | 
| 978 { | 1438 { | 
| 979 StringPiece slice(it->Value()); | 1439 StringPiece slice(it->Value()); | 
| 980 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) | 1440 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) | 
| 981 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1441 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 
| 982 } | 1442 } | 
| 983 | 1443 | 
| 984 it->Next(); // Is evicatble. | 1444 it->Next(); // Is evictable. | 
| 985 if (!CheckObjectStoreAndMetaDataType(it.get(), | 1445 if (!CheckObjectStoreAndMetaDataType(it.get(), | 
| 986 stop_key, | 1446 stop_key, | 
| 987 object_store_id, | 1447 object_store_id, | 
| 988 ObjectStoreMetaDataKey::EVICTABLE)) { | 1448 ObjectStoreMetaDataKey::EVICTABLE)) { | 
| 989 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 1449 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); | 
| 990 break; | 1450 break; | 
| 991 } | 1451 } | 
| 992 | 1452 | 
| 993 it->Next(); // Last version. | 1453 it->Next(); // Last version. | 
| 994 if (!CheckObjectStoreAndMetaDataType( | 1454 if (!CheckObjectStoreAndMetaDataType( | 
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1163 &found); | 1623 &found); | 
| 1164 if (!ok) { | 1624 if (!ok) { | 
| 1165 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); | 1625 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); | 
| 1166 return false; | 1626 return false; | 
| 1167 } | 1627 } | 
| 1168 if (!found) { | 1628 if (!found) { | 
| 1169 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); | 1629 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); | 
| 1170 return false; | 1630 return false; | 
| 1171 } | 1631 } | 
| 1172 | 1632 | 
| 1173 DeleteRange( | 1633 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); | 
| 1634 DeleteRangeHelper( | |
| 1174 leveldb_transaction, | 1635 leveldb_transaction, | 
| 1175 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), | 1636 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), | 
| 1176 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1637 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 
| 1177 | 1638 | 
| 1178 leveldb_transaction->Remove( | 1639 leveldb_transaction->Remove( | 
| 1179 ObjectStoreNamesKey::Encode(database_id, object_store_name)); | 1640 ObjectStoreNamesKey::Encode(database_id, object_store_name)); | 
| 1180 | 1641 | 
| 1181 DeleteRange(leveldb_transaction, | 1642 DeleteRangeHelper( | 
| 1182 IndexFreeListKey::Encode(database_id, object_store_id, 0), | 1643 leveldb_transaction, | 
| 1183 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); | 1644 IndexFreeListKey::Encode(database_id, object_store_id, 0), | 
| 1184 DeleteRange(leveldb_transaction, | 1645 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); | 
| 1185 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | 1646 DeleteRangeHelper( | 
| 1186 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | 1647 leveldb_transaction, | 
| 1648 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), | |
| 1649 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); | |
| 1187 | 1650 | 
| 1188 return ClearObjectStore(transaction, database_id, object_store_id); | 1651 return ClearObjectStore(transaction, database_id, object_store_id); | 
| 1189 } | 1652 } | 
| 1190 | 1653 | 
| 1191 bool IndexedDBBackingStore::GetRecord( | 1654 bool IndexedDBBackingStore::GetRecord( | 
| 1192 IndexedDBBackingStore::Transaction* transaction, | 1655 IndexedDBBackingStore::Transaction* transaction, | 
| 1193 int64 database_id, | 1656 int64 database_id, | 
| 1194 int64 object_store_id, | 1657 int64 object_store_id, | 
| 1195 const IndexedDBKey& key, | 1658 const IndexedDBKey& key, | 
| 1196 std::string* record) { | 1659 IndexedDBValue* record) { | 
| 1197 IDB_TRACE("IndexedDBBackingStore::GetRecord"); | 1660 IDB_TRACE("IndexedDBBackingStore::GetRecord"); | 
| 1198 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1661 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 
| 1199 return false; | 1662 return false; | 
| 1200 LevelDBTransaction* leveldb_transaction = | 1663 LevelDBTransaction* leveldb_transaction = | 
| 1201 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 1664 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1202 | 1665 | 
| 1203 const std::string leveldb_key = | 1666 const std::string leveldb_key = | 
| 1204 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1667 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 
| 1205 std::string data; | 1668 std::string data; | 
| 1206 | 1669 | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1219 return false; | 1682 return false; | 
| 1220 } | 1683 } | 
| 1221 | 1684 | 
| 1222 int64 version; | 1685 int64 version; | 
| 1223 StringPiece slice(data); | 1686 StringPiece slice(data); | 
| 1224 if (!DecodeVarInt(&slice, &version)) { | 1687 if (!DecodeVarInt(&slice, &version)) { | 
| 1225 INTERNAL_READ_ERROR(GET_RECORD); | 1688 INTERNAL_READ_ERROR(GET_RECORD); | 
| 1226 return false; | 1689 return false; | 
| 1227 } | 1690 } | 
| 1228 | 1691 | 
| 1229 *record = slice.as_string(); | 1692 record->bits = slice.as_string(); | 
| 1230 return true; | 1693 return GetBlobInfoForRecord( | 
| 1694 this, leveldb_transaction, database_id, leveldb_key, record); | |
| 1231 } | 1695 } | 
| 1232 | 1696 | 
| 1233 WARN_UNUSED_RESULT static bool GetNewVersionNumber( | 1697 WARN_UNUSED_RESULT static bool GetNewVersionNumber( | 
| 1234 LevelDBTransaction* transaction, | 1698 LevelDBTransaction* transaction, | 
| 1235 int64 database_id, | 1699 int64 database_id, | 
| 1236 int64 object_store_id, | 1700 int64 object_store_id, | 
| 1237 int64* new_version_number) { | 1701 int64* new_version_number) { | 
| 1238 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( | 1702 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( | 
| 1239 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); | 1703 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); | 
| 1240 | 1704 | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1259 | 1723 | 
| 1260 *new_version_number = version; | 1724 *new_version_number = version; | 
| 1261 return true; | 1725 return true; | 
| 1262 } | 1726 } | 
| 1263 | 1727 | 
| 1264 bool IndexedDBBackingStore::PutRecord( | 1728 bool IndexedDBBackingStore::PutRecord( | 
| 1265 IndexedDBBackingStore::Transaction* transaction, | 1729 IndexedDBBackingStore::Transaction* transaction, | 
| 1266 int64 database_id, | 1730 int64 database_id, | 
| 1267 int64 object_store_id, | 1731 int64 object_store_id, | 
| 1268 const IndexedDBKey& key, | 1732 const IndexedDBKey& key, | 
| 1269 const std::string& value, | 1733 IndexedDBValue& value, | 
| 1270 RecordIdentifier* record_identifier) { | 1734 RecordIdentifier* record_identifier) { | 
| 1271 IDB_TRACE("IndexedDBBackingStore::PutRecord"); | 1735 IDB_TRACE("IndexedDBBackingStore::PutRecord"); | 
| 1736 fprintf(stderr, "ERICU: PutRecord.\n"); | |
| 1272 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1737 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 
| 1273 return false; | 1738 return false; | 
| 1274 DCHECK(key.IsValid()); | 1739 DCHECK(key.IsValid()); | 
| 1275 | 1740 | 
| 1276 LevelDBTransaction* leveldb_transaction = | 1741 LevelDBTransaction* leveldb_transaction = | 
| 1277 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 1742 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1278 int64 version = -1; | 1743 int64 version = -1; | 
| 1279 bool ok = GetNewVersionNumber( | 1744 bool ok = GetNewVersionNumber( | 
| 1280 leveldb_transaction, database_id, object_store_id, &version); | 1745 leveldb_transaction, database_id, object_store_id, &version); | 
| 1281 if (!ok) | 1746 if (!ok) | 
| 1282 return false; | 1747 return false; | 
| 1283 DCHECK_GE(version, 0); | 1748 DCHECK_GE(version, 0); | 
| 1284 const std::string object_storedata_key = | 1749 const std::string object_store_data_key = | 
| 1285 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 1750 ObjectStoreDataKey::Encode(database_id, object_store_id, key); | 
| 1286 | 1751 | 
| 1287 std::string v; | 1752 std::string v; | 
| 1288 EncodeVarInt(version, &v); | 1753 EncodeVarInt(version, &v); | 
| 1289 v.append(value); | 1754 v.append(value.bits); | 
| 1290 | 1755 | 
| 1291 leveldb_transaction->Put(object_storedata_key, &v); | 1756 leveldb_transaction->Put(object_store_data_key, &v); | 
| 1757 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
| 1758 &value.blob_info); | |
| 1292 | 1759 | 
| 1293 const std::string exists_entry_key = | 1760 const std::string exists_entry_key = | 
| 1294 ExistsEntryKey::Encode(database_id, object_store_id, key); | 1761 ExistsEntryKey::Encode(database_id, object_store_id, key); | 
| 1295 std::string version_encoded; | 1762 std::string version_encoded; | 
| 1296 EncodeInt(version, &version_encoded); | 1763 EncodeInt(version, &version_encoded); | 
| 1297 leveldb_transaction->Put(exists_entry_key, &version_encoded); | 1764 leveldb_transaction->Put(exists_entry_key, &version_encoded); | 
| 1298 | 1765 | 
| 1299 std::string key_encoded; | 1766 std::string key_encoded; | 
| 1300 EncodeIDBKey(key, &key_encoded); | 1767 EncodeIDBKey(key, &key_encoded); | 
| 1301 record_identifier->Reset(key_encoded, version); | 1768 record_identifier->Reset(key_encoded, version); | 
| 1302 return true; | 1769 return true; | 
| 1303 } | 1770 } | 
| 1304 | 1771 | 
| 1305 bool IndexedDBBackingStore::ClearObjectStore( | 1772 bool IndexedDBBackingStore::ClearObjectStore( | 
| 1306 IndexedDBBackingStore::Transaction* transaction, | 1773 IndexedDBBackingStore::Transaction* transaction, | 
| 1307 int64 database_id, | 1774 int64 database_id, | 
| 1308 int64 object_store_id) { | 1775 int64 object_store_id) { | 
| 1309 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); | 1776 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); | 
| 1310 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1777 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 
| 1311 return false; | 1778 return false; | 
| 1312 LevelDBTransaction* leveldb_transaction = | 1779 LevelDBTransaction* leveldb_transaction = | 
| 1313 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 1780 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1314 const std::string start_key = | 1781 const std::string start_key = | 
| 1315 KeyPrefix(database_id, object_store_id).Encode(); | 1782 KeyPrefix(database_id, object_store_id).Encode(); | 
| 1316 const std::string stop_key = | 1783 const std::string stop_key = | 
| 1317 KeyPrefix(database_id, object_store_id + 1).Encode(); | 1784 KeyPrefix(database_id, object_store_id + 1).Encode(); | 
| 1318 | 1785 | 
| 1319 DeleteRange(leveldb_transaction, start_key, stop_key); | 1786 DeleteRangeHelper(leveldb_transaction, start_key, stop_key); | 
| 1787 DeleteBlobsInObjectStore(transaction, database_id, object_store_id); | |
| 1320 return true; | 1788 return true; | 
| 1321 } | 1789 } | 
| 1322 | 1790 | 
| 1323 bool IndexedDBBackingStore::DeleteRecord( | 1791 bool IndexedDBBackingStore::DeleteRecord( | 
| 1324 IndexedDBBackingStore::Transaction* transaction, | 1792 IndexedDBBackingStore::Transaction* transaction, | 
| 1325 int64 database_id, | 1793 int64 database_id, | 
| 1326 int64 object_store_id, | 1794 int64 object_store_id, | 
| 1327 const RecordIdentifier& record_identifier) { | 1795 const RecordIdentifier& record_identifier) { | 
| 1796 fprintf(stderr, "ERICU: DeleteRecord.\n"); | |
| 1328 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); | 1797 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); | 
| 1329 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1798 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 
| 1330 return false; | 1799 return false; | 
| 1331 LevelDBTransaction* leveldb_transaction = | 1800 LevelDBTransaction* leveldb_transaction = | 
| 1332 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 1801 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1333 | 1802 | 
| 1334 const std::string object_store_data_key = ObjectStoreDataKey::Encode( | 1803 const std::string object_store_data_key = ObjectStoreDataKey::Encode( | 
| 1335 database_id, object_store_id, record_identifier.primary_key()); | 1804 database_id, object_store_id, record_identifier.primary_key()); | 
| 1336 leveldb_transaction->Remove(object_store_data_key); | 1805 leveldb_transaction->Remove(object_store_data_key); | 
| 1806 transaction->PutBlobInfo(database_id, object_store_id, object_store_data_key, | |
| 1807 NULL); | |
| 1337 | 1808 | 
| 1338 const std::string exists_entry_key = ExistsEntryKey::Encode( | 1809 const std::string exists_entry_key = ExistsEntryKey::Encode( | 
| 1339 database_id, object_store_id, record_identifier.primary_key()); | 1810 database_id, object_store_id, record_identifier.primary_key()); | 
| 1340 leveldb_transaction->Remove(exists_entry_key); | 1811 leveldb_transaction->Remove(exists_entry_key); | 
| 1341 return true; | 1812 return true; | 
| 1342 } | 1813 } | 
| 1343 | 1814 | 
| 1815 bool IndexedDBBackingStore::DeleteRange( | |
| 1816 IndexedDBBackingStore::Transaction* transaction, | |
| 1817 int64 database_id, | |
| 1818 int64 object_store_id, | |
| 1819 const IndexedDBKeyRange& key_range) { | |
| 1820 fprintf(stderr, "ERICU: DeleteRange.\n"); | |
| 1821 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = | |
| 1822 OpenObjectStoreCursor(transaction, database_id, object_store_id, | |
| 1823 key_range, indexed_db::CURSOR_NEXT); | |
| 1824 if (backing_store_cursor) { | |
| 1825 do { | |
| 1826 if (!DeleteRecord( | |
| 1827 transaction, database_id, object_store_id, | |
| 1828 backing_store_cursor->record_identifier())) | |
| 1829 return false; | |
| 1830 } while (backing_store_cursor->Continue()); | |
| 1831 } | |
| 1832 | |
| 1833 std::string blob_lower = | |
| 1834 BlobEntryKey::Encode(database_id, object_store_id, | |
| 1835 key_range.lower()); | |
| 1836 std::string blob_upper = | |
| 1837 BlobEntryKey::Encode(database_id, object_store_id, | |
| 1838 key_range.upper()); | |
| 1839 LevelDBTransaction* leveldb_transaction = | |
| 1840 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | |
| 1841 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); | |
| 1842 it->Seek(blob_lower); | |
| 1843 while (it->IsValid() && | |
| 1844 ((key_range.lowerOpen() && | |
| 1845 CompareKeys(it->Key(), blob_lower) <= 0) || | |
| 1846 (!key_range.lowerOpen() && | |
| 1847 CompareKeys(it->Key(), blob_lower) < 0))) | |
| 
jsbell
2013/09/13 00:12:21
Given it->Seek(blob_lower), can CompareKeys(it->Ke
 
ericu
2013/11/20 23:05:39
Nope; fixed.
 | |
| 1848 it->Next(); | |
| 1849 | |
| 1850 while (it->IsValid() && | |
| 1851 ((key_range.upperOpen() && | |
| 1852 CompareKeys(it->Key(), blob_upper) < 0) || | |
| 1853 (!key_range.upperOpen() && | |
| 1854 CompareKeys(it->Key(), blob_upper) <= 0))) { | |
| 1855 StringPiece key_piece(it->Key()); | |
| 1856 std::string object_store_data_key = | |
| 1857 BlobEntryKey::EncodeToObjectStoreDataKey(&key_piece); | |
| 1858 if (!object_store_data_key.size()) | |
| 1859 return false; | |
| 1860 transaction->PutBlobInfo(database_id, object_store_id, | |
| 1861 object_store_data_key, NULL); | |
| 1862 it->Next(); | |
| 1863 } | |
| 1864 | |
| 1865 return true; | |
| 1866 } | |
| 1867 | |
| 1344 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( | 1868 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( | 
| 1345 IndexedDBBackingStore::Transaction* transaction, | 1869 IndexedDBBackingStore::Transaction* transaction, | 
| 1346 int64 database_id, | 1870 int64 database_id, | 
| 1347 int64 object_store_id, | 1871 int64 object_store_id, | 
| 1348 int64* key_generator_current_number) { | 1872 int64* key_generator_current_number) { | 
| 1349 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 1873 if (!KeyPrefix::ValidIds(database_id, object_store_id)) | 
| 1350 return false; | 1874 return false; | 
| 1351 LevelDBTransaction* leveldb_transaction = | 1875 LevelDBTransaction* leveldb_transaction = | 
| 1352 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 1876 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1353 | 1877 | 
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1473 StringPiece slice(data); | 1997 StringPiece slice(data); | 
| 1474 if (!DecodeVarInt(&slice, &version)) | 1998 if (!DecodeVarInt(&slice, &version)) | 
| 1475 return false; | 1999 return false; | 
| 1476 | 2000 | 
| 1477 std::string encoded_key; | 2001 std::string encoded_key; | 
| 1478 EncodeIDBKey(key, &encoded_key); | 2002 EncodeIDBKey(key, &encoded_key); | 
| 1479 found_record_identifier->Reset(encoded_key, version); | 2003 found_record_identifier->Reset(encoded_key, version); | 
| 1480 return true; | 2004 return true; | 
| 1481 } | 2005 } | 
| 1482 | 2006 | 
| 2007 class IndexedDBBackingStore::Transaction::ChainedBlobWriter : public | |
| 2008 base::RefCounted<IndexedDBBackingStore::Transaction::ChainedBlobWriter> { | |
| 2009 public: | |
| 2010 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec | |
| 2011 WriteDescriptorVec; | |
| 2012 ChainedBlobWriter( | |
| 2013 int64 database_id, | |
| 2014 IndexedDBBackingStore* backingStore, | |
| 2015 WriteDescriptorVec& blobs, | |
| 2016 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) | |
| 2017 : waiting_for_callback_(false), | |
| 2018 database_id_(database_id), | |
| 2019 backing_store_(backingStore), | |
| 2020 callback_(callback), | |
| 2021 aborted_(false) { | |
| 2022 blobs_.swap(blobs); | |
| 2023 iter_ = blobs_.begin(); | |
| 2024 WriteNextFile(); | |
| 2025 } | |
| 2026 | |
| 2027 void set_delegate(scoped_ptr<FileWriterDelegate> delegate) { | |
| 2028 delegate_.reset(delegate.release()); | |
| 2029 } | |
| 2030 | |
| 2031 void ReportWriteCompletion(bool succeeded, int64 bytes_written) { | |
| 2032 // TODO(ericu): Is there any need to check bytes_written against what we | |
| 2033 // know, if we know it? | |
| 2034 DCHECK(waiting_for_callback_); | |
| 2035 DCHECK(bytes_written >= 0); | |
| 2036 waiting_for_callback_ = false; | |
| 2037 content::BrowserThread::DeleteSoon( | |
| 2038 content::BrowserThread::IO, FROM_HERE, | |
| 2039 delegate_.release()); | |
| 2040 if (aborted_) { | |
| 2041 self_ref_ = NULL; | |
| 2042 return; | |
| 2043 } | |
| 2044 if (succeeded) | |
| 2045 WriteNextFile(); | |
| 2046 else | |
| 2047 callback_->didFail(); | |
| 2048 } | |
| 2049 | |
| 2050 void Abort() { | |
| 2051 if (!waiting_for_callback_) | |
| 2052 return; | |
| 2053 self_ref_ = this; | |
| 2054 aborted_ = true; | |
| 2055 } | |
| 2056 | |
| 2057 private: | |
| 2058 void WriteNextFile() { | |
| 2059 DCHECK(!waiting_for_callback_); | |
| 2060 DCHECK(!aborted_); | |
| 2061 if (iter_ == blobs_.end()) { | |
| 2062 callback_->didSucceed(); | |
| 2063 self_ref_ = NULL; | |
| 2064 } else { | |
| 2065 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { | |
| 2066 callback_->didFail(); | |
| 2067 return; | |
| 2068 } | |
| 2069 waiting_for_callback_ = true; | |
| 2070 ++iter_; | |
| 2071 } | |
| 2072 } | |
| 2073 | |
| 2074 bool waiting_for_callback_; | |
| 2075 scoped_refptr<ChainedBlobWriter> self_ref_; | |
| 2076 WriteDescriptorVec blobs_; | |
| 2077 WriteDescriptorVec::const_iterator iter_; | |
| 2078 int64 database_id_; | |
| 2079 IndexedDBBackingStore* backing_store_; | |
| 2080 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; | |
| 2081 scoped_ptr<FileWriterDelegate> delegate_; | |
| 2082 bool aborted_; | |
| 2083 }; | |
| 2084 | |
| 2085 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, | |
| 2086 public base::RefCounted<LocalWriteClosure> { | |
| 2087 public: | |
| 2088 LocalWriteClosure( | |
| 2089 IndexedDBBackingStore::Transaction::ChainedBlobWriter* | |
| 2090 chained_blob_writer_, | |
| 2091 base::TaskRunner* task_runner) | |
| 2092 : chained_blob_writer_(chained_blob_writer_), | |
| 2093 task_runner_(task_runner), | |
| 2094 bytes_written_(-1) { | |
| 2095 } | |
| 2096 | |
| 2097 void Run( | |
| 2098 base::PlatformFileError rv, | |
| 2099 int64 bytes, | |
| 2100 FileWriterDelegate::WriteProgressStatus write_status) { | |
| 2101 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) | |
| 2102 return; // We don't care about progress events. | |
| 2103 if (rv == base::PLATFORM_FILE_OK) { | |
| 2104 DCHECK(bytes >= 0); | |
| 2105 DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED); | |
| 2106 bytes_written_ = bytes; | |
| 2107 } else { | |
| 2108 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || | |
| 2109 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); | |
| 2110 } | |
| 2111 task_runner_->PostTask( | |
| 2112 FROM_HERE, | |
| 2113 base::Bind( | |
| 2114 &LocalWriteClosure::callBlobCallbackOnIDBTaskRunner, this, | |
| 2115 write_status == FileWriterDelegate::SUCCESS_COMPLETED)); | |
| 2116 } | |
| 2117 | |
| 2118 void writeBlobToFileOnIOThread( | |
| 2119 const FilePath& file_path, const GURL& blob_url, | |
| 2120 net::URLRequestContext* request_context) { | |
| 2121 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 2122 scoped_ptr<fileapi::FileStreamWriter> writer( | |
| 2123 new fileapi::LocalFileStreamWriter( | |
| 2124 task_runner_, file_path, 0, false)); | |
| 2125 scoped_ptr<FileWriterDelegate> delegate( | |
| 2126 new FileWriterDelegate(writer.Pass())); | |
| 2127 | |
| 2128 DCHECK(blob_url.is_valid()); | |
| 2129 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( | |
| 2130 blob_url, delegate.get())); | |
| 2131 | |
| 2132 delegate->Start(blob_request.Pass(), | |
| 2133 base::Bind(&LocalWriteClosure::Run, this)); | |
| 2134 chained_blob_writer_->set_delegate(delegate.Pass()); | |
| 2135 } | |
| 2136 | |
| 2137 private: | |
| 2138 void callBlobCallbackOnIDBTaskRunner(bool succeeded) { | |
| 2139 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
| 2140 chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_); | |
| 2141 } | |
| 2142 | |
| 2143 IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_; | |
| 2144 base::TaskRunner* task_runner_; | |
| 2145 int64 bytes_written_; | |
| 2146 }; | |
| 2147 | |
| 2148 bool IndexedDBBackingStore::WriteBlobFile( | |
| 2149 int64 database_id, | |
| 2150 const Transaction::WriteDescriptor& descriptor, | |
| 2151 Transaction::ChainedBlobWriter* chained_blob_writer) { | |
| 2152 | |
| 2153 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) | |
| 2154 return false; | |
| 2155 | |
| 2156 FilePath path = GetIDBBlobFileName(database_id, descriptor.key()); | |
| 2157 | |
| 2158 if (descriptor.is_file()) { | |
| 2159 // TODO: Should we validate the snapshot date here? | |
| 2160 DCHECK(!descriptor.file_path().empty()); | |
| 2161 if (!base::CopyFile(descriptor.file_path(), path)) | |
| 2162 return false; | |
| 2163 | |
| 2164 base::PlatformFileInfo info; | |
| 2165 if (file_util::GetFileInfo(descriptor.file_path(), &info)) { | |
| 2166 if (!file_util::TouchFile(path, info.last_accessed, info.last_modified)) | |
| 2167 ; // TODO: Complain quietly; timestamp's probably not vital. | |
| 2168 } else { | |
| 2169 ; // TODO: Complain quietly; timestamp's probably not vital. | |
| 2170 } | |
| 2171 | |
| 2172 task_runner_->PostTask( | |
| 2173 FROM_HERE, | |
| 2174 base::Bind( | |
| 2175 &Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
| 2176 chained_blob_writer, true, info.size)); | |
| 2177 } else { | |
| 2178 DCHECK(descriptor.url().is_valid()); | |
| 2179 scoped_refptr<LocalWriteClosure> write_closure( | |
| 2180 new LocalWriteClosure(chained_blob_writer, task_runner_)); | |
| 2181 content::BrowserThread::PostTask( | |
| 2182 content::BrowserThread::IO, FROM_HERE, | |
| 2183 base::Bind( | |
| 2184 &LocalWriteClosure::writeBlobToFileOnIOThread, write_closure.get(), | |
| 2185 path, descriptor.url(), request_context_)); | |
| 2186 } | |
| 2187 return true; | |
| 2188 } | |
| 2189 | |
| 2190 void IndexedDBBackingStore::ReportBlobUnused( | |
| 2191 int64 database_id, | |
| 2192 int64 blob_key) { | |
| 2193 fprintf(stderr, "ERICU: ReportBlobUnused(%ld, %ld).\n", database_id, | |
| 2194 blob_key); | |
| 2195 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
| 2196 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
| 2197 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
| 2198 scoped_refptr<LevelDBTransaction> transaction = | |
| 2199 new LevelDBTransaction(db_.get()); | |
| 2200 | |
| 2201 std::string secondary_key = LiveBlobJournalKey::Encode(); | |
| 2202 IndexedDBBackingStore::Transaction::BlobJournalType secondary_journal; | |
| 2203 if (!GetBlobJournal(secondary_key, transaction.get(), secondary_journal)) | |
| 2204 return; | |
| 2205 DCHECK(secondary_journal.size()); | |
| 2206 | |
| 2207 std::string primary_key = BlobJournalKey::Encode(); | |
| 2208 IndexedDBBackingStore::Transaction::BlobJournalType primary_journal; | |
| 2209 if (!GetBlobJournal(primary_key, transaction.get(), primary_journal)) | |
| 2210 return; | |
| 2211 | |
| 2212 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
| 2213 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to | |
| 2214 // remove all entries with database_id from the secondary journal and add only | |
| 2215 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) | |
| 2216 // and we hit kAllBlobsKey for the right database_id in the journal, we leave | |
| 2217 // the kAllBlobsKey entry in the secondary journal but add the specific blob | |
| 2218 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a | |
| 2219 // matching (database_id, blob_key) tuple, we should move it to the primary | |
| 2220 // journal. | |
| 2221 fprintf(stderr, "ERICU: journal sizes are: %ld, %ld.\n", | |
| 2222 primary_journal.size(), secondary_journal.size()); | |
| 2223 IndexedDBBackingStore::Transaction::BlobJournalType new_secondary_journal; | |
| 2224 for (journal_iter = secondary_journal.begin(); | |
| 2225 journal_iter != secondary_journal.end(); ++journal_iter) { | |
| 2226 int64 current_database_id = journal_iter->first; | |
| 2227 int64 current_blob_key = journal_iter->second; | |
| 2228 bool current_all_blobs = | |
| 2229 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; | |
| 2230 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || | |
| 2231 current_all_blobs); | |
| 2232 if (current_database_id == database_id && (all_blobs || | |
| 2233 current_all_blobs || blob_key == current_blob_key)) { | |
| 2234 if (!all_blobs) { | |
| 2235 fprintf(stderr, "ERICU: moving to primary: %ld, %ld.\n", database_id, | |
| 2236 blob_key); | |
| 2237 primary_journal.push_back( | |
| 2238 std::make_pair(database_id, current_blob_key)); | |
| 2239 if (current_all_blobs) | |
| 2240 new_secondary_journal.push_back(*journal_iter); | |
| 2241 new_secondary_journal.insert(new_secondary_journal.end(), | |
| 2242 ++journal_iter, secondary_journal.end()); // All the rest. | |
| 2243 break; | |
| 2244 } else { | |
| 2245 fprintf(stderr, "ERICU: was all_blobs\n"); | |
| 2246 } | |
| 2247 } else { | |
| 2248 fprintf(stderr, "ERICU: leaving in secondary: %ld, %ld.\n", database_id, | |
| 2249 blob_key); | |
| 2250 new_secondary_journal.push_back(*journal_iter); | |
| 2251 } | |
| 2252 } | |
| 2253 if (all_blobs) { | |
| 2254 primary_journal.push_back(std::make_pair( | |
| 2255 database_id, DatabaseMetaDataKey::kAllBlobsKey)); | |
| 2256 } | |
| 2257 fprintf(stderr, "ERICU: journal sizes are now: %ld, %ld.\n", | |
| 2258 primary_journal.size(), new_secondary_journal.size()); | |
| 2259 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); | |
| 2260 UpdateSecondaryJournalWithBlobList(transaction.get(), new_secondary_journal); | |
| 2261 transaction->Commit(); | |
| 2262 fprintf(stderr, "ERICU: committed journal updates. Cleaning in 5 sec.\n"); | |
| 2263 // We could just do the deletions/cleaning here, but if there are a lot of | |
| 2264 // blobs about to be garbage collected, it'd be better to wait and do them all | |
| 2265 // at once. | |
| 2266 journal_cleaning_timer_.Start( | |
| 2267 FROM_HERE, base::TimeDelta::FromSeconds(5), this, | |
| 
jsbell
2013/09/13 00:12:21
I just landed a change which tweaks the lifetime r
 
ericu
2013/11/20 23:05:39
OK, we should talk about what the right thing to d
 
ericu
2013/12/02 23:35:19
Addressed in patch set 57.
 | |
| 2268 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); | |
| 2269 } | |
| 2270 | |
| 2271 // This assumes a file path of dbId/3rd-byte-of-counter/counter. | |
| 2272 FilePath IndexedDBBackingStore::GetIDBBlobFileName( | |
| 2273 int64 database_id, int64 key) { | |
| 2274 FilePath path = GetIDBBlobDirectoryNameForKey(blob_path_, database_id, key); | |
| 2275 path = path.AppendASCII(base::StringPrintf("%lx", key)); | |
| 2276 return path; | |
| 2277 } | |
| 2278 | |
| 1483 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 2279 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, | 
| 1484 const std::string& stop_key, | 2280 const std::string& stop_key, | 
| 1485 int64 index_id, | 2281 int64 index_id, | 
| 1486 unsigned char meta_data_type) { | 2282 unsigned char meta_data_type) { | 
| 1487 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 2283 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) | 
| 1488 return false; | 2284 return false; | 
| 1489 | 2285 | 
| 1490 StringPiece slice(it->Key()); | 2286 StringPiece slice(it->Key()); | 
| 1491 IndexMetaDataKey meta_data_key; | 2287 IndexMetaDataKey meta_data_key; | 
| 1492 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 2288 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1575 | 2371 | 
| 1576 it->Next(); | 2372 it->Next(); | 
| 1577 } | 2373 } | 
| 1578 | 2374 | 
| 1579 (*indexes)[index_id] = IndexedDBIndexMetadata( | 2375 (*indexes)[index_id] = IndexedDBIndexMetadata( | 
| 1580 index_name, index_id, key_path, index_unique, index_multi_entry); | 2376 index_name, index_id, key_path, index_unique, index_multi_entry); | 
| 1581 } | 2377 } | 
| 1582 return true; | 2378 return true; | 
| 1583 } | 2379 } | 
| 1584 | 2380 | 
| 2381 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { | |
| 2382 FilePath fileName = GetIDBBlobFileName(database_id, key); | |
| 2383 return base::DeleteFile(fileName, false); | |
| 2384 } | |
| 2385 | |
| 2386 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { | |
| 2387 FilePath dirName = GetIDBBlobDirectoryName(blob_path_, database_id); | |
| 2388 return base::DeleteFile(dirName, true); | |
| 2389 } | |
| 2390 | |
| 2391 bool IndexedDBBackingStore::CleanUpBlobJournal( | |
| 2392 const std::string& level_db_key) { | |
| 2393 scoped_refptr<LevelDBTransaction> journal_transaction = | |
| 2394 new LevelDBTransaction(db_.get()); | |
| 2395 IndexedDBBackingStore::Transaction::BlobJournalType journal; | |
| 2396 if (!GetBlobJournal(level_db_key, journal_transaction.get(), | |
| 2397 journal)) { | |
| 2398 return false; | |
| 2399 } | |
| 2400 if (!journal.size()) { | |
| 2401 return true; | |
| 2402 } | |
| 2403 if (journal.size()) { | |
| 2404 IndexedDBBackingStore::Transaction::BlobJournalType::iterator journal_iter; | |
| 2405 for (journal_iter = journal.begin(); journal_iter != journal.end(); | |
| 2406 ++journal_iter) { | |
| 2407 int64 database_id = journal_iter->first; | |
| 2408 int64 blob_key = journal_iter->second; | |
| 2409 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); | |
| 2410 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { | |
| 2411 RemoveBlobDirectory(database_id); | |
| 2412 } else { | |
| 2413 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); | |
| 2414 RemoveBlobFile(database_id, blob_key); | |
| 2415 } | |
| 2416 } | |
| 2417 } | |
| 2418 ClearBlobJournal(journal_transaction.get(), level_db_key); | |
| 2419 return journal_transaction->Commit(); | |
| 2420 } | |
| 2421 | |
| 2422 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { | |
| 2423 fprintf(stderr, "ERICU: Cleaning primary journal.\n"); | |
| 2424 CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 2425 } | |
| 2426 | |
| 1585 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, | 2427 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, | 
| 1586 int64 database_id, | 2428 int64 database_id, | 
| 1587 int64 object_store_id, | 2429 int64 object_store_id, | 
| 1588 int64 index_id) { | 2430 int64 index_id) { | 
| 1589 int64 max_index_id = -1; | 2431 int64 max_index_id = -1; | 
| 1590 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 2432 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( | 
| 1591 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 2433 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); | 
| 1592 bool found = false; | 2434 bool found = false; | 
| 1593 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); | 2435 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); | 
| 1594 if (!ok) { | 2436 if (!ok) { | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1649 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); | 2491 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); | 
| 1650 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) | 2492 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) | 
| 1651 return false; | 2493 return false; | 
| 1652 LevelDBTransaction* leveldb_transaction = | 2494 LevelDBTransaction* leveldb_transaction = | 
| 1653 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 2495 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 1654 | 2496 | 
| 1655 const std::string index_meta_data_start = | 2497 const std::string index_meta_data_start = | 
| 1656 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); | 2498 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); | 
| 1657 const std::string index_meta_data_end = | 2499 const std::string index_meta_data_end = | 
| 1658 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2500 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 
| 1659 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); | 2501 DeleteRangeHelper(leveldb_transaction, index_meta_data_start, | 
| 2502 index_meta_data_end); | |
| 1660 | 2503 | 
| 1661 const std::string index_data_start = | 2504 const std::string index_data_start = | 
| 1662 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); | 2505 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); | 
| 1663 const std::string index_data_end = | 2506 const std::string index_data_end = | 
| 1664 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 2507 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); | 
| 1665 DeleteRange(leveldb_transaction, index_data_start, index_data_end); | 2508 DeleteRangeHelper(leveldb_transaction, index_data_start, index_data_end); | 
| 1666 return true; | 2509 return true; | 
| 1667 } | 2510 } | 
| 1668 | 2511 | 
| 1669 bool IndexedDBBackingStore::PutIndexDataForRecord( | 2512 bool IndexedDBBackingStore::PutIndexDataForRecord( | 
| 1670 IndexedDBBackingStore::Transaction* transaction, | 2513 IndexedDBBackingStore::Transaction* transaction, | 
| 1671 int64 database_id, | 2514 int64 database_id, | 
| 1672 int64 object_store_id, | 2515 int64 object_store_id, | 
| 1673 int64 index_id, | 2516 int64 index_id, | 
| 1674 const IndexedDBKey& key, | 2517 const IndexedDBKey& key, | 
| 1675 const RecordIdentifier& record_identifier) { | 2518 const RecordIdentifier& record_identifier) { | 
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1876 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); | 2719 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); | 
| 1877 return false; | 2720 return false; | 
| 1878 } | 2721 } | 
| 1879 | 2722 | 
| 1880 StringPiece slice(found_encoded_primary_key); | 2723 StringPiece slice(found_encoded_primary_key); | 
| 1881 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); | 2724 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); | 
| 1882 } | 2725 } | 
| 1883 | 2726 | 
| 1884 IndexedDBBackingStore::Cursor::Cursor( | 2727 IndexedDBBackingStore::Cursor::Cursor( | 
| 1885 const IndexedDBBackingStore::Cursor* other) | 2728 const IndexedDBBackingStore::Cursor* other) | 
| 1886 : transaction_(other->transaction_), | 2729 : backing_store_(other->backing_store_), | 
| 2730 transaction_(other->transaction_), | |
| 2731 database_id_(other->database_id_), | |
| 1887 cursor_options_(other->cursor_options_), | 2732 cursor_options_(other->cursor_options_), | 
| 1888 current_key_(new IndexedDBKey(*other->current_key_)) { | 2733 current_key_(new IndexedDBKey(*other->current_key_)) { | 
| 1889 if (other->iterator_) { | 2734 if (other->iterator_) { | 
| 1890 iterator_ = transaction_->CreateIterator(); | 2735 iterator_ = transaction_->CreateIterator(); | 
| 1891 | 2736 | 
| 1892 if (other->iterator_->IsValid()) { | 2737 if (other->iterator_->IsValid()) { | 
| 1893 iterator_->Seek(other->iterator_->Key()); | 2738 iterator_->Seek(other->iterator_->Key()); | 
| 1894 DCHECK(iterator_->IsValid()); | 2739 DCHECK(iterator_->IsValid()); | 
| 1895 } | 2740 } | 
| 1896 } | 2741 } | 
| 1897 } | 2742 } | 
| 1898 | 2743 | 
| 1899 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, | 2744 IndexedDBBackingStore::Cursor::Cursor( | 
| 1900 const CursorOptions& cursor_options) | 2745 scoped_refptr<IndexedDBBackingStore> backing_store, | 
| 1901 : transaction_(transaction), cursor_options_(cursor_options) {} | 2746 LevelDBTransaction* transaction, | 
| 2747 int64 database_id, | |
| 2748 const CursorOptions& cursor_options) | |
| 2749 : backing_store_(backing_store), | |
| 2750 transaction_(transaction), | |
| 2751 database_id_(database_id), | |
| 2752 cursor_options_(cursor_options) { | |
| 2753 } | |
| 1902 IndexedDBBackingStore::Cursor::~Cursor() {} | 2754 IndexedDBBackingStore::Cursor::~Cursor() {} | 
| 1903 | 2755 | 
| 1904 bool IndexedDBBackingStore::Cursor::FirstSeek() { | 2756 bool IndexedDBBackingStore::Cursor::FirstSeek() { | 
| 1905 iterator_ = transaction_->CreateIterator(); | 2757 iterator_ = transaction_->CreateIterator(); | 
| 1906 if (cursor_options_.forward) | 2758 if (cursor_options_.forward) | 
| 1907 iterator_->Seek(cursor_options_.low_key); | 2759 iterator_->Seek(cursor_options_.low_key); | 
| 1908 else | 2760 else | 
| 1909 iterator_->Seek(cursor_options_.high_key); | 2761 iterator_->Seek(cursor_options_.high_key); | 
| 1910 | 2762 | 
| 1911 return Continue(0, READY); | 2763 return Continue(0, READY); | 
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2055 } | 2907 } | 
| 2056 | 2908 | 
| 2057 const IndexedDBBackingStore::RecordIdentifier& | 2909 const IndexedDBBackingStore::RecordIdentifier& | 
| 2058 IndexedDBBackingStore::Cursor::record_identifier() const { | 2910 IndexedDBBackingStore::Cursor::record_identifier() const { | 
| 2059 return record_identifier_; | 2911 return record_identifier_; | 
| 2060 } | 2912 } | 
| 2061 | 2913 | 
| 2062 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 2914 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 
| 2063 public: | 2915 public: | 
| 2064 ObjectStoreKeyCursorImpl( | 2916 ObjectStoreKeyCursorImpl( | 
| 2917 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2065 LevelDBTransaction* transaction, | 2918 LevelDBTransaction* transaction, | 
| 2919 int64 database_id, | |
| 2066 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2920 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 
| 2067 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2921 : IndexedDBBackingStore::Cursor( | 
| 2922 backing_store, transaction, database_id, cursor_options) {} | |
| 2068 | 2923 | 
| 2069 virtual Cursor* Clone() OVERRIDE { | 2924 virtual Cursor* Clone() OVERRIDE { | 
| 2070 return new ObjectStoreKeyCursorImpl(this); | 2925 return new ObjectStoreKeyCursorImpl(this); | 
| 2071 } | 2926 } | 
| 2072 | 2927 | 
| 2073 // IndexedDBBackingStore::Cursor | 2928 // IndexedDBBackingStore::Cursor | 
| 2074 virtual std::string* Value() OVERRIDE { | 2929 virtual IndexedDBValue* Value() OVERRIDE { | 
| 2075 NOTREACHED(); | 2930 NOTREACHED(); | 
| 2076 return NULL; | 2931 return NULL; | 
| 2077 } | 2932 } | 
| 2078 virtual bool LoadCurrentRow() OVERRIDE; | 2933 virtual bool LoadCurrentRow() OVERRIDE; | 
| 2079 | 2934 | 
| 2080 protected: | 2935 protected: | 
| 2081 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2936 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 
| 2082 return ObjectStoreDataKey::Encode( | 2937 return ObjectStoreDataKey::Encode( | 
| 2083 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2938 cursor_options_.database_id, cursor_options_.object_store_id, key); | 
| 2084 } | 2939 } | 
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2109 std::string encoded_key; | 2964 std::string encoded_key; | 
| 2110 EncodeIDBKey(*current_key_, &encoded_key); | 2965 EncodeIDBKey(*current_key_, &encoded_key); | 
| 2111 record_identifier_.Reset(encoded_key, version); | 2966 record_identifier_.Reset(encoded_key, version); | 
| 2112 | 2967 | 
| 2113 return true; | 2968 return true; | 
| 2114 } | 2969 } | 
| 2115 | 2970 | 
| 2116 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { | 2971 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { | 
| 2117 public: | 2972 public: | 
| 2118 ObjectStoreCursorImpl( | 2973 ObjectStoreCursorImpl( | 
| 2974 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2119 LevelDBTransaction* transaction, | 2975 LevelDBTransaction* transaction, | 
| 2976 int64 database_id, | |
| 2120 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 2977 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 
| 2121 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 2978 : IndexedDBBackingStore::Cursor( | 
| 2979 backing_store, transaction, database_id, cursor_options) {} | |
| 2122 | 2980 | 
| 2123 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } | 2981 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } | 
| 2124 | 2982 | 
| 2125 // IndexedDBBackingStore::Cursor | 2983 // IndexedDBBackingStore::Cursor | 
| 2126 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 2984 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } | 
| 2127 virtual bool LoadCurrentRow() OVERRIDE; | 2985 virtual bool LoadCurrentRow() OVERRIDE; | 
| 2128 | 2986 | 
| 2129 protected: | 2987 protected: | 
| 2130 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 2988 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 
| 2131 return ObjectStoreDataKey::Encode( | 2989 return ObjectStoreDataKey::Encode( | 
| 2132 cursor_options_.database_id, cursor_options_.object_store_id, key); | 2990 cursor_options_.database_id, cursor_options_.object_store_id, key); | 
| 2133 } | 2991 } | 
| 2134 | 2992 | 
| 2135 private: | 2993 private: | 
| 2136 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) | 2994 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) | 
| 2137 : IndexedDBBackingStore::Cursor(other), | 2995 : IndexedDBBackingStore::Cursor(other), | 
| 2138 current_value_(other->current_value_) {} | 2996 current_value_(other->current_value_) {} | 
| 2139 | 2997 | 
| 2140 std::string current_value_; | 2998 IndexedDBValue current_value_; | 
| 2141 }; | 2999 }; | 
| 2142 | 3000 | 
| 2143 bool ObjectStoreCursorImpl::LoadCurrentRow() { | 3001 bool ObjectStoreCursorImpl::LoadCurrentRow() { | 
| 2144 StringPiece slice(iterator_->Key()); | 3002 StringPiece key_slice(iterator_->Key()); | 
| 2145 ObjectStoreDataKey object_store_data_key; | 3003 ObjectStoreDataKey object_store_data_key; | 
| 2146 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { | 3004 if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) { | 
| 2147 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3005 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2148 return false; | 3006 return false; | 
| 2149 } | 3007 } | 
| 2150 | 3008 | 
| 2151 current_key_ = object_store_data_key.user_key(); | 3009 current_key_ = object_store_data_key.user_key(); | 
| 2152 | 3010 | 
| 2153 int64 version; | 3011 int64 version; | 
| 2154 slice = StringPiece(iterator_->Value()); | 3012 StringPiece value_slice = StringPiece(iterator_->Value()); | 
| 2155 if (!DecodeVarInt(&slice, &version)) { | 3013 if (!DecodeVarInt(&value_slice, &version)) { | 
| 2156 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3014 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2157 return false; | 3015 return false; | 
| 2158 } | 3016 } | 
| 2159 | 3017 | 
| 2160 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. | 3018 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. | 
| 2161 std::string encoded_key; | 3019 std::string encoded_key; | 
| 2162 EncodeIDBKey(*current_key_, &encoded_key); | 3020 EncodeIDBKey(*current_key_, &encoded_key); | 
| 2163 record_identifier_.Reset(encoded_key, version); | 3021 record_identifier_.Reset(encoded_key, version); | 
| 2164 | 3022 | 
| 2165 current_value_ = slice.as_string(); | 3023 // TODO(ericu): Don't set bits until we know we've succeeded? | 
| 2166 return true; | 3024 current_value_.bits = value_slice.as_string(); | 
| 3025 return GetBlobInfoForRecord(backing_store_, transaction_, database_id_, | |
| 3026 iterator_->Key().as_string(), ¤t_value_); | |
| 2167 } | 3027 } | 
| 2168 | 3028 | 
| 2169 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 3029 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { | 
| 2170 public: | 3030 public: | 
| 2171 IndexKeyCursorImpl( | 3031 IndexKeyCursorImpl( | 
| 3032 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2172 LevelDBTransaction* transaction, | 3033 LevelDBTransaction* transaction, | 
| 3034 int64 database_id, | |
| 2173 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 3035 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 
| 2174 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 3036 : IndexedDBBackingStore::Cursor( | 
| 3037 backing_store, transaction, database_id, cursor_options) {} | |
| 2175 | 3038 | 
| 2176 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } | 3039 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } | 
| 2177 | 3040 | 
| 2178 // IndexedDBBackingStore::Cursor | 3041 // IndexedDBBackingStore::Cursor | 
| 2179 virtual std::string* Value() OVERRIDE { | 3042 virtual IndexedDBValue* Value() OVERRIDE { | 
| 2180 NOTREACHED(); | 3043 NOTREACHED(); | 
| 2181 return NULL; | 3044 return NULL; | 
| 2182 } | 3045 } | 
| 2183 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 3046 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 
| 2184 return *primary_key_; | 3047 return *primary_key_; | 
| 2185 } | 3048 } | 
| 2186 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 3049 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() | 
| 2187 const { | 3050 const OVERRIDE { | 
| 2188 NOTREACHED(); | 3051 NOTREACHED(); | 
| 2189 return record_identifier_; | 3052 return record_identifier_; | 
| 2190 } | 3053 } | 
| 2191 virtual bool LoadCurrentRow() OVERRIDE; | 3054 virtual bool LoadCurrentRow() OVERRIDE; | 
| 2192 | 3055 | 
| 2193 protected: | 3056 protected: | 
| 2194 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 3057 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 
| 2195 return IndexDataKey::Encode(cursor_options_.database_id, | 3058 return IndexDataKey::Encode(cursor_options_.database_id, | 
| 2196 cursor_options_.object_store_id, | 3059 cursor_options_.object_store_id, | 
| 2197 cursor_options_.index_id, | 3060 cursor_options_.index_id, | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2261 transaction_->Remove(iterator_->Key()); | 3124 transaction_->Remove(iterator_->Key()); | 
| 2262 return false; | 3125 return false; | 
| 2263 } | 3126 } | 
| 2264 | 3127 | 
| 2265 return true; | 3128 return true; | 
| 2266 } | 3129 } | 
| 2267 | 3130 | 
| 2268 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { | 3131 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { | 
| 2269 public: | 3132 public: | 
| 2270 IndexCursorImpl( | 3133 IndexCursorImpl( | 
| 3134 scoped_refptr<IndexedDBBackingStore> backing_store, | |
| 2271 LevelDBTransaction* transaction, | 3135 LevelDBTransaction* transaction, | 
| 3136 int64 database_id, | |
| 2272 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 3137 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) | 
| 2273 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} | 3138 : IndexedDBBackingStore::Cursor( | 
| 3139 backing_store, transaction, database_id, cursor_options) {} | |
| 2274 | 3140 | 
| 2275 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } | 3141 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } | 
| 2276 | 3142 | 
| 2277 // IndexedDBBackingStore::Cursor | 3143 // IndexedDBBackingStore::Cursor | 
| 2278 virtual std::string* Value() OVERRIDE { return ¤t_value_; } | 3144 virtual IndexedDBValue* Value() OVERRIDE { return ¤t_value_; } | 
| 2279 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 3145 virtual const IndexedDBKey& primary_key() const OVERRIDE { | 
| 2280 return *primary_key_; | 3146 return *primary_key_; | 
| 2281 } | 3147 } | 
| 2282 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() | 3148 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() | 
| 2283 const { | 3149 const OVERRIDE { | 
| 2284 NOTREACHED(); | 3150 NOTREACHED(); | 
| 2285 return record_identifier_; | 3151 return record_identifier_; | 
| 2286 } | 3152 } | 
| 2287 virtual bool LoadCurrentRow() OVERRIDE; | 3153 virtual bool LoadCurrentRow() OVERRIDE; | 
| 2288 | 3154 | 
| 2289 protected: | 3155 protected: | 
| 2290 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 3156 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { | 
| 2291 return IndexDataKey::Encode(cursor_options_.database_id, | 3157 return IndexDataKey::Encode(cursor_options_.database_id, | 
| 2292 cursor_options_.object_store_id, | 3158 cursor_options_.object_store_id, | 
| 2293 cursor_options_.index_id, | 3159 cursor_options_.index_id, | 
| 2294 key); | 3160 key); | 
| 2295 } | 3161 } | 
| 2296 | 3162 | 
| 2297 private: | 3163 private: | 
| 2298 explicit IndexCursorImpl(const IndexCursorImpl* other) | 3164 explicit IndexCursorImpl(const IndexCursorImpl* other) | 
| 2299 : IndexedDBBackingStore::Cursor(other), | 3165 : IndexedDBBackingStore::Cursor(other), | 
| 2300 primary_key_(new IndexedDBKey(*other->primary_key_)), | 3166 primary_key_(new IndexedDBKey(*other->primary_key_)), | 
| 2301 current_value_(other->current_value_), | 3167 current_value_(other->current_value_), | 
| 2302 primary_leveldb_key_(other->primary_leveldb_key_) {} | 3168 primary_leveldb_key_(other->primary_leveldb_key_) {} | 
| 2303 | 3169 | 
| 2304 scoped_ptr<IndexedDBKey> primary_key_; | 3170 scoped_ptr<IndexedDBKey> primary_key_; | 
| 2305 std::string current_value_; | 3171 IndexedDBValue current_value_; | 
| 2306 std::string primary_leveldb_key_; | 3172 std::string primary_leveldb_key_; | 
| 2307 }; | 3173 }; | 
| 2308 | 3174 | 
| 2309 bool IndexCursorImpl::LoadCurrentRow() { | 3175 bool IndexCursorImpl::LoadCurrentRow() { | 
| 2310 StringPiece slice(iterator_->Key()); | 3176 StringPiece slice(iterator_->Key()); | 
| 2311 IndexDataKey index_data_key; | 3177 IndexDataKey index_data_key; | 
| 2312 if (!IndexDataKey::Decode(&slice, &index_data_key)) { | 3178 if (!IndexDataKey::Decode(&slice, &index_data_key)) { | 
| 2313 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3179 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2314 return false; | 3180 return false; | 
| 2315 } | 3181 } | 
| 2316 | 3182 | 
| 2317 current_key_ = index_data_key.user_key(); | 3183 current_key_ = index_data_key.user_key(); | 
| 2318 DCHECK(current_key_); | 3184 DCHECK(current_key_); | 
| 2319 | 3185 | 
| 2320 slice = StringPiece(iterator_->Value()); | 3186 slice = StringPiece(iterator_->Value()); | 
| 2321 int64 index_data_version; | 3187 int64 index_data_version; | 
| 2322 if (!DecodeVarInt(&slice, &index_data_version)) { | 3188 if (!DecodeVarInt(&slice, &index_data_version)) { | 
| 2323 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3189 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2324 return false; | 3190 return false; | 
| 2325 } | 3191 } | 
| 2326 if (!DecodeIDBKey(&slice, &primary_key_)) { | 3192 if (!DecodeIDBKey(&slice, &primary_key_)) { | 
| 2327 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3193 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2328 return false; | 3194 return false; | 
| 2329 } | 3195 } | 
| 2330 | 3196 | 
| 3197 DCHECK_EQ(index_data_key.DatabaseId(), database_id_); | |
| 2331 primary_leveldb_key_ = | 3198 primary_leveldb_key_ = | 
| 2332 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), | 3199 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), | 
| 2333 index_data_key.ObjectStoreId(), | 3200 index_data_key.ObjectStoreId(), | 
| 2334 *primary_key_); | 3201 *primary_key_); | 
| 2335 | 3202 | 
| 2336 std::string result; | 3203 std::string result; | 
| 2337 bool found = false; | 3204 bool found = false; | 
| 2338 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); | 3205 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); | 
| 2339 if (!ok) { | 3206 if (!ok) { | 
| 2340 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3207 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2354 if (!DecodeVarInt(&slice, &object_store_data_version)) { | 3221 if (!DecodeVarInt(&slice, &object_store_data_version)) { | 
| 2355 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 3222 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); | 
| 2356 return false; | 3223 return false; | 
| 2357 } | 3224 } | 
| 2358 | 3225 | 
| 2359 if (object_store_data_version != index_data_version) { | 3226 if (object_store_data_version != index_data_version) { | 
| 2360 transaction_->Remove(iterator_->Key()); | 3227 transaction_->Remove(iterator_->Key()); | 
| 2361 return false; | 3228 return false; | 
| 2362 } | 3229 } | 
| 2363 | 3230 | 
| 2364 current_value_ = slice.as_string(); | 3231 current_value_.bits = slice.as_string(); | 
| 2365 return true; | 3232 return GetBlobInfoForRecord(backing_store_, transaction_, database_id_, | 
| 3233 primary_leveldb_key_, ¤t_value_); | |
| 2366 } | 3234 } | 
| 2367 | 3235 | 
| 2368 bool ObjectStoreCursorOptions( | 3236 bool ObjectStoreCursorOptions( | 
| 2369 LevelDBTransaction* transaction, | 3237 LevelDBTransaction* transaction, | 
| 2370 int64 database_id, | 3238 int64 database_id, | 
| 2371 int64 object_store_id, | 3239 int64 object_store_id, | 
| 2372 const IndexedDBKeyRange& range, | 3240 const IndexedDBKeyRange& range, | 
| 2373 indexed_db::CursorDirection direction, | 3241 indexed_db::CursorDirection direction, | 
| 2374 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { | 3242 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { | 
| 2375 cursor_options->database_id = database_id; | 3243 cursor_options->database_id = database_id; | 
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2513 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 3381 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 2514 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3382 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 
| 2515 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3383 if (!ObjectStoreCursorOptions(leveldb_transaction, | 
| 2516 database_id, | 3384 database_id, | 
| 2517 object_store_id, | 3385 object_store_id, | 
| 2518 range, | 3386 range, | 
| 2519 direction, | 3387 direction, | 
| 2520 &cursor_options)) | 3388 &cursor_options)) | 
| 2521 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3389 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2522 scoped_ptr<ObjectStoreCursorImpl> cursor( | 3390 scoped_ptr<ObjectStoreCursorImpl> cursor( | 
| 2523 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); | 3391 new ObjectStoreCursorImpl( | 
| 3392 this, leveldb_transaction, database_id, cursor_options)); | |
| 2524 if (!cursor->FirstSeek()) | 3393 if (!cursor->FirstSeek()) | 
| 2525 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3394 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2526 | 3395 | 
| 2527 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3396 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 
| 2528 } | 3397 } | 
| 2529 | 3398 | 
| 2530 scoped_ptr<IndexedDBBackingStore::Cursor> | 3399 scoped_ptr<IndexedDBBackingStore::Cursor> | 
| 2531 IndexedDBBackingStore::OpenObjectStoreKeyCursor( | 3400 IndexedDBBackingStore::OpenObjectStoreKeyCursor( | 
| 2532 IndexedDBBackingStore::Transaction* transaction, | 3401 IndexedDBBackingStore::Transaction* transaction, | 
| 2533 int64 database_id, | 3402 int64 database_id, | 
| 2534 int64 object_store_id, | 3403 int64 object_store_id, | 
| 2535 const IndexedDBKeyRange& range, | 3404 const IndexedDBKeyRange& range, | 
| 2536 indexed_db::CursorDirection direction) { | 3405 indexed_db::CursorDirection direction) { | 
| 2537 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); | 3406 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); | 
| 2538 LevelDBTransaction* leveldb_transaction = | 3407 LevelDBTransaction* leveldb_transaction = | 
| 2539 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 3408 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 2540 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3409 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 
| 2541 if (!ObjectStoreCursorOptions(leveldb_transaction, | 3410 if (!ObjectStoreCursorOptions(leveldb_transaction, | 
| 2542 database_id, | 3411 database_id, | 
| 2543 object_store_id, | 3412 object_store_id, | 
| 2544 range, | 3413 range, | 
| 2545 direction, | 3414 direction, | 
| 2546 &cursor_options)) | 3415 &cursor_options)) | 
| 2547 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3416 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2548 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( | 3417 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( | 
| 2549 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); | 3418 new ObjectStoreKeyCursorImpl( | 
| 3419 this, leveldb_transaction, database_id, cursor_options)); | |
| 2550 if (!cursor->FirstSeek()) | 3420 if (!cursor->FirstSeek()) | 
| 2551 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3421 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2552 | 3422 | 
| 2553 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3423 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 
| 2554 } | 3424 } | 
| 2555 | 3425 | 
| 2556 scoped_ptr<IndexedDBBackingStore::Cursor> | 3426 scoped_ptr<IndexedDBBackingStore::Cursor> | 
| 2557 IndexedDBBackingStore::OpenIndexKeyCursor( | 3427 IndexedDBBackingStore::OpenIndexKeyCursor( | 
| 2558 IndexedDBBackingStore::Transaction* transaction, | 3428 IndexedDBBackingStore::Transaction* transaction, | 
| 2559 int64 database_id, | 3429 int64 database_id, | 
| 2560 int64 object_store_id, | 3430 int64 object_store_id, | 
| 2561 int64 index_id, | 3431 int64 index_id, | 
| 2562 const IndexedDBKeyRange& range, | 3432 const IndexedDBKeyRange& range, | 
| 2563 indexed_db::CursorDirection direction) { | 3433 indexed_db::CursorDirection direction) { | 
| 2564 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); | 3434 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); | 
| 2565 LevelDBTransaction* leveldb_transaction = | 3435 LevelDBTransaction* leveldb_transaction = | 
| 2566 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 3436 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 2567 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3437 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 
| 2568 if (!IndexCursorOptions(leveldb_transaction, | 3438 if (!IndexCursorOptions(leveldb_transaction, | 
| 2569 database_id, | 3439 database_id, | 
| 2570 object_store_id, | 3440 object_store_id, | 
| 2571 index_id, | 3441 index_id, | 
| 2572 range, | 3442 range, | 
| 2573 direction, | 3443 direction, | 
| 2574 &cursor_options)) | 3444 &cursor_options)) | 
| 2575 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3445 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2576 scoped_ptr<IndexKeyCursorImpl> cursor( | 3446 scoped_ptr<IndexKeyCursorImpl> cursor( | 
| 2577 new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); | 3447 new IndexKeyCursorImpl( | 
| 3448 this, leveldb_transaction, database_id, cursor_options)); | |
| 2578 if (!cursor->FirstSeek()) | 3449 if (!cursor->FirstSeek()) | 
| 2579 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3450 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2580 | 3451 | 
| 2581 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3452 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 
| 2582 } | 3453 } | 
| 2583 | 3454 | 
| 2584 scoped_ptr<IndexedDBBackingStore::Cursor> | 3455 scoped_ptr<IndexedDBBackingStore::Cursor> | 
| 2585 IndexedDBBackingStore::OpenIndexCursor( | 3456 IndexedDBBackingStore::OpenIndexCursor( | 
| 2586 IndexedDBBackingStore::Transaction* transaction, | 3457 IndexedDBBackingStore::Transaction* transaction, | 
| 2587 int64 database_id, | 3458 int64 database_id, | 
| 2588 int64 object_store_id, | 3459 int64 object_store_id, | 
| 2589 int64 index_id, | 3460 int64 index_id, | 
| 2590 const IndexedDBKeyRange& range, | 3461 const IndexedDBKeyRange& range, | 
| 2591 indexed_db::CursorDirection direction) { | 3462 indexed_db::CursorDirection direction) { | 
| 2592 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); | 3463 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); | 
| 2593 LevelDBTransaction* leveldb_transaction = | 3464 LevelDBTransaction* leveldb_transaction = | 
| 2594 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 3465 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); | 
| 2595 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 3466 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; | 
| 2596 if (!IndexCursorOptions(leveldb_transaction, | 3467 if (!IndexCursorOptions(leveldb_transaction, | 
| 2597 database_id, | 3468 database_id, | 
| 2598 object_store_id, | 3469 object_store_id, | 
| 2599 index_id, | 3470 index_id, | 
| 2600 range, | 3471 range, | 
| 2601 direction, | 3472 direction, | 
| 2602 &cursor_options)) | 3473 &cursor_options)) | 
| 2603 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3474 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2604 scoped_ptr<IndexCursorImpl> cursor( | 3475 scoped_ptr<IndexCursorImpl> cursor( | 
| 2605 new IndexCursorImpl(leveldb_transaction, cursor_options)); | 3476 new IndexCursorImpl( | 
| 3477 this, leveldb_transaction, database_id, cursor_options)); | |
| 2606 if (!cursor->FirstSeek()) | 3478 if (!cursor->FirstSeek()) | 
| 2607 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 3479 return scoped_ptr<IndexedDBBackingStore::Cursor>(); | 
| 2608 | 3480 | 
| 2609 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 3481 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); | 
| 2610 } | 3482 } | 
| 2611 | 3483 | 
| 2612 IndexedDBBackingStore::Transaction::Transaction( | 3484 IndexedDBBackingStore::Transaction::Transaction( | 
| 2613 IndexedDBBackingStore* backing_store) | 3485 IndexedDBBackingStore* backing_store) | 
| 2614 : backing_store_(backing_store) {} | 3486 : backing_store_(backing_store), | 
| 3487 database_id_(-1) { | |
| 3488 blob_info_tree_.abstractor().comparator_ = backing_store->comparator(); | |
| 3489 } | |
| 2615 | 3490 | 
| 2616 IndexedDBBackingStore::Transaction::~Transaction() {} | 3491 IndexedDBBackingStore::Transaction::~Transaction() {} | 
| 2617 | 3492 | 
| 2618 void IndexedDBBackingStore::Transaction::Begin() { | 3493 void IndexedDBBackingStore::Transaction::Begin() { | 
| 2619 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); | 3494 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); | 
| 2620 DCHECK(!transaction_.get()); | 3495 DCHECK(!transaction_.get()); | 
| 2621 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); | 3496 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); | 
| 2622 } | 3497 fprintf(stderr, "ERICU: %p::Begin(%p).\n", this, transaction_.get()); | 
| 2623 | 3498 } | 
| 2624 bool IndexedDBBackingStore::Transaction::Commit() { | 3499 | 
| 2625 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); | 3500 bool IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( | 
| 2626 DCHECK(transaction_.get()); | 3501 BlobEntryKeyValuePairVec* new_blob_entries, | 
| 3502 WriteDescriptorVec* new_files_to_write) { | |
| 3503 TreeType::Iterator iter; | |
| 3504 iter.StartIterLeast(&blob_info_tree_); | |
| 3505 new_blob_entries->clear(); | |
| 3506 new_files_to_write->clear(); | |
| 3507 if (*iter) { | |
| 3508 // Create LevelDBTransaction for the name generator seed and add-journal. | |
| 3509 scoped_refptr<LevelDBTransaction> pre_transaction = | |
| 3510 new LevelDBTransaction(backing_store_->db_.get()); | |
| 3511 BlobJournalType journal; | |
| 3512 for (; *iter; ++iter) { | |
| 3513 std::vector<IndexedDBBlobInfo>::iterator info_iter; | |
| 3514 std::vector<IndexedDBBlobInfo*> new_blob_keys; | |
| 3515 for (info_iter = (*iter)->blob_info.begin(); | |
| 3516 info_iter != (*iter)->blob_info.end(); ++info_iter) { | |
| 3517 int64 next_blob_key = -1; | |
| 3518 bool result = GetBlobKeyGeneratorCurrentNumber( | |
| 3519 pre_transaction.get(), database_id_, next_blob_key); | |
| 3520 if (!result || next_blob_key < 0) | |
| 3521 return false; | |
| 3522 BlobJournalEntryType journal_entry = | |
| 3523 std::make_pair(database_id_, next_blob_key); | |
| 3524 journal.push_back(journal_entry); | |
| 3525 if (info_iter->is_file()) { | |
| 3526 new_files_to_write->push_back( | |
| 3527 WriteDescriptor(info_iter->file_path(), next_blob_key)); | |
| 3528 } else { | |
| 3529 new_files_to_write->push_back( | |
| 3530 WriteDescriptor(info_iter->url(), next_blob_key)); | |
| 3531 } | |
| 3532 info_iter->set_key(next_blob_key); | |
| 3533 new_blob_keys.push_back(&*info_iter); | |
| 3534 result = UpdateBlobKeyGeneratorCurrentNumber( | |
| 3535 pre_transaction.get(), database_id_, next_blob_key + 1); | |
| 3536 if (!result) | |
| 3537 return result; | |
| 3538 } | |
| 3539 BlobEntryKey blob_entry_key; | |
| 3540 StringPiece key_piece((*iter)->key); | |
| 3541 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
| 3542 NOTREACHED(); | |
| 3543 return false; | |
| 3544 } | |
| 3545 new_blob_entries->push_back(std::make_pair(blob_entry_key, | |
| 3546 EncodeBlobData(new_blob_keys))); | |
| 3547 } | |
| 3548 UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal); | |
| 3549 if (!pre_transaction->Commit()) | |
| 3550 return false; | |
| 3551 } | |
| 3552 return true; | |
| 3553 } | |
| 3554 | |
| 3555 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { | |
| 3556 TreeType::Iterator iter; | |
| 3557 iter.StartIterLeast(&blob_info_tree_); | |
| 3558 // Look up all old files to remove as part of the transaction, store their | |
| 3559 // names in blobs_to_remove_, and remove their old blob data entries. | |
| 3560 if (*iter) { | |
| 3561 scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator(); | |
| 3562 for (; *iter; ++iter) { | |
| 3563 BlobEntryKey blob_entry_key; | |
| 3564 StringPiece key_piece((*iter)->key); | |
| 3565 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { | |
| 3566 NOTREACHED(); | |
| 3567 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3568 transaction_ = NULL; | |
| 3569 return false; | |
| 3570 } | |
| 3571 if (database_id_ < 0) | |
| 3572 database_id_ = blob_entry_key.database_id(); | |
| 3573 else | |
| 3574 DCHECK_EQ(database_id_, blob_entry_key.database_id()); | |
| 3575 std::string blob_entry_key_bytes = blob_entry_key.Encode(); | |
| 3576 db_iter->Seek(blob_entry_key_bytes); | |
| 3577 if (db_iter->IsValid()) { | |
| 3578 std::vector<IndexedDBBlobInfo> blob_info; | |
| 3579 if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) { | |
| 3580 INTERNAL_READ_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3581 transaction_ = NULL; | |
| 3582 return false; | |
| 3583 } | |
| 3584 std::vector<IndexedDBBlobInfo>::iterator blob_info_iter; | |
| 3585 for (blob_info_iter = blob_info.begin(); | |
| 3586 blob_info_iter != blob_info.end(); ++blob_info_iter) | |
| 3587 blobs_to_remove_.push_back( | |
| 3588 std::make_pair(database_id_, blob_info_iter->key())); | |
| 3589 transaction_->Remove(blob_entry_key_bytes); | |
| 3590 } else { | |
| 3591 fprintf(stderr, "ERICU: db_iter wasn't valid.\n"); | |
| 3592 } | |
| 3593 } | |
| 3594 } | |
| 3595 return true; | |
| 3596 } | |
| 3597 | |
| 3598 void IndexedDBBackingStore::Transaction::WriteNewBlobs( | |
| 3599 BlobEntryKeyValuePairVec& new_blob_entries, | |
| 3600 WriteDescriptorVec& new_files_to_write, | |
| 3601 scoped_refptr<BlobWriteCallback> callback) { | |
| 3602 DCHECK_GT(new_files_to_write.size(), 0UL); | |
| 3603 DCHECK_GT(database_id_, 0); | |
| 3604 BlobEntryKeyValuePairVec::iterator blob_entry_iter; | |
| 3605 for (blob_entry_iter = new_blob_entries.begin(); | |
| 3606 blob_entry_iter != new_blob_entries.end(); ++blob_entry_iter) { | |
| 3607 // Add the new blob-table entry for each blob to the main transaction, or | |
| 3608 // remove any entry that may exist if there's no new one. | |
| 3609 if (!blob_entry_iter->second.size()) | |
| 3610 transaction_->Remove(blob_entry_iter->first.Encode()); | |
| 3611 else | |
| 3612 transaction_->Put(blob_entry_iter->first.Encode(), | |
| 3613 &blob_entry_iter->second); | |
| 3614 } | |
| 3615 // Creating the writer will start it going asynchronously. | |
| 3616 chained_blob_writer_ = new ChainedBlobWriter(database_id_, backing_store_, | |
| 3617 new_files_to_write, callback); | |
| 3618 } | |
| 3619 | |
| 3620 bool IndexedDBBackingStore::Transaction::SortBlobsToRemove() { | |
| 3621 IndexedDBActiveBlobRegistry* registry = | |
| 3622 backing_store_->active_blob_registry(); | |
| 3623 BlobJournalType::iterator iter; | |
| 3624 BlobJournalType primary_journal, secondary_journal; | |
| 3625 for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end(); | |
| 3626 ++iter) { | |
| 3627 if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second)) | |
| 3628 secondary_journal.push_back(*iter); | |
| 3629 else | |
| 3630 primary_journal.push_back(*iter); | |
| 3631 } | |
| 3632 fprintf(stderr, "ERICU: Updating primary journal.\n"); | |
| 3633 UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal); | |
| 3634 fprintf(stderr, "ERICU: Updating secondary journal.\n"); | |
| 3635 if (!MergeBlobsIntoSecondaryJournal(transaction_.get(), secondary_journal)) { | |
| 3636 fprintf(stderr, "ERICU: Updating secondary journal FAILED!\n"); | |
| 3637 return false; | |
| 3638 } | |
| 3639 // To signal how many blobs need attention right now. | |
| 3640 blobs_to_remove_.swap(primary_journal); | |
| 3641 return true; | |
| 3642 } | |
| 3643 | |
| 3644 bool IndexedDBBackingStore::Transaction::CommitPhaseOne( | |
| 3645 scoped_refptr<BlobWriteCallback> callback) { | |
| 3646 IDB_TRACE("IndexedDBBackingStore::Transaction::commit"); | |
| 3647 DCHECK(transaction_); | |
| 3648 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); | |
| 3649 | |
| 3650 if (!backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode())) { | |
| 3651 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3652 transaction_ = NULL; | |
| 3653 return false; | |
| 3654 } | |
| 3655 | |
| 3656 BlobEntryKeyValuePairVec new_blob_entries; | |
| 3657 WriteDescriptorVec new_files_to_write; | |
| 3658 // This commits the journal of blob files we're about to add, if any. | |
| 3659 if (!HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write)) { | |
| 3660 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3661 transaction_ = NULL; | |
| 3662 return false; | |
| 3663 } | |
| 3664 | |
| 3665 DCHECK(!new_files_to_write.size() || | |
| 3666 KeyPrefix::IsValidDatabaseId(database_id_)); | |
| 3667 fprintf(stderr, "ERICU: Calling CollectBlobFilesToRemove.\n"); | |
| 3668 if (!CollectBlobFilesToRemove()) { | |
| 3669 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3670 transaction_ = NULL; | |
| 3671 return false; | |
| 3672 } | |
| 3673 | |
| 3674 if (new_files_to_write.size()) { | |
| 3675 // This kicks off the writes of the new blobs, if any. | |
| 3676 // This call will zero out new_blob_entries and new_files_to_write. | |
| 3677 WriteNewBlobs(new_blob_entries, new_files_to_write, callback); | |
| 3678 // Remove the add journal, if any; once the blobs are written, and we | |
| 3679 // commit, this will do the cleanup. | |
| 3680 ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode()); | |
| 3681 } else { | |
| 3682 callback->didSucceed(); | |
| 3683 } | |
| 3684 | |
| 3685 return true; | |
| 3686 } | |
| 3687 | |
| 3688 bool IndexedDBBackingStore::Transaction::CommitPhaseTwo() { | |
| 3689 fprintf(stderr, "ERICU: In CommitPhaseTwo; blobs_to_remove_.size() is %lu.\n", | |
| 3690 blobs_to_remove_.size()); | |
| 3691 if (blobs_to_remove_.size()) | |
| 3692 if (!SortBlobsToRemove()) { | |
| 3693 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | |
| 3694 transaction_ = NULL; | |
| 3695 return false; | |
| 3696 } | |
| 3697 | |
| 3698 fprintf(stderr, "ERICU: committing transaction_.\n"); | |
| 2627 bool result = transaction_->Commit(); | 3699 bool result = transaction_->Commit(); | 
| 2628 transaction_ = NULL; | 3700 transaction_ = NULL; | 
| 3701 | |
| 2629 if (!result) | 3702 if (!result) | 
| 2630 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | 3703 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); | 
| 3704 else if (blobs_to_remove_.size()) | |
| 3705 backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); | |
| 3706 | |
| 2631 return result; | 3707 return result; | 
| 2632 } | 3708 } | 
| 2633 | 3709 | 
| 2634 void IndexedDBBackingStore::Transaction::Rollback() { | 3710 void IndexedDBBackingStore::Transaction::Rollback() { | 
| 2635 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 3711 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); | 
| 2636 DCHECK(transaction_.get()); | 3712 DCHECK(transaction_.get()); | 
| 3713 if (chained_blob_writer_) | |
| 3714 chained_blob_writer_->Abort(); | |
| 2637 transaction_->Rollback(); | 3715 transaction_->Rollback(); | 
| 2638 transaction_ = NULL; | 3716 transaction_ = NULL; | 
| 2639 } | 3717 } | 
| 2640 | 3718 | 
| 3719 // This is storing an info, even if empty, even if the previous key had no blob | |
| 3720 // info that we know of. It duplicates a bunch of information stored in the | |
| 3721 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the | |
| 3722 // changes to exists or index keys here. | |
| 3723 void IndexedDBBackingStore::Transaction::PutBlobInfo( | |
| 3724 int64 database_id, | |
| 3725 int64 object_store_id, | |
| 3726 const std::string&key, | |
| 3727 std::vector<IndexedDBBlobInfo>* blob_info) { | |
| 3728 fprintf(stderr, "ERICU: PutBlobInfo ; blob_info is %p.\n", blob_info); | |
| 3729 DCHECK_GT(key.size(), 0UL); | |
| 3730 if (database_id_ < 0) | |
| 3731 database_id_ = database_id; | |
| 3732 DCHECK_EQ(database_id_, database_id); | |
| 3733 AVLTreeNode* node = blob_info_tree_.Search(key); | |
| 3734 if (!node) { | |
| 3735 node = new AVLTreeNode; | |
| 3736 node->key.insert(node->key.end(), key.begin(), key.end()); | |
| 3737 blob_info_tree_.Insert(node); | |
| 3738 node->object_store_id = object_store_id; | |
| 3739 } | |
| 3740 DCHECK_EQ(node->object_store_id, object_store_id); | |
| 3741 node->blob_info.clear(); | |
| 3742 if (blob_info) | |
| 3743 node->blob_info.swap(*blob_info); | |
| 3744 } | |
| 3745 | |
| 3746 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3747 const GURL& url, int64_t key) | |
| 3748 : is_file_(false), | |
| 3749 url_(url), | |
| 3750 key_(key) | |
| 3751 { | |
| 3752 } | |
| 3753 | |
| 3754 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( | |
| 3755 const FilePath& file_path, int64_t key) | |
| 3756 : is_file_(true), | |
| 3757 file_path_(file_path), | |
| 3758 key_(key) | |
| 3759 { | |
| 3760 } | |
| 3761 | |
| 2641 } // namespace content | 3762 } // namespace content | 
| OLD | NEW |