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 3 // found in the LICENSE file. 4 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" 6 7 #include "base/files/file_path.h" 8 #include "base/files/file_util.h" 9 #include "base/format_macros.h" 10 #include "base/json/json_reader.h" 11 #include "base/json/json_writer.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/stringprintf.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "content/browser/child_process_security_policy_impl.h" 18 #include "content/browser/indexed_db/indexed_db_blob_info.h" 19 #include "content/browser/indexed_db/indexed_db_class_factory.h" 20 #include "content/browser/indexed_db/indexed_db_database_error.h" 21 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" 22 #include "content/browser/indexed_db/indexed_db_metadata.h" 23 #include "content/browser/indexed_db/indexed_db_tracing.h" 24 #include "content/browser/indexed_db/indexed_db_value.h" 25 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" 26 #include "content/browser/indexed_db/leveldb/leveldb_database.h" 27 #include "content/browser/indexed_db/leveldb/leveldb_factory.h" 28 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" 29 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" 30 #include "content/common/indexed_db/indexed_db_key.h" 31 #include "content/common/indexed_db/indexed_db_key_path.h" 32 #include "content/common/indexed_db/indexed_db_key_range.h" 33 #include "content/public/browser/browser_thread.h" 34 #include "net/url_request/url_request_context.h" 35 #include "storage/browser/blob/blob_data_handle.h" 36 #include "storage/browser/fileapi/file_stream_writer.h" 37 #include "storage/browser/fileapi/file_writer_delegate.h" 38 #include "storage/browser/fileapi/local_file_stream_writer.h" 39 #include "storage/common/database/database_identifier.h" 40 #include "third_party/WebKit/public/platform/WebIDBTypes.h" 41 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" 42 #include "third_party/leveldatabase/env_chromium.h" 43 44 using base::FilePath; 45 using base::StringPiece; 46 using storage::FileWriterDelegate; 47 48 namespace content { 49 50 namespace { 51 52 FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) { 53 return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id)); 54 } 55 56 FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase, 57 int64 database_id, 58 int64 key) { 59 FilePath path = GetBlobDirectoryName(pathBase, database_id); 60 path = path.AppendASCII(base::StringPrintf( 61 "%02x", static_cast<int>(key & 0x000000000000ff00) >> 8)); 62 return path; 63 } 64 65 FilePath GetBlobFileNameForKey(const FilePath& pathBase, 66 int64 database_id, 67 int64 key) { 68 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); 69 path = path.AppendASCII(base::StringPrintf("%" PRIx64, key)); 70 return path; 71 } 72 73 bool MakeIDBBlobDirectory(const FilePath& pathBase, 74 int64 database_id, 75 int64 key) { 76 FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key); 77 return base::CreateDirectory(path); 78 } 79 80 static std::string ComputeOriginIdentifier(const GURL& origin_url) { 81 return storage::GetIdentifierFromOrigin(origin_url) + "@1"; 82 } 83 84 static base::FilePath ComputeFileName(const GURL& origin_url) { 85 return base::FilePath() 86 .AppendASCII(storage::GetIdentifierFromOrigin(origin_url)) 87 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); 88 } 89 90 static base::FilePath ComputeBlobPath(const GURL& origin_url) { 91 return base::FilePath() 92 .AppendASCII(storage::GetIdentifierFromOrigin(origin_url)) 93 .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob")); 94 } 95 96 static base::FilePath ComputeCorruptionFileName(const GURL& origin_url) { 97 return ComputeFileName(origin_url) 98 .Append(FILE_PATH_LITERAL("corruption_info.json")); 99 } 100 101 } // namespace 102 103 static const int64 kKeyGeneratorInitialNumber = 104 1; // From the IndexedDB specification. 105 106 enum IndexedDBBackingStoreErrorSource { 107 // 0 - 2 are no longer used. 108 FIND_KEY_IN_INDEX = 3, 109 GET_IDBDATABASE_METADATA, 110 GET_INDEXES, 111 GET_KEY_GENERATOR_CURRENT_NUMBER, 112 GET_OBJECT_STORES, 113 GET_RECORD, 114 KEY_EXISTS_IN_OBJECT_STORE, 115 LOAD_CURRENT_ROW, 116 SET_UP_METADATA, 117 GET_PRIMARY_KEY_VIA_INDEX, 118 KEY_EXISTS_IN_INDEX, 119 VERSION_EXISTS, 120 DELETE_OBJECT_STORE, 121 SET_MAX_OBJECT_STORE_ID, 122 SET_MAX_INDEX_ID, 123 GET_NEW_DATABASE_ID, 124 GET_NEW_VERSION_NUMBER, 125 CREATE_IDBDATABASE_METADATA, 126 DELETE_DATABASE, 127 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro 128 GET_DATABASE_NAMES, 129 DELETE_INDEX, 130 CLEAR_OBJECT_STORE, 131 READ_BLOB_JOURNAL, 132 DECODE_BLOB_JOURNAL, 133 GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER, 134 GET_BLOB_INFO_FOR_RECORD, 135 INTERNAL_ERROR_MAX, 136 }; 137 138 static void RecordInternalError(const char* type, 139 IndexedDBBackingStoreErrorSource location) { 140 std::string name; 141 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); 142 base::Histogram::FactoryGet(name, 143 1, 144 INTERNAL_ERROR_MAX, 145 INTERNAL_ERROR_MAX + 1, 146 base::HistogramBase::kUmaTargetedHistogramFlag) 147 ->Add(location); 148 } 149 150 // Use to signal conditions caused by data corruption. 151 // A macro is used instead of an inline function so that the assert and log 152 // report the line number. 153 #define REPORT_ERROR(type, location) \ 154 do { \ 155 LOG(ERROR) << "IndexedDB " type " Error: " #location; \ 156 RecordInternalError(type, location); \ 157 } while (0) 158 159 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location) 160 #define INTERNAL_CONSISTENCY_ERROR(location) \ 161 REPORT_ERROR("Consistency", location) 162 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location) 163 164 // Use to signal conditions that usually indicate developer error, but 165 // could be caused by data corruption. A macro is used instead of an 166 // inline function so that the assert and log report the line number. 167 // TODO(cmumford): Improve test coverage so that all error conditions are 168 // "tested" and then delete this macro. 169 #define REPORT_ERROR_UNTESTED(type, location) \ 170 do { \ 171 LOG(ERROR) << "IndexedDB " type " Error: " #location; \ 172 NOTREACHED(); \ 173 RecordInternalError(type, location); \ 174 } while (0) 175 176 #define INTERNAL_READ_ERROR_UNTESTED(location) \ 177 REPORT_ERROR_UNTESTED("Read", location) 178 #define INTERNAL_CONSISTENCY_ERROR_UNTESTED(location) \ 179 REPORT_ERROR_UNTESTED("Consistency", location) 180 #define INTERNAL_WRITE_ERROR_UNTESTED(location) \ 181 REPORT_ERROR_UNTESTED("Write", location) 182 183 static void PutBool(LevelDBTransaction* transaction, 184 const StringPiece& key, 185 bool value) { 186 std::string buffer; 187 EncodeBool(value, &buffer); 188 transaction->Put(key, &buffer); 189 } 190 191 // Was able to use LevelDB to read the data w/o error, but the data read was not 192 // in the expected format. 193 static leveldb::Status InternalInconsistencyStatus() { 194 return leveldb::Status::Corruption("Internal inconsistency"); 195 } 196 197 static leveldb::Status InvalidDBKeyStatus() { 198 return leveldb::Status::InvalidArgument("Invalid database key ID"); 199 } 200 201 static leveldb::Status IOErrorStatus() { 202 return leveldb::Status::IOError("IO Error"); 203 } 204 205 template <typename DBOrTransaction> 206 static leveldb::Status GetInt(DBOrTransaction* db, 207 const StringPiece& key, 208 int64* found_int, 209 bool* found) { 210 std::string result; 211 leveldb::Status s = db->Get(key, &result, found); 212 if (!s.ok()) 213 return s; 214 if (!*found) 215 return leveldb::Status::OK(); 216 StringPiece slice(result); 217 if (DecodeInt(&slice, found_int) && slice.empty()) 218 return s; 219 return InternalInconsistencyStatus(); 220 } 221 222 static void PutInt(LevelDBTransaction* transaction, 223 const StringPiece& key, 224 int64 value) { 225 DCHECK_GE(value, 0); 226 std::string buffer; 227 EncodeInt(value, &buffer); 228 transaction->Put(key, &buffer); 229 } 230 231 template <typename DBOrTransaction> 232 WARN_UNUSED_RESULT static leveldb::Status GetVarInt(DBOrTransaction* db, 233 const StringPiece& key, 234 int64* found_int, 235 bool* found) { 236 std::string result; 237 leveldb::Status s = db->Get(key, &result, found); 238 if (!s.ok()) 239 return s; 240 if (!*found) 241 return leveldb::Status::OK(); 242 StringPiece slice(result); 243 if (DecodeVarInt(&slice, found_int) && slice.empty()) 244 return s; 245 return InternalInconsistencyStatus(); 246 } 247 248 static void PutVarInt(LevelDBTransaction* transaction, 249 const StringPiece& key, 250 int64 value) { 251 std::string buffer; 252 EncodeVarInt(value, &buffer); 253 transaction->Put(key, &buffer); 254 } 255 256 template <typename DBOrTransaction> 257 WARN_UNUSED_RESULT static leveldb::Status GetString( 258 DBOrTransaction* db, 259 const StringPiece& key, 260 base::string16* found_string, 261 bool* found) { 262 std::string result; 263 *found = false; 264 leveldb::Status s = db->Get(key, &result, found); 265 if (!s.ok()) 266 return s; 267 if (!*found) 268 return leveldb::Status::OK(); 269 StringPiece slice(result); 270 if (DecodeString(&slice, found_string) && slice.empty()) 271 return s; 272 return InternalInconsistencyStatus(); 273 } 274 275 static void PutString(LevelDBTransaction* transaction, 276 const StringPiece& key, 277 const base::string16& value) { 278 std::string buffer; 279 EncodeString(value, &buffer); 280 transaction->Put(key, &buffer); 281 } 282 283 static void PutIDBKeyPath(LevelDBTransaction* transaction, 284 const StringPiece& key, 285 const IndexedDBKeyPath& value) { 286 std::string buffer; 287 EncodeIDBKeyPath(value, &buffer); 288 transaction->Put(key, &buffer); 289 } 290 291 static int CompareKeys(const StringPiece& a, const StringPiece& b) { 292 return Compare(a, b, false /*index_keys*/); 293 } 294 295 static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) { 296 return Compare(a, b, true /*index_keys*/); 297 } 298 299 int IndexedDBBackingStore::Comparator::Compare(const StringPiece& a, 300 const StringPiece& b) const { 301 return content::Compare(a, b, false /*index_keys*/); 302 } 303 304 const char* IndexedDBBackingStore::Comparator::Name() const { 305 return "idb_cmp1"; 306 } 307 308 // 0 - Initial version. 309 // 1 - Adds UserIntVersion to DatabaseMetaData. 310 // 2 - Adds DataVersion to to global metadata. 311 // 3 - Adds metadata needed for blob support. 312 static const int64 kLatestKnownSchemaVersion = 3; 313 WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) { 314 int64 db_schema_version = 0; 315 bool found = false; 316 leveldb::Status s = 317 GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found); 318 if (!s.ok()) 319 return false; 320 if (!found) { 321 *known = true; 322 return true; 323 } 324 if (db_schema_version > kLatestKnownSchemaVersion) { 325 *known = false; 326 return true; 327 } 328 329 const uint32 latest_known_data_version = 330 blink::kSerializedScriptValueVersion; 331 int64 db_data_version = 0; 332 s = GetInt(db, DataVersionKey::Encode(), &db_data_version, &found); 333 if (!s.ok()) 334 return false; 335 if (!found) { 336 *known = true; 337 return true; 338 } 339 340 if (db_data_version > latest_known_data_version) { 341 *known = false; 342 return true; 343 } 344 345 *known = true; 346 return true; 347 } 348 349 // TODO(ericu): Move this down into the member section of this file. I'm 350 // leaving it here for this CL as it's easier to see the diffs in place. 351 WARN_UNUSED_RESULT leveldb::Status IndexedDBBackingStore::SetUpMetadata() { 352 const uint32 latest_known_data_version = 353 blink::kSerializedScriptValueVersion; 354 const std::string schema_version_key = SchemaVersionKey::Encode(); 355 const std::string data_version_key = DataVersionKey::Encode(); 356 357 scoped_refptr<LevelDBTransaction> transaction = 358 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); 359 360 int64 db_schema_version = 0; 361 int64 db_data_version = 0; 362 bool found = false; 363 leveldb::Status s = 364 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); 365 if (!s.ok()) { 366 INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA); 367 return s; 368 } 369 if (!found) { 370 // Initialize new backing store. 371 db_schema_version = kLatestKnownSchemaVersion; 372 PutInt(transaction.get(), schema_version_key, db_schema_version); 373 db_data_version = latest_known_data_version; 374 PutInt(transaction.get(), data_version_key, db_data_version); 375 // If a blob directory already exists for this database, blow it away. It's 376 // leftover from a partially-purged previous generation of data. 377 if (!base::DeleteFile(blob_path_, true)) { 378 INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA); 379 return IOErrorStatus(); 380 } 381 } else { 382 // Upgrade old backing store. 383 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); 384 if (db_schema_version < 1) { 385 db_schema_version = 1; 386 PutInt(transaction.get(), schema_version_key, db_schema_version); 387 const std::string start_key = 388 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); 389 const std::string stop_key = 390 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); 391 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 392 for (s = it->Seek(start_key); 393 s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 394 s = it->Next()) { 395 int64 database_id = 0; 396 found = false; 397 s = GetInt(transaction.get(), it->Key(), &database_id, &found); 398 if (!s.ok()) { 399 INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA); 400 return s; 401 } 402 if (!found) { 403 INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA); 404 return InternalInconsistencyStatus(); 405 } 406 std::string int_version_key = DatabaseMetaDataKey::Encode( 407 database_id, DatabaseMetaDataKey::USER_INT_VERSION); 408 PutVarInt(transaction.get(), 409 int_version_key, 410 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 411 } 412 } 413 if (s.ok() && db_schema_version < 2) { 414 db_schema_version = 2; 415 PutInt(transaction.get(), schema_version_key, db_schema_version); 416 db_data_version = blink::kSerializedScriptValueVersion; 417 PutInt(transaction.get(), data_version_key, db_data_version); 418 } 419 if (db_schema_version < 3) { 420 db_schema_version = 3; 421 if (!base::DeleteFile(blob_path_, true)) { 422 INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA); 423 return IOErrorStatus(); 424 } 425 } 426 } 427 428 if (!s.ok()) { 429 INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA); 430 return s; 431 } 432 433 // All new values will be written using this serialization version. 434 found = false; 435 s = GetInt(transaction.get(), data_version_key, &db_data_version, &found); 436 if (!s.ok()) { 437 INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA); 438 return s; 439 } 440 if (!found) { 441 INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA); 442 return InternalInconsistencyStatus(); 443 } 444 if (db_data_version < latest_known_data_version) { 445 db_data_version = latest_known_data_version; 446 PutInt(transaction.get(), data_version_key, db_data_version); 447 } 448 449 DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion); 450 DCHECK_EQ(db_data_version, latest_known_data_version); 451 452 s = transaction->Commit(); 453 if (!s.ok()) 454 INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA); 455 return s; 456 } 457 458 template <typename DBOrTransaction> 459 WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId( 460 DBOrTransaction* db, 461 int64 database_id, 462 int64* max_object_store_id) { 463 const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode( 464 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); 465 return GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id); 466 } 467 468 template <typename DBOrTransaction> 469 WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId( 470 DBOrTransaction* db, 471 const std::string& max_object_store_id_key, 472 int64* max_object_store_id) { 473 *max_object_store_id = -1; 474 bool found = false; 475 leveldb::Status s = 476 GetInt(db, max_object_store_id_key, max_object_store_id, &found); 477 if (!s.ok()) 478 return s; 479 if (!found) 480 *max_object_store_id = 0; 481 482 DCHECK_GE(*max_object_store_id, 0); 483 return s; 484 } 485 486 class DefaultLevelDBFactory : public LevelDBFactory { 487 public: 488 DefaultLevelDBFactory() {} 489 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, 490 const LevelDBComparator* comparator, 491 scoped_ptr<LevelDBDatabase>* db, 492 bool* is_disk_full) OVERRIDE { 493 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); 494 } 495 virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) 496 OVERRIDE { 497 return LevelDBDatabase::Destroy(file_name); 498 } 499 500 private: 501 DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory); 502 }; 503 504 static bool GetBlobKeyGeneratorCurrentNumber( 505 LevelDBTransaction* leveldb_transaction, 506 int64 database_id, 507 int64* blob_key_generator_current_number) { 508 const std::string key_gen_key = DatabaseMetaDataKey::Encode( 509 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); 510 511 // Default to initial number if not found. 512 int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber; 513 std::string data; 514 515 bool found = false; 516 bool ok = leveldb_transaction->Get(key_gen_key, &data, &found).ok(); 517 if (!ok) { 518 INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); 519 return false; 520 } 521 if (found) { 522 StringPiece slice(data); 523 if (!DecodeVarInt(&slice, &cur_number) || !slice.empty() || 524 !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) { 525 INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER); 526 return false; 527 } 528 } 529 *blob_key_generator_current_number = cur_number; 530 return true; 531 } 532 533 static bool UpdateBlobKeyGeneratorCurrentNumber( 534 LevelDBTransaction* leveldb_transaction, 535 int64 database_id, 536 int64 blob_key_generator_current_number) { 537 #ifndef NDEBUG 538 int64 old_number; 539 if (!GetBlobKeyGeneratorCurrentNumber( 540 leveldb_transaction, database_id, &old_number)) 541 return false; 542 DCHECK_LT(old_number, blob_key_generator_current_number); 543 #endif 544 DCHECK( 545 DatabaseMetaDataKey::IsValidBlobKey(blob_key_generator_current_number)); 546 const std::string key = DatabaseMetaDataKey::Encode( 547 database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER); 548 549 PutVarInt(leveldb_transaction, key, blob_key_generator_current_number); 550 return true; 551 } 552 553 // TODO(ericu): Error recovery. If we persistently can't read the 554 // blob journal, the safe thing to do is to clear it and leak the blobs, 555 // though that may be costly. Still, database/directory deletion should always 556 // clean things up, and we can write an fsck that will do a full correction if 557 // need be. 558 template <typename T> 559 static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key, 560 T* leveldb_transaction, 561 BlobJournalType* journal) { 562 std::string data; 563 bool found = false; 564 leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found); 565 if (!s.ok()) { 566 INTERNAL_READ_ERROR(READ_BLOB_JOURNAL); 567 return s; 568 } 569 journal->clear(); 570 if (!found || !data.size()) 571 return leveldb::Status::OK(); 572 StringPiece slice(data); 573 if (!DecodeBlobJournal(&slice, journal)) { 574 INTERNAL_CONSISTENCY_ERROR_UNTESTED(DECODE_BLOB_JOURNAL); 575 s = InternalInconsistencyStatus(); 576 } 577 return s; 578 } 579 580 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction, 581 const std::string& level_db_key) { 582 leveldb_transaction->Remove(level_db_key); 583 } 584 585 static void UpdatePrimaryJournalWithBlobList( 586 LevelDBTransaction* leveldb_transaction, 587 const BlobJournalType& journal) { 588 const std::string leveldb_key = BlobJournalKey::Encode(); 589 std::string data; 590 EncodeBlobJournal(journal, &data); 591 leveldb_transaction->Put(leveldb_key, &data); 592 } 593 594 static void UpdateLiveBlobJournalWithBlobList( 595 LevelDBTransaction* leveldb_transaction, 596 const BlobJournalType& journal) { 597 const std::string leveldb_key = LiveBlobJournalKey::Encode(); 598 std::string data; 599 EncodeBlobJournal(journal, &data); 600 leveldb_transaction->Put(leveldb_key, &data); 601 } 602 603 static leveldb::Status MergeBlobsIntoLiveBlobJournal( 604 LevelDBTransaction* leveldb_transaction, 605 const BlobJournalType& journal) { 606 BlobJournalType old_journal; 607 const std::string key = LiveBlobJournalKey::Encode(); 608 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal); 609 if (!s.ok()) 610 return s; 611 612 old_journal.insert(old_journal.end(), journal.begin(), journal.end()); 613 614 UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal); 615 return leveldb::Status::OK(); 616 } 617 618 static void UpdateBlobJournalWithDatabase( 619 LevelDBDirectTransaction* leveldb_transaction, 620 int64 database_id) { 621 BlobJournalType journal; 622 journal.push_back( 623 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); 624 const std::string key = BlobJournalKey::Encode(); 625 std::string data; 626 EncodeBlobJournal(journal, &data); 627 leveldb_transaction->Put(key, &data); 628 } 629 630 static leveldb::Status MergeDatabaseIntoLiveBlobJournal( 631 LevelDBDirectTransaction* leveldb_transaction, 632 int64 database_id) { 633 BlobJournalType journal; 634 const std::string key = LiveBlobJournalKey::Encode(); 635 leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal); 636 if (!s.ok()) 637 return s; 638 journal.push_back( 639 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); 640 std::string data; 641 EncodeBlobJournal(journal, &data); 642 leveldb_transaction->Put(key, &data); 643 return leveldb::Status::OK(); 644 } 645 646 // Blob Data is encoded as a series of: 647 // { is_file [bool], key [int64 as varInt], 648 // type [string-with-length, may be empty], 649 // (for Blobs only) size [int64 as varInt] 650 // (for Files only) fileName [string-with-length] 651 // } 652 // There is no length field; just read until you run out of data. 653 static std::string EncodeBlobData( 654 const std::vector<IndexedDBBlobInfo*>& blob_info) { 655 std::string ret; 656 std::vector<IndexedDBBlobInfo*>::const_iterator iter; 657 for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) { 658 const IndexedDBBlobInfo& info = **iter; 659 EncodeBool(info.is_file(), &ret); 660 EncodeVarInt(info.key(), &ret); 661 EncodeStringWithLength(info.type(), &ret); 662 if (info.is_file()) 663 EncodeStringWithLength(info.file_name(), &ret); 664 else 665 EncodeVarInt(info.size(), &ret); 666 } 667 return ret; 668 } 669 670 static bool DecodeBlobData(const std::string& data, 671 std::vector<IndexedDBBlobInfo>* output) { 672 std::vector<IndexedDBBlobInfo> ret; 673 output->clear(); 674 StringPiece slice(data); 675 while (!slice.empty()) { 676 bool is_file; 677 int64 key; 678 base::string16 type; 679 int64 size; 680 base::string16 file_name; 681 682 if (!DecodeBool(&slice, &is_file)) 683 return false; 684 if (!DecodeVarInt(&slice, &key) || 685 !DatabaseMetaDataKey::IsValidBlobKey(key)) 686 return false; 687 if (!DecodeStringWithLength(&slice, &type)) 688 return false; 689 if (is_file) { 690 if (!DecodeStringWithLength(&slice, &file_name)) 691 return false; 692 ret.push_back(IndexedDBBlobInfo(key, type, file_name)); 693 } else { 694 if (!DecodeVarInt(&slice, &size) || size < 0) 695 return false; 696 ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key)); 697 } 698 } 699 output->swap(ret); 700 701 return true; 702 } 703 704 IndexedDBBackingStore::IndexedDBBackingStore( 705 IndexedDBFactory* indexed_db_factory, 706 const GURL& origin_url, 707 const base::FilePath& blob_path, 708 net::URLRequestContext* request_context, 709 scoped_ptr<LevelDBDatabase> db, 710 scoped_ptr<LevelDBComparator> comparator, 711 base::SequencedTaskRunner* task_runner) 712 : indexed_db_factory_(indexed_db_factory), 713 origin_url_(origin_url), 714 blob_path_(blob_path), 715 origin_identifier_(ComputeOriginIdentifier(origin_url)), 716 request_context_(request_context), 717 task_runner_(task_runner), 718 db_(db.Pass()), 719 comparator_(comparator.Pass()), 720 active_blob_registry_(this) { 721 } 722 723 IndexedDBBackingStore::~IndexedDBBackingStore() { 724 if (!blob_path_.empty() && !child_process_ids_granted_.empty()) { 725 ChildProcessSecurityPolicyImpl* policy = 726 ChildProcessSecurityPolicyImpl::GetInstance(); 727 std::set<int>::const_iterator iter; 728 for (iter = child_process_ids_granted_.begin(); 729 iter != child_process_ids_granted_.end(); 730 ++iter) { 731 policy->RevokeAllPermissionsForFile(*iter, blob_path_); 732 } 733 } 734 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), 735 incognito_blob_map_.end()); 736 // db_'s destructor uses comparator_. The order of destruction is important. 737 db_.reset(); 738 comparator_.reset(); 739 } 740 741 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( 742 const std::string& primary_key, 743 int64 version) 744 : primary_key_(primary_key), version_(version) { 745 DCHECK(!primary_key.empty()); 746 } 747 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier() 748 : primary_key_(), version_(-1) {} 749 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {} 750 751 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {} 752 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {} 753 754 enum IndexedDBBackingStoreOpenResult { 755 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, 756 INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, 757 INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, 758 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, 759 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, 760 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, 761 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, 762 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, 763 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, 764 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, 765 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, 766 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, 767 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, 768 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, 769 INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, 770 INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, 771 INDEXED_DB_BACKING_STORE_OPEN_MAX, 772 }; 773 774 // static 775 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( 776 IndexedDBFactory* indexed_db_factory, 777 const GURL& origin_url, 778 const base::FilePath& path_base, 779 net::URLRequestContext* request_context, 780 blink::WebIDBDataLoss* data_loss, 781 std::string* data_loss_message, 782 bool* disk_full, 783 base::SequencedTaskRunner* task_runner, 784 bool clean_journal, 785 leveldb::Status* status) { 786 *data_loss = blink::WebIDBDataLossNone; 787 DefaultLevelDBFactory leveldb_factory; 788 return IndexedDBBackingStore::Open(indexed_db_factory, 789 origin_url, 790 path_base, 791 request_context, 792 data_loss, 793 data_loss_message, 794 disk_full, 795 &leveldb_factory, 796 task_runner, 797 clean_journal, 798 status); 799 } 800 801 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { 802 if (origin_url.host() == "docs.google.com") 803 return ".Docs"; 804 return std::string(); 805 } 806 807 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, 808 const GURL& origin_url) { 809 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus", 810 result, 811 INDEXED_DB_BACKING_STORE_OPEN_MAX); 812 const std::string suffix = OriginToCustomHistogramSuffix(origin_url); 813 // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used 814 // to generate a graph. So as not to alter the meaning of that graph, 815 // continue to collect all stats there (above) but also now collect docs stats 816 // separately (below). 817 if (!suffix.empty()) { 818 base::LinearHistogram::FactoryGet( 819 "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix, 820 1, 821 INDEXED_DB_BACKING_STORE_OPEN_MAX, 822 INDEXED_DB_BACKING_STORE_OPEN_MAX + 1, 823 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result); 824 } 825 } 826 827 static bool IsPathTooLong(const base::FilePath& leveldb_dir) { 828 int limit = base::GetMaximumPathComponentLength(leveldb_dir.DirName()); 829 if (limit == -1) { 830 DLOG(WARNING) << "GetMaximumPathComponentLength returned -1"; 831 // In limited testing, ChromeOS returns 143, other OSes 255. 832 #if defined(OS_CHROMEOS) 833 limit = 143; 834 #else 835 limit = 255; 836 #endif 837 } 838 size_t component_length = leveldb_dir.BaseName().value().length(); 839 if (component_length > static_cast<uint32_t>(limit)) { 840 DLOG(WARNING) << "Path component length (" << component_length 841 << ") exceeds maximum (" << limit 842 << ") allowed by this filesystem."; 843 const int min = 140; 844 const int max = 300; 845 const int num_buckets = 12; 846 UMA_HISTOGRAM_CUSTOM_COUNTS( 847 "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength", 848 component_length, 849 min, 850 max, 851 num_buckets); 852 return true; 853 } 854 return false; 855 } 856 857 leveldb::Status IndexedDBBackingStore::DestroyBackingStore( 858 const base::FilePath& path_base, 859 const GURL& origin_url) { 860 const base::FilePath file_path = 861 path_base.Append(ComputeFileName(origin_url)); 862 DefaultLevelDBFactory leveldb_factory; 863 return leveldb_factory.DestroyLevelDB(file_path); 864 } 865 866 bool IndexedDBBackingStore::ReadCorruptionInfo(const base::FilePath& path_base, 867 const GURL& origin_url, 868 std::string* message) { 869 const base::FilePath info_path = 870 path_base.Append(ComputeCorruptionFileName(origin_url)); 871 872 if (IsPathTooLong(info_path)) 873 return false; 874 875 const int64 max_json_len = 4096; 876 int64 file_size(0); 877 if (!GetFileSize(info_path, &file_size) || file_size > max_json_len) 878 return false; 879 if (!file_size) { 880 NOTREACHED(); 881 return false; 882 } 883 884 base::File file(info_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 885 bool success = false; 886 if (file.IsValid()) { 887 std::vector<char> bytes(file_size); 888 if (file_size == file.Read(0, &bytes[0], file_size)) { 889 std::string input_js(&bytes[0], file_size); 890 base::JSONReader reader; 891 scoped_ptr<base::Value> val(reader.ReadToValue(input_js)); 892 if (val && val->GetType() == base::Value::TYPE_DICTIONARY) { 893 base::DictionaryValue* dict_val = 894 static_cast<base::DictionaryValue*>(val.get()); 895 success = dict_val->GetString("message", message); 896 } 897 } 898 file.Close(); 899 } 900 901 base::DeleteFile(info_path, false); 902 903 return success; 904 } 905 906 bool IndexedDBBackingStore::RecordCorruptionInfo( 907 const base::FilePath& path_base, 908 const GURL& origin_url, 909 const std::string& message) { 910 const base::FilePath info_path = 911 path_base.Append(ComputeCorruptionFileName(origin_url)); 912 if (IsPathTooLong(info_path)) 913 return false; 914 915 base::DictionaryValue root_dict; 916 root_dict.SetString("message", message); 917 std::string output_js; 918 base::JSONWriter::Write(&root_dict, &output_js); 919 920 base::File file(info_path, 921 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 922 if (!file.IsValid()) 923 return false; 924 int written = file.Write(0, output_js.c_str(), output_js.length()); 925 return size_t(written) == output_js.length(); 926 } 927 928 // static 929 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( 930 IndexedDBFactory* indexed_db_factory, 931 const GURL& origin_url, 932 const base::FilePath& path_base, 933 net::URLRequestContext* request_context, 934 blink::WebIDBDataLoss* data_loss, 935 std::string* data_loss_message, 936 bool* is_disk_full, 937 LevelDBFactory* leveldb_factory, 938 base::SequencedTaskRunner* task_runner, 939 bool clean_journal, 940 leveldb::Status* status) { 941 IDB_TRACE("IndexedDBBackingStore::Open"); 942 DCHECK(!path_base.empty()); 943 *data_loss = blink::WebIDBDataLossNone; 944 *data_loss_message = ""; 945 *is_disk_full = false; 946 947 *status = leveldb::Status::OK(); 948 949 scoped_ptr<LevelDBComparator> comparator(new Comparator()); 950 951 if (!base::IsStringASCII(path_base.AsUTF8Unsafe())) { 952 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, 953 origin_url); 954 } 955 if (!base::CreateDirectory(path_base)) { 956 *status = 957 leveldb::Status::IOError("Unable to create IndexedDB database path"); 958 LOG(ERROR) << status->ToString() << ": \"" << path_base.AsUTF8Unsafe() 959 << "\""; 960 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, 961 origin_url); 962 return scoped_refptr<IndexedDBBackingStore>(); 963 } 964 965 const base::FilePath file_path = 966 path_base.Append(ComputeFileName(origin_url)); 967 const base::FilePath blob_path = 968 path_base.Append(ComputeBlobPath(origin_url)); 969 970 if (IsPathTooLong(file_path)) { 971 *status = leveldb::Status::IOError("File path too long"); 972 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, 973 origin_url); 974 return scoped_refptr<IndexedDBBackingStore>(); 975 } 976 977 scoped_ptr<LevelDBDatabase> db; 978 *status = leveldb_factory->OpenLevelDB( 979 file_path, comparator.get(), &db, is_disk_full); 980 981 DCHECK(!db == !status->ok()); 982 if (!status->ok()) { 983 if (leveldb_env::IndicatesDiskFull(*status)) { 984 *is_disk_full = true; 985 } else if (leveldb_env::IsCorruption(*status)) { 986 *data_loss = blink::WebIDBDataLossTotal; 987 *data_loss_message = leveldb_env::GetCorruptionMessage(*status); 988 } 989 } 990 991 bool is_schema_known = false; 992 if (db) { 993 std::string corruption_message; 994 if (ReadCorruptionInfo(path_base, origin_url, &corruption_message)) { 995 LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) " 996 "database."; 997 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, 998 origin_url); 999 db.reset(); 1000 *data_loss = blink::WebIDBDataLossTotal; 1001 *data_loss_message = 1002 "IndexedDB (database was corrupt): " + corruption_message; 1003 } else if (!IsSchemaKnown(db.get(), &is_schema_known)) { 1004 LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as " 1005 "failure to open"; 1006 HistogramOpenStatus( 1007 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, 1008 origin_url); 1009 db.reset(); 1010 *data_loss = blink::WebIDBDataLossTotal; 1011 *data_loss_message = "I/O error checking schema"; 1012 } else if (!is_schema_known) { 1013 LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it " 1014 "as failure to open"; 1015 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, 1016 origin_url); 1017 db.reset(); 1018 *data_loss = blink::WebIDBDataLossTotal; 1019 *data_loss_message = "Unknown schema"; 1020 } 1021 } 1022 1023 DCHECK(status->ok() || !is_schema_known || leveldb_env::IsIOError(*status) || 1024 leveldb_env::IsCorruption(*status)); 1025 1026 if (db) { 1027 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url); 1028 } else if (leveldb_env::IsIOError(*status)) { 1029 LOG(ERROR) << "Unable to open backing store, not trying to recover - " 1030 << status->ToString(); 1031 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, origin_url); 1032 return scoped_refptr<IndexedDBBackingStore>(); 1033 } else { 1034 DCHECK(!is_schema_known || leveldb_env::IsCorruption(*status)); 1035 LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup"; 1036 *status = leveldb_factory->DestroyLevelDB(file_path); 1037 if (!status->ok()) { 1038 LOG(ERROR) << "IndexedDB backing store cleanup failed"; 1039 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, 1040 origin_url); 1041 return scoped_refptr<IndexedDBBackingStore>(); 1042 } 1043 1044 LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening"; 1045 leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, NULL); 1046 if (!db) { 1047 LOG(ERROR) << "IndexedDB backing store reopen after recovery failed"; 1048 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, 1049 origin_url); 1050 return scoped_refptr<IndexedDBBackingStore>(); 1051 } 1052 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, 1053 origin_url); 1054 } 1055 1056 if (!db) { 1057 NOTREACHED(); 1058 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, 1059 origin_url); 1060 return scoped_refptr<IndexedDBBackingStore>(); 1061 } 1062 1063 scoped_refptr<IndexedDBBackingStore> backing_store = 1064 Create(indexed_db_factory, 1065 origin_url, 1066 blob_path, 1067 request_context, 1068 db.Pass(), 1069 comparator.Pass(), 1070 task_runner, 1071 status); 1072 1073 if (clean_journal && backing_store.get() && 1074 !backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode()).ok()) { 1075 HistogramOpenStatus( 1076 INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, origin_url); 1077 return scoped_refptr<IndexedDBBackingStore>(); 1078 } 1079 return backing_store; 1080 } 1081 1082 // static 1083 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( 1084 const GURL& origin_url, 1085 base::SequencedTaskRunner* task_runner, 1086 leveldb::Status* status) { 1087 DefaultLevelDBFactory leveldb_factory; 1088 return IndexedDBBackingStore::OpenInMemory( 1089 origin_url, &leveldb_factory, task_runner, status); 1090 } 1091 1092 // static 1093 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( 1094 const GURL& origin_url, 1095 LevelDBFactory* leveldb_factory, 1096 base::SequencedTaskRunner* task_runner, 1097 leveldb::Status* status) { 1098 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); 1099 1100 scoped_ptr<LevelDBComparator> comparator(new Comparator()); 1101 scoped_ptr<LevelDBDatabase> db = 1102 LevelDBDatabase::OpenInMemory(comparator.get()); 1103 if (!db) { 1104 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; 1105 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, 1106 origin_url); 1107 return scoped_refptr<IndexedDBBackingStore>(); 1108 } 1109 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); 1110 1111 return Create(NULL /* indexed_db_factory */, 1112 origin_url, 1113 base::FilePath(), 1114 NULL /* request_context */, 1115 db.Pass(), 1116 comparator.Pass(), 1117 task_runner, 1118 status); 1119 } 1120 1121 // static 1122 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( 1123 IndexedDBFactory* indexed_db_factory, 1124 const GURL& origin_url, 1125 const base::FilePath& blob_path, 1126 net::URLRequestContext* request_context, 1127 scoped_ptr<LevelDBDatabase> db, 1128 scoped_ptr<LevelDBComparator> comparator, 1129 base::SequencedTaskRunner* task_runner, 1130 leveldb::Status* status) { 1131 // TODO(jsbell): Handle comparator name changes. 1132 scoped_refptr<IndexedDBBackingStore> backing_store( 1133 new IndexedDBBackingStore(indexed_db_factory, 1134 origin_url, 1135 blob_path, 1136 request_context, 1137 db.Pass(), 1138 comparator.Pass(), 1139 task_runner)); 1140 *status = backing_store->SetUpMetadata(); 1141 if (!status->ok()) 1142 return scoped_refptr<IndexedDBBackingStore>(); 1143 1144 return backing_store; 1145 } 1146 1147 void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) { 1148 if (!child_process_ids_granted_.count(child_process_id)) { 1149 child_process_ids_granted_.insert(child_process_id); 1150 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 1151 child_process_id, blob_path_); 1152 } 1153 } 1154 1155 std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames( 1156 leveldb::Status* s) { 1157 *s = leveldb::Status::OK(); 1158 std::vector<base::string16> found_names; 1159 const std::string start_key = 1160 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); 1161 const std::string stop_key = 1162 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); 1163 1164 DCHECK(found_names.empty()); 1165 1166 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 1167 for (*s = it->Seek(start_key); 1168 s->ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 1169 *s = it->Next()) { 1170 // Decode database name (in iterator key). 1171 StringPiece slice(it->Key()); 1172 DatabaseNameKey database_name_key; 1173 if (!DatabaseNameKey::Decode(&slice, &database_name_key) || 1174 !slice.empty()) { 1175 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES); 1176 continue; 1177 } 1178 1179 // Decode database id (in iterator value). 1180 int64 database_id = 0; 1181 StringPiece valueSlice(it->Value()); 1182 if (!DecodeInt(&valueSlice, &database_id) || !valueSlice.empty()) { 1183 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES); 1184 continue; 1185 } 1186 1187 // Look up version by id. 1188 bool found = false; 1189 int64 database_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; 1190 *s = GetVarInt(db_.get(), 1191 DatabaseMetaDataKey::Encode( 1192 database_id, DatabaseMetaDataKey::USER_INT_VERSION), 1193 &database_version, 1194 &found); 1195 if (!s->ok() || !found) { 1196 INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES); 1197 continue; 1198 } 1199 1200 // Ignore stale metadata from failed initial opens. 1201 if (database_version != IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) 1202 found_names.push_back(database_name_key.database_name()); 1203 } 1204 1205 if (!s->ok()) 1206 INTERNAL_READ_ERROR(GET_DATABASE_NAMES); 1207 1208 return found_names; 1209 } 1210 1211 leveldb::Status IndexedDBBackingStore::GetIDBDatabaseMetaData( 1212 const base::string16& name, 1213 IndexedDBDatabaseMetadata* metadata, 1214 bool* found) { 1215 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); 1216 *found = false; 1217 1218 leveldb::Status s = GetInt(db_.get(), key, &metadata->id, found); 1219 if (!s.ok()) { 1220 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); 1221 return s; 1222 } 1223 if (!*found) 1224 return leveldb::Status::OK(); 1225 1226 s = GetString(db_.get(), 1227 DatabaseMetaDataKey::Encode(metadata->id, 1228 DatabaseMetaDataKey::USER_VERSION), 1229 &metadata->version, 1230 found); 1231 if (!s.ok()) { 1232 INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1233 return s; 1234 } 1235 if (!*found) { 1236 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1237 return InternalInconsistencyStatus(); 1238 } 1239 1240 s = GetVarInt(db_.get(), 1241 DatabaseMetaDataKey::Encode( 1242 metadata->id, DatabaseMetaDataKey::USER_INT_VERSION), 1243 &metadata->int_version, 1244 found); 1245 if (!s.ok()) { 1246 INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1247 return s; 1248 } 1249 if (!*found) { 1250 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1251 return InternalInconsistencyStatus(); 1252 } 1253 1254 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) 1255 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; 1256 1257 s = GetMaxObjectStoreId( 1258 db_.get(), metadata->id, &metadata->max_object_store_id); 1259 if (!s.ok()) { 1260 INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1261 } 1262 1263 // We don't cache this, we just check it if it's there. 1264 int64 blob_key_generator_current_number = 1265 DatabaseMetaDataKey::kInvalidBlobKey; 1266 1267 s = GetVarInt( 1268 db_.get(), 1269 DatabaseMetaDataKey::Encode( 1270 metadata->id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), 1271 &blob_key_generator_current_number, 1272 found); 1273 if (!s.ok()) { 1274 INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1275 return s; 1276 } 1277 if (!*found) { 1278 // This database predates blob support. 1279 *found = true; 1280 } else if (!DatabaseMetaDataKey::IsValidBlobKey( 1281 blob_key_generator_current_number)) { 1282 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1283 return InternalInconsistencyStatus(); 1284 } 1285 1286 return s; 1287 } 1288 1289 WARN_UNUSED_RESULT static leveldb::Status GetNewDatabaseId( 1290 LevelDBTransaction* transaction, 1291 int64* new_id) { 1292 *new_id = -1; 1293 int64 max_database_id = -1; 1294 bool found = false; 1295 leveldb::Status s = 1296 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); 1297 if (!s.ok()) { 1298 INTERNAL_READ_ERROR_UNTESTED(GET_NEW_DATABASE_ID); 1299 return s; 1300 } 1301 if (!found) 1302 max_database_id = 0; 1303 1304 DCHECK_GE(max_database_id, 0); 1305 1306 int64 database_id = max_database_id + 1; 1307 PutInt(transaction, MaxDatabaseIdKey::Encode(), database_id); 1308 *new_id = database_id; 1309 return leveldb::Status::OK(); 1310 } 1311 1312 leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData( 1313 const base::string16& name, 1314 const base::string16& version, 1315 int64 int_version, 1316 int64* row_id) { 1317 // TODO(jsbell): Don't persist metadata if open fails. http://crbug.com/395472 1318 scoped_refptr<LevelDBTransaction> transaction = 1319 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); 1320 1321 leveldb::Status s = GetNewDatabaseId(transaction.get(), row_id); 1322 if (!s.ok()) 1323 return s; 1324 DCHECK_GE(*row_id, 0); 1325 1326 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 1327 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; 1328 1329 PutInt(transaction.get(), 1330 DatabaseNameKey::Encode(origin_identifier_, name), 1331 *row_id); 1332 PutString( 1333 transaction.get(), 1334 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), 1335 version); 1336 PutVarInt(transaction.get(), 1337 DatabaseMetaDataKey::Encode(*row_id, 1338 DatabaseMetaDataKey::USER_INT_VERSION), 1339 int_version); 1340 PutVarInt( 1341 transaction.get(), 1342 DatabaseMetaDataKey::Encode( 1343 *row_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER), 1344 DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber); 1345 1346 s = transaction->Commit(); 1347 if (!s.ok()) 1348 INTERNAL_WRITE_ERROR_UNTESTED(CREATE_IDBDATABASE_METADATA); 1349 return s; 1350 } 1351 1352 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( 1353 IndexedDBBackingStore::Transaction* transaction, 1354 int64 row_id, 1355 int64 int_version) { 1356 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 1357 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; 1358 DCHECK_GE(int_version, 0) << "int_version was " << int_version; 1359 PutVarInt(transaction->transaction(), 1360 DatabaseMetaDataKey::Encode(row_id, 1361 DatabaseMetaDataKey::USER_INT_VERSION), 1362 int_version); 1363 return true; 1364 } 1365 1366 // If you're deleting a range that contains user keys that have blob info, this 1367 // won't clean up the blobs. 1368 static leveldb::Status DeleteRangeBasic(LevelDBTransaction* transaction, 1369 const std::string& begin, 1370 const std::string& end, 1371 bool upper_open) { 1372 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); 1373 leveldb::Status s; 1374 for (s = it->Seek(begin); s.ok() && it->IsValid() && 1375 (upper_open ? CompareKeys(it->Key(), end) < 0 1376 : CompareKeys(it->Key(), end) <= 0); 1377 s = it->Next()) 1378 transaction->Remove(it->Key()); 1379 return s; 1380 } 1381 1382 static leveldb::Status DeleteBlobsInRange( 1383 IndexedDBBackingStore::Transaction* transaction, 1384 int64 database_id, 1385 int64 object_store_id, 1386 const std::string& start_key, 1387 const std::string& end_key, 1388 bool upper_open) { 1389 scoped_ptr<LevelDBIterator> it = transaction->transaction()->CreateIterator(); 1390 leveldb::Status s = it->Seek(start_key); 1391 for (; s.ok() && it->IsValid() && 1392 (upper_open ? CompareKeys(it->Key(), end_key) < 0 1393 : CompareKeys(it->Key(), end_key) <= 0); 1394 s = it->Next()) { 1395 StringPiece key_piece(it->Key()); 1396 std::string user_key = 1397 BlobEntryKey::ReencodeToObjectStoreDataKey(&key_piece); 1398 if (!user_key.size()) { 1399 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA); 1400 return InternalInconsistencyStatus(); 1401 } 1402 transaction->PutBlobInfo( 1403 database_id, object_store_id, user_key, NULL, NULL); 1404 } 1405 return s; 1406 } 1407 1408 static leveldb::Status DeleteBlobsInObjectStore( 1409 IndexedDBBackingStore::Transaction* transaction, 1410 int64 database_id, 1411 int64 object_store_id) { 1412 std::string start_key, stop_key; 1413 start_key = 1414 BlobEntryKey::EncodeMinKeyForObjectStore(database_id, object_store_id); 1415 stop_key = 1416 BlobEntryKey::EncodeStopKeyForObjectStore(database_id, object_store_id); 1417 return DeleteBlobsInRange( 1418 transaction, database_id, object_store_id, start_key, stop_key, true); 1419 } 1420 1421 leveldb::Status IndexedDBBackingStore::DeleteDatabase( 1422 const base::string16& name) { 1423 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); 1424 scoped_ptr<LevelDBDirectTransaction> transaction = 1425 LevelDBDirectTransaction::Create(db_.get()); 1426 1427 leveldb::Status s; 1428 s = CleanUpBlobJournal(BlobJournalKey::Encode()); 1429 if (!s.ok()) 1430 return s; 1431 1432 IndexedDBDatabaseMetadata metadata; 1433 bool success = false; 1434 s = GetIDBDatabaseMetaData(name, &metadata, &success); 1435 if (!s.ok()) 1436 return s; 1437 if (!success) 1438 return leveldb::Status::OK(); 1439 1440 const std::string start_key = DatabaseMetaDataKey::Encode( 1441 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); 1442 const std::string stop_key = DatabaseMetaDataKey::Encode( 1443 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); 1444 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 1445 for (s = it->Seek(start_key); 1446 s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 1447 s = it->Next()) 1448 transaction->Remove(it->Key()); 1449 if (!s.ok()) { 1450 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); 1451 return s; 1452 } 1453 1454 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); 1455 transaction->Remove(key); 1456 1457 bool need_cleanup = false; 1458 if (active_blob_registry()->MarkDeletedCheckIfUsed( 1459 metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) { 1460 s = MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id); 1461 if (!s.ok()) 1462 return s; 1463 } else { 1464 UpdateBlobJournalWithDatabase(transaction.get(), metadata.id); 1465 need_cleanup = true; 1466 } 1467 1468 s = transaction->Commit(); 1469 if (!s.ok()) { 1470 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE); 1471 return s; 1472 } 1473 1474 if (need_cleanup) 1475 CleanUpBlobJournal(BlobJournalKey::Encode()); 1476 1477 db_->Compact(start_key, stop_key); 1478 return s; 1479 } 1480 1481 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, 1482 const std::string& stop_key, 1483 int64 object_store_id, 1484 int64 meta_data_type) { 1485 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 1486 return false; 1487 1488 StringPiece slice(it->Key()); 1489 ObjectStoreMetaDataKey meta_data_key; 1490 bool ok = 1491 ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty(); 1492 DCHECK(ok); 1493 if (meta_data_key.ObjectStoreId() != object_store_id) 1494 return false; 1495 if (meta_data_key.MetaDataType() != meta_data_type) 1496 return false; 1497 return ok; 1498 } 1499 1500 // TODO(jsbell): This should do some error handling rather than 1501 // plowing ahead when bad data is encountered. 1502 leveldb::Status IndexedDBBackingStore::GetObjectStores( 1503 int64 database_id, 1504 IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) { 1505 IDB_TRACE("IndexedDBBackingStore::GetObjectStores"); 1506 if (!KeyPrefix::IsValidDatabaseId(database_id)) 1507 return InvalidDBKeyStatus(); 1508 const std::string start_key = 1509 ObjectStoreMetaDataKey::Encode(database_id, 1, 0); 1510 const std::string stop_key = 1511 ObjectStoreMetaDataKey::EncodeMaxKey(database_id); 1512 1513 DCHECK(object_stores->empty()); 1514 1515 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 1516 leveldb::Status s = it->Seek(start_key); 1517 while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 1518 StringPiece slice(it->Key()); 1519 ObjectStoreMetaDataKey meta_data_key; 1520 bool ok = 1521 ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty(); 1522 DCHECK(ok); 1523 if (!ok || meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) { 1524 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1525 // Possible stale metadata, but don't fail the load. 1526 s = it->Next(); 1527 if (!s.ok()) 1528 break; 1529 continue; 1530 } 1531 1532 int64 object_store_id = meta_data_key.ObjectStoreId(); 1533 1534 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 1535 // simplify. 1536 base::string16 object_store_name; 1537 { 1538 StringPiece slice(it->Value()); 1539 if (!DecodeString(&slice, &object_store_name) || !slice.empty()) 1540 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1541 } 1542 1543 s = it->Next(); 1544 if (!s.ok()) 1545 break; 1546 if (!CheckObjectStoreAndMetaDataType(it.get(), 1547 stop_key, 1548 object_store_id, 1549 ObjectStoreMetaDataKey::KEY_PATH)) { 1550 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1551 break; 1552 } 1553 IndexedDBKeyPath key_path; 1554 { 1555 StringPiece slice(it->Value()); 1556 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 1557 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1558 } 1559 1560 s = it->Next(); 1561 if (!s.ok()) 1562 break; 1563 if (!CheckObjectStoreAndMetaDataType( 1564 it.get(), 1565 stop_key, 1566 object_store_id, 1567 ObjectStoreMetaDataKey::AUTO_INCREMENT)) { 1568 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1569 break; 1570 } 1571 bool auto_increment; 1572 { 1573 StringPiece slice(it->Value()); 1574 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) 1575 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1576 } 1577 1578 s = it->Next(); // Is evictable. 1579 if (!s.ok()) 1580 break; 1581 if (!CheckObjectStoreAndMetaDataType(it.get(), 1582 stop_key, 1583 object_store_id, 1584 ObjectStoreMetaDataKey::EVICTABLE)) { 1585 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1586 break; 1587 } 1588 1589 s = it->Next(); // Last version. 1590 if (!s.ok()) 1591 break; 1592 if (!CheckObjectStoreAndMetaDataType( 1593 it.get(), 1594 stop_key, 1595 object_store_id, 1596 ObjectStoreMetaDataKey::LAST_VERSION)) { 1597 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1598 break; 1599 } 1600 1601 s = it->Next(); // Maximum index id allocated. 1602 if (!s.ok()) 1603 break; 1604 if (!CheckObjectStoreAndMetaDataType( 1605 it.get(), 1606 stop_key, 1607 object_store_id, 1608 ObjectStoreMetaDataKey::MAX_INDEX_ID)) { 1609 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1610 break; 1611 } 1612 int64 max_index_id; 1613 { 1614 StringPiece slice(it->Value()); 1615 if (!DecodeInt(&slice, &max_index_id) || !slice.empty()) 1616 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1617 } 1618 1619 s = it->Next(); // [optional] has key path (is not null) 1620 if (!s.ok()) 1621 break; 1622 if (CheckObjectStoreAndMetaDataType(it.get(), 1623 stop_key, 1624 object_store_id, 1625 ObjectStoreMetaDataKey::HAS_KEY_PATH)) { 1626 bool has_key_path; 1627 { 1628 StringPiece slice(it->Value()); 1629 if (!DecodeBool(&slice, &has_key_path)) 1630 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1631 } 1632 // This check accounts for two layers of legacy coding: 1633 // (1) Initially, has_key_path was added to distinguish null vs. string. 1634 // (2) Later, null vs. string vs. array was stored in the key_path itself. 1635 // So this check is only relevant for string-type key_paths. 1636 if (!has_key_path && 1637 (key_path.type() == blink::WebIDBKeyPathTypeString && 1638 !key_path.string().empty())) { 1639 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1640 break; 1641 } 1642 if (!has_key_path) 1643 key_path = IndexedDBKeyPath(); 1644 s = it->Next(); 1645 if (!s.ok()) 1646 break; 1647 } 1648 1649 int64 key_generator_current_number = -1; 1650 if (CheckObjectStoreAndMetaDataType( 1651 it.get(), 1652 stop_key, 1653 object_store_id, 1654 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) { 1655 StringPiece slice(it->Value()); 1656 if (!DecodeInt(&slice, &key_generator_current_number) || !slice.empty()) 1657 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES); 1658 1659 // TODO(jsbell): Return key_generator_current_number, cache in 1660 // object store, and write lazily to backing store. For now, 1661 // just assert that if it was written it was valid. 1662 DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber); 1663 s = it->Next(); 1664 if (!s.ok()) 1665 break; 1666 } 1667 1668 IndexedDBObjectStoreMetadata metadata(object_store_name, 1669 object_store_id, 1670 key_path, 1671 auto_increment, 1672 max_index_id); 1673 s = GetIndexes(database_id, object_store_id, &metadata.indexes); 1674 if (!s.ok()) 1675 break; 1676 (*object_stores)[object_store_id] = metadata; 1677 } 1678 1679 if (!s.ok()) 1680 INTERNAL_READ_ERROR_UNTESTED(GET_OBJECT_STORES); 1681 1682 return s; 1683 } 1684 1685 WARN_UNUSED_RESULT static leveldb::Status SetMaxObjectStoreId( 1686 LevelDBTransaction* transaction, 1687 int64 database_id, 1688 int64 object_store_id) { 1689 const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode( 1690 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); 1691 int64 max_object_store_id = -1; 1692 leveldb::Status s = GetMaxObjectStoreId( 1693 transaction, max_object_store_id_key, &max_object_store_id); 1694 if (!s.ok()) { 1695 INTERNAL_READ_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID); 1696 return s; 1697 } 1698 1699 if (object_store_id <= max_object_store_id) { 1700 INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID); 1701 return InternalInconsistencyStatus(); 1702 } 1703 PutInt(transaction, max_object_store_id_key, object_store_id); 1704 return s; 1705 } 1706 1707 void IndexedDBBackingStore::Compact() { db_->CompactAll(); } 1708 1709 leveldb::Status IndexedDBBackingStore::CreateObjectStore( 1710 IndexedDBBackingStore::Transaction* transaction, 1711 int64 database_id, 1712 int64 object_store_id, 1713 const base::string16& name, 1714 const IndexedDBKeyPath& key_path, 1715 bool auto_increment) { 1716 IDB_TRACE("IndexedDBBackingStore::CreateObjectStore"); 1717 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1718 return InvalidDBKeyStatus(); 1719 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1720 leveldb::Status s = 1721 SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id); 1722 if (!s.ok()) 1723 return s; 1724 1725 const std::string name_key = ObjectStoreMetaDataKey::Encode( 1726 database_id, object_store_id, ObjectStoreMetaDataKey::NAME); 1727 const std::string key_path_key = ObjectStoreMetaDataKey::Encode( 1728 database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH); 1729 const std::string auto_increment_key = ObjectStoreMetaDataKey::Encode( 1730 database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT); 1731 const std::string evictable_key = ObjectStoreMetaDataKey::Encode( 1732 database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE); 1733 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1734 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1735 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 1736 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 1737 const std::string has_key_path_key = ObjectStoreMetaDataKey::Encode( 1738 database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH); 1739 const std::string key_generator_current_number_key = 1740 ObjectStoreMetaDataKey::Encode( 1741 database_id, 1742 object_store_id, 1743 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1744 const std::string names_key = ObjectStoreNamesKey::Encode(database_id, name); 1745 1746 PutString(leveldb_transaction, name_key, name); 1747 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 1748 PutInt(leveldb_transaction, auto_increment_key, auto_increment); 1749 PutInt(leveldb_transaction, evictable_key, false); 1750 PutInt(leveldb_transaction, last_version_key, 1); 1751 PutInt(leveldb_transaction, max_index_id_key, kMinimumIndexId); 1752 PutBool(leveldb_transaction, has_key_path_key, !key_path.IsNull()); 1753 PutInt(leveldb_transaction, 1754 key_generator_current_number_key, 1755 kKeyGeneratorInitialNumber); 1756 PutInt(leveldb_transaction, names_key, object_store_id); 1757 return s; 1758 } 1759 1760 leveldb::Status IndexedDBBackingStore::DeleteObjectStore( 1761 IndexedDBBackingStore::Transaction* transaction, 1762 int64 database_id, 1763 int64 object_store_id) { 1764 IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore"); 1765 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1766 return InvalidDBKeyStatus(); 1767 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1768 1769 base::string16 object_store_name; 1770 bool found = false; 1771 leveldb::Status s = 1772 GetString(leveldb_transaction, 1773 ObjectStoreMetaDataKey::Encode( 1774 database_id, object_store_id, ObjectStoreMetaDataKey::NAME), 1775 &object_store_name, 1776 &found); 1777 if (!s.ok()) { 1778 INTERNAL_READ_ERROR_UNTESTED(DELETE_OBJECT_STORE); 1779 return s; 1780 } 1781 if (!found) { 1782 INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE); 1783 return InternalInconsistencyStatus(); 1784 } 1785 1786 s = DeleteBlobsInObjectStore(transaction, database_id, object_store_id); 1787 if (!s.ok()) { 1788 INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE); 1789 return s; 1790 } 1791 1792 s = DeleteRangeBasic( 1793 leveldb_transaction, 1794 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), 1795 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id), 1796 true); 1797 1798 if (s.ok()) { 1799 leveldb_transaction->Remove( 1800 ObjectStoreNamesKey::Encode(database_id, object_store_name)); 1801 1802 s = DeleteRangeBasic( 1803 leveldb_transaction, 1804 IndexFreeListKey::Encode(database_id, object_store_id, 0), 1805 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id), 1806 true); 1807 } 1808 1809 if (s.ok()) { 1810 s = DeleteRangeBasic( 1811 leveldb_transaction, 1812 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), 1813 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id), 1814 true); 1815 } 1816 1817 if (!s.ok()) { 1818 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_OBJECT_STORE); 1819 return s; 1820 } 1821 1822 return ClearObjectStore(transaction, database_id, object_store_id); 1823 } 1824 1825 leveldb::Status IndexedDBBackingStore::GetRecord( 1826 IndexedDBBackingStore::Transaction* transaction, 1827 int64 database_id, 1828 int64 object_store_id, 1829 const IndexedDBKey& key, 1830 IndexedDBValue* record) { 1831 IDB_TRACE("IndexedDBBackingStore::GetRecord"); 1832 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1833 return InvalidDBKeyStatus(); 1834 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1835 1836 const std::string leveldb_key = 1837 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1838 std::string data; 1839 1840 record->clear(); 1841 1842 bool found = false; 1843 leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found); 1844 if (!s.ok()) { 1845 INTERNAL_READ_ERROR(GET_RECORD); 1846 return s; 1847 } 1848 if (!found) 1849 return s; 1850 if (data.empty()) { 1851 INTERNAL_READ_ERROR_UNTESTED(GET_RECORD); 1852 return leveldb::Status::NotFound("Record contained no data"); 1853 } 1854 1855 int64 version; 1856 StringPiece slice(data); 1857 if (!DecodeVarInt(&slice, &version)) { 1858 INTERNAL_READ_ERROR_UNTESTED(GET_RECORD); 1859 return InternalInconsistencyStatus(); 1860 } 1861 1862 record->bits = slice.as_string(); 1863 return transaction->GetBlobInfoForRecord(database_id, leveldb_key, record); 1864 } 1865 1866 WARN_UNUSED_RESULT static leveldb::Status GetNewVersionNumber( 1867 LevelDBTransaction* transaction, 1868 int64 database_id, 1869 int64 object_store_id, 1870 int64* new_version_number) { 1871 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1872 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1873 1874 *new_version_number = -1; 1875 int64 last_version = -1; 1876 bool found = false; 1877 leveldb::Status s = 1878 GetInt(transaction, last_version_key, &last_version, &found); 1879 if (!s.ok()) { 1880 INTERNAL_READ_ERROR_UNTESTED(GET_NEW_VERSION_NUMBER); 1881 return s; 1882 } 1883 if (!found) 1884 last_version = 0; 1885 1886 DCHECK_GE(last_version, 0); 1887 1888 int64 version = last_version + 1; 1889 PutInt(transaction, last_version_key, version); 1890 1891 // TODO(jsbell): Think about how we want to handle the overflow scenario. 1892 DCHECK(version > last_version); 1893 1894 *new_version_number = version; 1895 return s; 1896 } 1897 1898 leveldb::Status IndexedDBBackingStore::PutRecord( 1899 IndexedDBBackingStore::Transaction* transaction, 1900 int64 database_id, 1901 int64 object_store_id, 1902 const IndexedDBKey& key, 1903 IndexedDBValue* value, 1904 ScopedVector<storage::BlobDataHandle>* handles, 1905 RecordIdentifier* record_identifier) { 1906 IDB_TRACE("IndexedDBBackingStore::PutRecord"); 1907 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1908 return InvalidDBKeyStatus(); 1909 DCHECK(key.IsValid()); 1910 1911 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1912 int64 version = -1; 1913 leveldb::Status s = GetNewVersionNumber( 1914 leveldb_transaction, database_id, object_store_id, &version); 1915 if (!s.ok()) 1916 return s; 1917 DCHECK_GE(version, 0); 1918 const std::string object_store_data_key = 1919 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1920 1921 std::string v; 1922 EncodeVarInt(version, &v); 1923 v.append(value->bits); 1924 1925 leveldb_transaction->Put(object_store_data_key, &v); 1926 s = transaction->PutBlobInfoIfNeeded(database_id, 1927 object_store_id, 1928 object_store_data_key, 1929 &value->blob_info, 1930 handles); 1931 if (!s.ok()) 1932 return s; 1933 DCHECK(!handles->size()); 1934 1935 const std::string exists_entry_key = 1936 ExistsEntryKey::Encode(database_id, object_store_id, key); 1937 std::string version_encoded; 1938 EncodeInt(version, &version_encoded); 1939 leveldb_transaction->Put(exists_entry_key, &version_encoded); 1940 1941 std::string key_encoded; 1942 EncodeIDBKey(key, &key_encoded); 1943 record_identifier->Reset(key_encoded, version); 1944 return s; 1945 } 1946 1947 leveldb::Status IndexedDBBackingStore::ClearObjectStore( 1948 IndexedDBBackingStore::Transaction* transaction, 1949 int64 database_id, 1950 int64 object_store_id) { 1951 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); 1952 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1953 return InvalidDBKeyStatus(); 1954 const std::string start_key = 1955 KeyPrefix(database_id, object_store_id).Encode(); 1956 const std::string stop_key = 1957 KeyPrefix(database_id, object_store_id + 1).Encode(); 1958 1959 leveldb::Status s = 1960 DeleteRangeBasic(transaction->transaction(), start_key, stop_key, true); 1961 if (!s.ok()) { 1962 INTERNAL_WRITE_ERROR(CLEAR_OBJECT_STORE); 1963 return s; 1964 } 1965 return DeleteBlobsInObjectStore(transaction, database_id, object_store_id); 1966 } 1967 1968 leveldb::Status IndexedDBBackingStore::DeleteRecord( 1969 IndexedDBBackingStore::Transaction* transaction, 1970 int64 database_id, 1971 int64 object_store_id, 1972 const RecordIdentifier& record_identifier) { 1973 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); 1974 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1975 return InvalidDBKeyStatus(); 1976 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1977 1978 const std::string object_store_data_key = ObjectStoreDataKey::Encode( 1979 database_id, object_store_id, record_identifier.primary_key()); 1980 leveldb_transaction->Remove(object_store_data_key); 1981 leveldb::Status s = transaction->PutBlobInfoIfNeeded( 1982 database_id, object_store_id, object_store_data_key, NULL, NULL); 1983 if (!s.ok()) 1984 return s; 1985 1986 const std::string exists_entry_key = ExistsEntryKey::Encode( 1987 database_id, object_store_id, record_identifier.primary_key()); 1988 leveldb_transaction->Remove(exists_entry_key); 1989 return leveldb::Status::OK(); 1990 } 1991 1992 leveldb::Status IndexedDBBackingStore::DeleteRange( 1993 IndexedDBBackingStore::Transaction* transaction, 1994 int64 database_id, 1995 int64 object_store_id, 1996 const IndexedDBKeyRange& key_range) { 1997 leveldb::Status s; 1998 scoped_ptr<IndexedDBBackingStore::Cursor> start_cursor = 1999 OpenObjectStoreCursor(transaction, 2000 database_id, 2001 object_store_id, 2002 key_range, 2003 blink::WebIDBCursorDirectionNext, 2004 &s); 2005 if (!s.ok()) 2006 return s; 2007 if (!start_cursor) 2008 return leveldb::Status::OK(); // Empty range == delete success. 2009 2010 scoped_ptr<IndexedDBBackingStore::Cursor> end_cursor = 2011 OpenObjectStoreCursor(transaction, 2012 database_id, 2013 object_store_id, 2014 key_range, 2015 blink::WebIDBCursorDirectionPrev, 2016 &s); 2017 2018 if (!s.ok()) 2019 return s; 2020 if (!end_cursor) 2021 return leveldb::Status::OK(); // Empty range == delete success. 2022 2023 BlobEntryKey start_blob_key, end_blob_key; 2024 2025 std::string start_key = ObjectStoreDataKey::Encode( 2026 database_id, object_store_id, start_cursor->key()); 2027 base::StringPiece start_key_piece(start_key); 2028 if (!BlobEntryKey::FromObjectStoreDataKey(&start_key_piece, &start_blob_key)) 2029 return InternalInconsistencyStatus(); 2030 std::string stop_key = ObjectStoreDataKey::Encode( 2031 database_id, object_store_id, end_cursor->key()); 2032 base::StringPiece stop_key_piece(stop_key); 2033 if (!BlobEntryKey::FromObjectStoreDataKey(&stop_key_piece, &end_blob_key)) 2034 return InternalInconsistencyStatus(); 2035 2036 s = DeleteBlobsInRange(transaction, 2037 database_id, 2038 object_store_id, 2039 start_blob_key.Encode(), 2040 end_blob_key.Encode(), 2041 false); 2042 if (!s.ok()) 2043 return s; 2044 s = DeleteRangeBasic(transaction->transaction(), start_key, stop_key, false); 2045 if (!s.ok()) 2046 return s; 2047 start_key = 2048 ExistsEntryKey::Encode(database_id, object_store_id, start_cursor->key()); 2049 stop_key = 2050 ExistsEntryKey::Encode(database_id, object_store_id, end_cursor->key()); 2051 return DeleteRangeBasic( 2052 transaction->transaction(), start_key, stop_key, false); 2053 } 2054 2055 leveldb::Status IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( 2056 IndexedDBBackingStore::Transaction* transaction, 2057 int64 database_id, 2058 int64 object_store_id, 2059 int64* key_generator_current_number) { 2060 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 2061 return InvalidDBKeyStatus(); 2062 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2063 2064 const std::string key_generator_current_number_key = 2065 ObjectStoreMetaDataKey::Encode( 2066 database_id, 2067 object_store_id, 2068 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 2069 2070 *key_generator_current_number = -1; 2071 std::string data; 2072 2073 bool found = false; 2074 leveldb::Status s = 2075 leveldb_transaction->Get(key_generator_current_number_key, &data, &found); 2076 if (!s.ok()) { 2077 INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER); 2078 return s; 2079 } 2080 if (found && !data.empty()) { 2081 StringPiece slice(data); 2082 if (!DecodeInt(&slice, key_generator_current_number) || !slice.empty()) { 2083 INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER); 2084 return InternalInconsistencyStatus(); 2085 } 2086 return s; 2087 } 2088 2089 // Previously, the key generator state was not stored explicitly 2090 // but derived from the maximum numeric key present in existing 2091 // data. This violates the spec as the data may be cleared but the 2092 // key generator state must be preserved. 2093 // TODO(jsbell): Fix this for all stores on database open? 2094 const std::string start_key = 2095 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 2096 const std::string stop_key = 2097 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 2098 2099 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 2100 int64 max_numeric_key = 0; 2101 2102 for (s = it->Seek(start_key); 2103 s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 2104 s = it->Next()) { 2105 StringPiece slice(it->Key()); 2106 ObjectStoreDataKey data_key; 2107 if (!ObjectStoreDataKey::Decode(&slice, &data_key) || !slice.empty()) { 2108 INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER); 2109 return InternalInconsistencyStatus(); 2110 } 2111 scoped_ptr<IndexedDBKey> user_key = data_key.user_key(); 2112 if (user_key->type() == blink::WebIDBKeyTypeNumber) { 2113 int64 n = static_cast<int64>(user_key->number()); 2114 if (n > max_numeric_key) 2115 max_numeric_key = n; 2116 } 2117 } 2118 2119 if (s.ok()) 2120 *key_generator_current_number = max_numeric_key + 1; 2121 else 2122 INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER); 2123 2124 return s; 2125 } 2126 2127 leveldb::Status IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber( 2128 IndexedDBBackingStore::Transaction* transaction, 2129 int64 database_id, 2130 int64 object_store_id, 2131 int64 new_number, 2132 bool check_current) { 2133 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 2134 return InvalidDBKeyStatus(); 2135 2136 if (check_current) { 2137 int64 current_number; 2138 leveldb::Status s = GetKeyGeneratorCurrentNumber( 2139 transaction, database_id, object_store_id, ¤t_number); 2140 if (!s.ok()) 2141 return s; 2142 if (new_number <= current_number) 2143 return s; 2144 } 2145 2146 const std::string key_generator_current_number_key = 2147 ObjectStoreMetaDataKey::Encode( 2148 database_id, 2149 object_store_id, 2150 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 2151 PutInt( 2152 transaction->transaction(), key_generator_current_number_key, new_number); 2153 return leveldb::Status::OK(); 2154 } 2155 2156 leveldb::Status IndexedDBBackingStore::KeyExistsInObjectStore( 2157 IndexedDBBackingStore::Transaction* transaction, 2158 int64 database_id, 2159 int64 object_store_id, 2160 const IndexedDBKey& key, 2161 RecordIdentifier* found_record_identifier, 2162 bool* found) { 2163 IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore"); 2164 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 2165 return InvalidDBKeyStatus(); 2166 *found = false; 2167 const std::string leveldb_key = 2168 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 2169 std::string data; 2170 2171 leveldb::Status s = 2172 transaction->transaction()->Get(leveldb_key, &data, found); 2173 if (!s.ok()) { 2174 INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE); 2175 return s; 2176 } 2177 if (!*found) 2178 return leveldb::Status::OK(); 2179 if (!data.size()) { 2180 INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE); 2181 return InternalInconsistencyStatus(); 2182 } 2183 2184 int64 version; 2185 StringPiece slice(data); 2186 if (!DecodeVarInt(&slice, &version)) 2187 return InternalInconsistencyStatus(); 2188 2189 std::string encoded_key; 2190 EncodeIDBKey(key, &encoded_key); 2191 found_record_identifier->Reset(encoded_key, version); 2192 return s; 2193 } 2194 2195 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl 2196 : public IndexedDBBackingStore::Transaction::ChainedBlobWriter { 2197 public: 2198 typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec 2199 WriteDescriptorVec; 2200 ChainedBlobWriterImpl( 2201 int64 database_id, 2202 IndexedDBBackingStore* backing_store, 2203 WriteDescriptorVec* blobs, 2204 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback) 2205 : waiting_for_callback_(false), 2206 database_id_(database_id), 2207 backing_store_(backing_store), 2208 callback_(callback), 2209 aborted_(false) { 2210 blobs_.swap(*blobs); 2211 iter_ = blobs_.begin(); 2212 backing_store->task_runner()->PostTask( 2213 FROM_HERE, base::Bind(&ChainedBlobWriterImpl::WriteNextFile, this)); 2214 } 2215 2216 virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE { 2217 delegate_.reset(delegate.release()); 2218 } 2219 2220 virtual void ReportWriteCompletion(bool succeeded, 2221 int64 bytes_written) OVERRIDE { 2222 DCHECK(waiting_for_callback_); 2223 DCHECK(!succeeded || bytes_written >= 0); 2224 waiting_for_callback_ = false; 2225 if (delegate_.get()) // Only present for Blob, not File. 2226 content::BrowserThread::DeleteSoon( 2227 content::BrowserThread::IO, FROM_HERE, delegate_.release()); 2228 if (aborted_) { 2229 self_ref_ = NULL; 2230 return; 2231 } 2232 if (iter_->size() != -1 && iter_->size() != bytes_written) 2233 succeeded = false; 2234 if (succeeded) { 2235 ++iter_; 2236 WriteNextFile(); 2237 } else { 2238 callback_->Run(false); 2239 } 2240 } 2241 2242 virtual void Abort() OVERRIDE { 2243 if (!waiting_for_callback_) 2244 return; 2245 self_ref_ = this; 2246 aborted_ = true; 2247 } 2248 2249 private: 2250 virtual ~ChainedBlobWriterImpl() {} 2251 2252 void WriteNextFile() { 2253 DCHECK(!waiting_for_callback_); 2254 DCHECK(!aborted_); 2255 if (iter_ == blobs_.end()) { 2256 DCHECK(!self_ref_.get()); 2257 callback_->Run(true); 2258 return; 2259 } else { 2260 if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) { 2261 callback_->Run(false); 2262 return; 2263 } 2264 waiting_for_callback_ = true; 2265 } 2266 } 2267 2268 bool waiting_for_callback_; 2269 scoped_refptr<ChainedBlobWriterImpl> self_ref_; 2270 WriteDescriptorVec blobs_; 2271 WriteDescriptorVec::const_iterator iter_; 2272 int64 database_id_; 2273 IndexedDBBackingStore* backing_store_; 2274 scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_; 2275 scoped_ptr<FileWriterDelegate> delegate_; 2276 bool aborted_; 2277 2278 DISALLOW_COPY_AND_ASSIGN(ChainedBlobWriterImpl); 2279 }; 2280 2281 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback, 2282 public base::RefCountedThreadSafe<LocalWriteClosure> { 2283 public: 2284 LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter* 2285 chained_blob_writer, 2286 base::SequencedTaskRunner* task_runner) 2287 : chained_blob_writer_(chained_blob_writer), 2288 task_runner_(task_runner), 2289 bytes_written_(0) {} 2290 2291 void Run(base::File::Error rv, 2292 int64 bytes, 2293 FileWriterDelegate::WriteProgressStatus write_status) { 2294 DCHECK_GE(bytes, 0); 2295 bytes_written_ += bytes; 2296 if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING) 2297 return; // We don't care about progress events. 2298 if (rv == base::File::FILE_OK) { 2299 DCHECK_EQ(write_status, FileWriterDelegate::SUCCESS_COMPLETED); 2300 } else { 2301 DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED || 2302 write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED); 2303 } 2304 task_runner_->PostTask( 2305 FROM_HERE, 2306 base::Bind(&IndexedDBBackingStore::Transaction::ChainedBlobWriter:: 2307 ReportWriteCompletion, 2308 chained_blob_writer_, 2309 write_status == FileWriterDelegate::SUCCESS_COMPLETED, 2310 bytes_written_)); 2311 } 2312 2313 void writeBlobToFileOnIOThread(const FilePath& file_path, 2314 const GURL& blob_url, 2315 net::URLRequestContext* request_context) { 2316 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 2317 scoped_ptr<storage::FileStreamWriter> writer( 2318 storage::FileStreamWriter::CreateForLocalFile( 2319 task_runner_.get(), 2320 file_path, 2321 0, 2322 storage::FileStreamWriter::CREATE_NEW_FILE)); 2323 scoped_ptr<FileWriterDelegate> delegate( 2324 new FileWriterDelegate(writer.Pass(), 2325 FileWriterDelegate::FLUSH_ON_COMPLETION)); 2326 2327 DCHECK(blob_url.is_valid()); 2328 scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest( 2329 blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL)); 2330 2331 delegate->Start(blob_request.Pass(), 2332 base::Bind(&LocalWriteClosure::Run, this)); 2333 chained_blob_writer_->set_delegate(delegate.Pass()); 2334 } 2335 2336 private: 2337 virtual ~LocalWriteClosure() { 2338 // Make sure the last reference to a ChainedBlobWriter is released (and 2339 // deleted) on the IDB thread since it owns a transaction which has thread 2340 // affinity. 2341 IndexedDBBackingStore::Transaction::ChainedBlobWriter* raw_tmp = 2342 chained_blob_writer_.get(); 2343 raw_tmp->AddRef(); 2344 chained_blob_writer_ = NULL; 2345 task_runner_->ReleaseSoon(FROM_HERE, raw_tmp); 2346 } 2347 friend class base::RefCountedThreadSafe<LocalWriteClosure>; 2348 2349 scoped_refptr<IndexedDBBackingStore::Transaction::ChainedBlobWriter> 2350 chained_blob_writer_; 2351 scoped_refptr<base::SequencedTaskRunner> task_runner_; 2352 int64 bytes_written_; 2353 2354 DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure); 2355 }; 2356 2357 bool IndexedDBBackingStore::WriteBlobFile( 2358 int64 database_id, 2359 const Transaction::WriteDescriptor& descriptor, 2360 Transaction::ChainedBlobWriter* chained_blob_writer) { 2361 2362 if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) 2363 return false; 2364 2365 FilePath path = GetBlobFileName(database_id, descriptor.key()); 2366 2367 if (descriptor.is_file()) { 2368 DCHECK(!descriptor.file_path().empty()); 2369 if (!base::CopyFile(descriptor.file_path(), path)) 2370 return false; 2371 2372 base::File::Info info; 2373 if (base::GetFileInfo(descriptor.file_path(), &info)) { 2374 if (descriptor.size() != -1) { 2375 if (descriptor.size() != info.size) 2376 return false; 2377 // The round-trip can be lossy; round to nearest millisecond. 2378 int64 delta = (descriptor.last_modified() - 2379 info.last_modified).InMilliseconds(); 2380 if (std::abs(delta) > 1) 2381 return false; 2382 } 2383 if (!base::TouchFile(path, info.last_accessed, info.last_modified)) { 2384 // TODO(ericu): Complain quietly; timestamp's probably not vital. 2385 } 2386 } else { 2387 // TODO(ericu): Complain quietly; timestamp's probably not vital. 2388 } 2389 2390 task_runner_->PostTask( 2391 FROM_HERE, 2392 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, 2393 chained_blob_writer, 2394 true, 2395 info.size)); 2396 } else { 2397 DCHECK(descriptor.url().is_valid()); 2398 scoped_refptr<LocalWriteClosure> write_closure( 2399 new LocalWriteClosure(chained_blob_writer, task_runner_.get())); 2400 content::BrowserThread::PostTask( 2401 content::BrowserThread::IO, 2402 FROM_HERE, 2403 base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread, 2404 write_closure.get(), 2405 path, 2406 descriptor.url(), 2407 request_context_)); 2408 } 2409 return true; 2410 } 2411 2412 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id, 2413 int64 blob_key) { 2414 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); 2415 bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; 2416 DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); 2417 scoped_refptr<LevelDBTransaction> transaction = 2418 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); 2419 2420 std::string live_blob_key = LiveBlobJournalKey::Encode(); 2421 BlobJournalType live_blob_journal; 2422 if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal) 2423 .ok()) 2424 return; 2425 DCHECK(live_blob_journal.size()); 2426 2427 std::string primary_key = BlobJournalKey::Encode(); 2428 BlobJournalType primary_journal; 2429 if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok()) 2430 return; 2431 2432 // There are several cases to handle. If blob_key is kAllBlobsKey, we want to 2433 // remove all entries with database_id from the live_blob journal and add only 2434 // kAllBlobsKey to the primary journal. Otherwise if IsValidBlobKey(blob_key) 2435 // and we hit kAllBlobsKey for the right database_id in the journal, we leave 2436 // the kAllBlobsKey entry in the live_blob journal but add the specific blob 2437 // to the primary. Otherwise if IsValidBlobKey(blob_key) and we find a 2438 // matching (database_id, blob_key) tuple, we should move it to the primary 2439 // journal. 2440 BlobJournalType new_live_blob_journal; 2441 for (BlobJournalType::iterator journal_iter = live_blob_journal.begin(); 2442 journal_iter != live_blob_journal.end(); 2443 ++journal_iter) { 2444 int64 current_database_id = journal_iter->first; 2445 int64 current_blob_key = journal_iter->second; 2446 bool current_all_blobs = 2447 current_blob_key == DatabaseMetaDataKey::kAllBlobsKey; 2448 DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) || 2449 current_all_blobs); 2450 if (current_database_id == database_id && 2451 (all_blobs || current_all_blobs || blob_key == current_blob_key)) { 2452 if (!all_blobs) { 2453 primary_journal.push_back( 2454 std::make_pair(database_id, current_blob_key)); 2455 if (current_all_blobs) 2456 new_live_blob_journal.push_back(*journal_iter); 2457 new_live_blob_journal.insert(new_live_blob_journal.end(), 2458 ++journal_iter, 2459 live_blob_journal.end()); // All the rest. 2460 break; 2461 } 2462 } else { 2463 new_live_blob_journal.push_back(*journal_iter); 2464 } 2465 } 2466 if (all_blobs) { 2467 primary_journal.push_back( 2468 std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey)); 2469 } 2470 UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal); 2471 UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal); 2472 transaction->Commit(); 2473 // We could just do the deletions/cleaning here, but if there are a lot of 2474 // blobs about to be garbage collected, it'd be better to wait and do them all 2475 // at once. 2476 StartJournalCleaningTimer(); 2477 } 2478 2479 // The this reference is a raw pointer that's declared Unretained inside the 2480 // timer code, so this won't confuse IndexedDBFactory's check for 2481 // HasLastBackingStoreReference. It's safe because if the backing store is 2482 // deleted, the timer will automatically be canceled on destruction. 2483 void IndexedDBBackingStore::StartJournalCleaningTimer() { 2484 journal_cleaning_timer_.Start( 2485 FROM_HERE, 2486 base::TimeDelta::FromSeconds(5), 2487 this, 2488 &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn); 2489 } 2490 2491 // This assumes a file path of dbId/second-to-LSB-of-counter/counter. 2492 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) { 2493 return GetBlobFileNameForKey(blob_path_, database_id, key); 2494 } 2495 2496 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, 2497 const std::string& stop_key, 2498 int64 index_id, 2499 unsigned char meta_data_type) { 2500 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 2501 return false; 2502 2503 StringPiece slice(it->Key()); 2504 IndexMetaDataKey meta_data_key; 2505 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 2506 DCHECK(ok); 2507 if (meta_data_key.IndexId() != index_id) 2508 return false; 2509 if (meta_data_key.meta_data_type() != meta_data_type) 2510 return false; 2511 return true; 2512 } 2513 2514 // TODO(jsbell): This should do some error handling rather than plowing ahead 2515 // when bad data is encountered. 2516 leveldb::Status IndexedDBBackingStore::GetIndexes( 2517 int64 database_id, 2518 int64 object_store_id, 2519 IndexedDBObjectStoreMetadata::IndexMap* indexes) { 2520 IDB_TRACE("IndexedDBBackingStore::GetIndexes"); 2521 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 2522 return InvalidDBKeyStatus(); 2523 const std::string start_key = 2524 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0); 2525 const std::string stop_key = 2526 IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0); 2527 2528 DCHECK(indexes->empty()); 2529 2530 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 2531 leveldb::Status s = it->Seek(start_key); 2532 while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 2533 StringPiece slice(it->Key()); 2534 IndexMetaDataKey meta_data_key; 2535 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 2536 DCHECK(ok); 2537 if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) { 2538 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2539 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail 2540 // the load. 2541 s = it->Next(); 2542 if (!s.ok()) 2543 break; 2544 continue; 2545 } 2546 2547 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 2548 // simplify. 2549 int64 index_id = meta_data_key.IndexId(); 2550 base::string16 index_name; 2551 { 2552 StringPiece slice(it->Value()); 2553 if (!DecodeString(&slice, &index_name) || !slice.empty()) 2554 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2555 } 2556 2557 s = it->Next(); // unique flag 2558 if (!s.ok()) 2559 break; 2560 if (!CheckIndexAndMetaDataKey( 2561 it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) { 2562 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2563 break; 2564 } 2565 bool index_unique; 2566 { 2567 StringPiece slice(it->Value()); 2568 if (!DecodeBool(&slice, &index_unique) || !slice.empty()) 2569 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2570 } 2571 2572 s = it->Next(); // key_path 2573 if (!s.ok()) 2574 break; 2575 if (!CheckIndexAndMetaDataKey( 2576 it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) { 2577 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2578 break; 2579 } 2580 IndexedDBKeyPath key_path; 2581 { 2582 StringPiece slice(it->Value()); 2583 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 2584 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2585 } 2586 2587 s = it->Next(); // [optional] multi_entry flag 2588 if (!s.ok()) 2589 break; 2590 bool index_multi_entry = false; 2591 if (CheckIndexAndMetaDataKey( 2592 it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) { 2593 StringPiece slice(it->Value()); 2594 if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty()) 2595 INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES); 2596 2597 s = it->Next(); 2598 if (!s.ok()) 2599 break; 2600 } 2601 2602 (*indexes)[index_id] = IndexedDBIndexMetadata( 2603 index_name, index_id, key_path, index_unique, index_multi_entry); 2604 } 2605 2606 if (!s.ok()) 2607 INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES); 2608 2609 return s; 2610 } 2611 2612 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) { 2613 FilePath fileName = GetBlobFileName(database_id, key); 2614 return base::DeleteFile(fileName, false); 2615 } 2616 2617 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) { 2618 FilePath dirName = GetBlobDirectoryName(blob_path_, database_id); 2619 return base::DeleteFile(dirName, true); 2620 } 2621 2622 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal( 2623 const std::string& level_db_key) { 2624 scoped_refptr<LevelDBTransaction> journal_transaction = 2625 IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); 2626 BlobJournalType journal; 2627 leveldb::Status s = 2628 GetBlobJournal(level_db_key, journal_transaction.get(), &journal); 2629 if (!s.ok()) 2630 return s; 2631 if (!journal.size()) 2632 return leveldb::Status::OK(); 2633 BlobJournalType::iterator journal_iter; 2634 for (journal_iter = journal.begin(); journal_iter != journal.end(); 2635 ++journal_iter) { 2636 int64 database_id = journal_iter->first; 2637 int64 blob_key = journal_iter->second; 2638 DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); 2639 if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) { 2640 if (!RemoveBlobDirectory(database_id)) 2641 return IOErrorStatus(); 2642 } else { 2643 DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key)); 2644 if (!RemoveBlobFile(database_id, blob_key)) 2645 return IOErrorStatus(); 2646 } 2647 } 2648 ClearBlobJournal(journal_transaction.get(), level_db_key); 2649 return journal_transaction->Commit(); 2650 } 2651 2652 leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord( 2653 int64 database_id, 2654 const std::string& object_store_data_key, 2655 IndexedDBValue* value) { 2656 BlobChangeRecord* change_record = NULL; 2657 BlobChangeMap::const_iterator blob_iter = 2658 blob_change_map_.find(object_store_data_key); 2659 if (blob_iter != blob_change_map_.end()) { 2660 change_record = blob_iter->second; 2661 } else { 2662 blob_iter = incognito_blob_map_.find(object_store_data_key); 2663 if (blob_iter != incognito_blob_map_.end()) 2664 change_record = blob_iter->second; 2665 } 2666 if (change_record) { 2667 // Either we haven't written the blob to disk yet or we're in incognito 2668 // mode, so we have to send back the one they sent us. This change record 2669 // includes the original UUID. 2670 value->blob_info = change_record->blob_info(); 2671 return leveldb::Status::OK(); 2672 } 2673 2674 BlobEntryKey blob_entry_key; 2675 StringPiece leveldb_key_piece(object_store_data_key); 2676 if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece, 2677 &blob_entry_key)) { 2678 NOTREACHED(); 2679 return InternalInconsistencyStatus(); 2680 } 2681 std::string encoded_key = blob_entry_key.Encode(); 2682 bool found; 2683 std::string encoded_value; 2684 leveldb::Status s = transaction()->Get(encoded_key, &encoded_value, &found); 2685 if (!s.ok()) 2686 return s; 2687 if (found) { 2688 if (!DecodeBlobData(encoded_value, &value->blob_info)) { 2689 INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD); 2690 return InternalInconsistencyStatus(); 2691 } 2692 std::vector<IndexedDBBlobInfo>::iterator iter; 2693 for (iter = value->blob_info.begin(); iter != value->blob_info.end(); 2694 ++iter) { 2695 iter->set_file_path( 2696 backing_store_->GetBlobFileName(database_id, iter->key())); 2697 iter->set_mark_used_callback( 2698 backing_store_->active_blob_registry()->GetAddBlobRefCallback( 2699 database_id, iter->key())); 2700 iter->set_release_callback( 2701 backing_store_->active_blob_registry()->GetFinalReleaseCallback( 2702 database_id, iter->key())); 2703 if (iter->is_file()) { 2704 base::File::Info info; 2705 if (base::GetFileInfo(iter->file_path(), &info)) { 2706 // This should always work, but it isn't fatal if it doesn't; it just 2707 // means a potential slow synchronous call from the renderer later. 2708 iter->set_last_modified(info.last_modified); 2709 iter->set_size(info.size); 2710 } 2711 } 2712 } 2713 } 2714 return leveldb::Status::OK(); 2715 } 2716 2717 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() { 2718 CleanUpBlobJournal(BlobJournalKey::Encode()); 2719 } 2720 2721 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( 2722 LevelDBTransaction* transaction, 2723 int64 database_id, 2724 int64 object_store_id, 2725 int64 index_id) { 2726 int64 max_index_id = -1; 2727 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 2728 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 2729 bool found = false; 2730 leveldb::Status s = 2731 GetInt(transaction, max_index_id_key, &max_index_id, &found); 2732 if (!s.ok()) { 2733 INTERNAL_READ_ERROR_UNTESTED(SET_MAX_INDEX_ID); 2734 return s; 2735 } 2736 if (!found) 2737 max_index_id = kMinimumIndexId; 2738 2739 if (index_id <= max_index_id) { 2740 INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_INDEX_ID); 2741 return InternalInconsistencyStatus(); 2742 } 2743 2744 PutInt(transaction, max_index_id_key, index_id); 2745 return s; 2746 } 2747 2748 leveldb::Status IndexedDBBackingStore::CreateIndex( 2749 IndexedDBBackingStore::Transaction* transaction, 2750 int64 database_id, 2751 int64 object_store_id, 2752 int64 index_id, 2753 const base::string16& name, 2754 const IndexedDBKeyPath& key_path, 2755 bool is_unique, 2756 bool is_multi_entry) { 2757 IDB_TRACE("IndexedDBBackingStore::CreateIndex"); 2758 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2759 return InvalidDBKeyStatus(); 2760 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2761 leveldb::Status s = SetMaxIndexId( 2762 leveldb_transaction, database_id, object_store_id, index_id); 2763 2764 if (!s.ok()) 2765 return s; 2766 2767 const std::string name_key = IndexMetaDataKey::Encode( 2768 database_id, object_store_id, index_id, IndexMetaDataKey::NAME); 2769 const std::string unique_key = IndexMetaDataKey::Encode( 2770 database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE); 2771 const std::string key_path_key = IndexMetaDataKey::Encode( 2772 database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH); 2773 const std::string multi_entry_key = IndexMetaDataKey::Encode( 2774 database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY); 2775 2776 PutString(leveldb_transaction, name_key, name); 2777 PutBool(leveldb_transaction, unique_key, is_unique); 2778 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 2779 PutBool(leveldb_transaction, multi_entry_key, is_multi_entry); 2780 return s; 2781 } 2782 2783 leveldb::Status IndexedDBBackingStore::DeleteIndex( 2784 IndexedDBBackingStore::Transaction* transaction, 2785 int64 database_id, 2786 int64 object_store_id, 2787 int64 index_id) { 2788 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); 2789 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2790 return InvalidDBKeyStatus(); 2791 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2792 2793 const std::string index_meta_data_start = 2794 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); 2795 const std::string index_meta_data_end = 2796 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 2797 leveldb::Status s = DeleteRangeBasic( 2798 leveldb_transaction, index_meta_data_start, index_meta_data_end, true); 2799 2800 if (s.ok()) { 2801 const std::string index_data_start = 2802 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 2803 const std::string index_data_end = 2804 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 2805 s = DeleteRangeBasic( 2806 leveldb_transaction, index_data_start, index_data_end, true); 2807 } 2808 2809 if (!s.ok()) 2810 INTERNAL_WRITE_ERROR_UNTESTED(DELETE_INDEX); 2811 2812 return s; 2813 } 2814 2815 leveldb::Status IndexedDBBackingStore::PutIndexDataForRecord( 2816 IndexedDBBackingStore::Transaction* transaction, 2817 int64 database_id, 2818 int64 object_store_id, 2819 int64 index_id, 2820 const IndexedDBKey& key, 2821 const RecordIdentifier& record_identifier) { 2822 IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord"); 2823 DCHECK(key.IsValid()); 2824 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2825 return InvalidDBKeyStatus(); 2826 2827 std::string encoded_key; 2828 EncodeIDBKey(key, &encoded_key); 2829 2830 const std::string index_data_key = 2831 IndexDataKey::Encode(database_id, 2832 object_store_id, 2833 index_id, 2834 encoded_key, 2835 record_identifier.primary_key(), 2836 0); 2837 2838 std::string data; 2839 EncodeVarInt(record_identifier.version(), &data); 2840 data.append(record_identifier.primary_key()); 2841 2842 transaction->transaction()->Put(index_data_key, &data); 2843 return leveldb::Status::OK(); 2844 } 2845 2846 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, 2847 const std::string& target, 2848 std::string* found_key, 2849 leveldb::Status* s) { 2850 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); 2851 *s = it->Seek(target); 2852 if (!s->ok()) 2853 return false; 2854 2855 if (!it->IsValid()) { 2856 *s = it->SeekToLast(); 2857 if (!s->ok() || !it->IsValid()) 2858 return false; 2859 } 2860 2861 while (CompareIndexKeys(it->Key(), target) > 0) { 2862 *s = it->Prev(); 2863 if (!s->ok() || !it->IsValid()) 2864 return false; 2865 } 2866 2867 do { 2868 *found_key = it->Key().as_string(); 2869 2870 // There can be several index keys that compare equal. We want the last one. 2871 *s = it->Next(); 2872 } while (s->ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target)); 2873 2874 return true; 2875 } 2876 2877 static leveldb::Status VersionExists(LevelDBTransaction* transaction, 2878 int64 database_id, 2879 int64 object_store_id, 2880 int64 version, 2881 const std::string& encoded_primary_key, 2882 bool* exists) { 2883 const std::string key = 2884 ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key); 2885 std::string data; 2886 2887 leveldb::Status s = transaction->Get(key, &data, exists); 2888 if (!s.ok()) { 2889 INTERNAL_READ_ERROR_UNTESTED(VERSION_EXISTS); 2890 return s; 2891 } 2892 if (!*exists) 2893 return s; 2894 2895 StringPiece slice(data); 2896 int64 decoded; 2897 if (!DecodeInt(&slice, &decoded) || !slice.empty()) 2898 return InternalInconsistencyStatus(); 2899 *exists = (decoded == version); 2900 return s; 2901 } 2902 2903 leveldb::Status IndexedDBBackingStore::FindKeyInIndex( 2904 IndexedDBBackingStore::Transaction* transaction, 2905 int64 database_id, 2906 int64 object_store_id, 2907 int64 index_id, 2908 const IndexedDBKey& key, 2909 std::string* found_encoded_primary_key, 2910 bool* found) { 2911 IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex"); 2912 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id)); 2913 2914 DCHECK(found_encoded_primary_key->empty()); 2915 *found = false; 2916 2917 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2918 const std::string leveldb_key = 2919 IndexDataKey::Encode(database_id, object_store_id, index_id, key); 2920 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 2921 leveldb::Status s = it->Seek(leveldb_key); 2922 if (!s.ok()) { 2923 INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX); 2924 return s; 2925 } 2926 2927 for (;;) { 2928 if (!it->IsValid()) 2929 return leveldb::Status::OK(); 2930 if (CompareIndexKeys(it->Key(), leveldb_key) > 0) 2931 return leveldb::Status::OK(); 2932 2933 StringPiece slice(it->Value()); 2934 2935 int64 version; 2936 if (!DecodeVarInt(&slice, &version)) { 2937 INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX); 2938 return InternalInconsistencyStatus(); 2939 } 2940 *found_encoded_primary_key = slice.as_string(); 2941 2942 bool exists = false; 2943 s = VersionExists(leveldb_transaction, 2944 database_id, 2945 object_store_id, 2946 version, 2947 *found_encoded_primary_key, 2948 &exists); 2949 if (!s.ok()) 2950 return s; 2951 if (!exists) { 2952 // Delete stale index data entry and continue. 2953 leveldb_transaction->Remove(it->Key()); 2954 s = it->Next(); 2955 continue; 2956 } 2957 *found = true; 2958 return s; 2959 } 2960 } 2961 2962 leveldb::Status IndexedDBBackingStore::GetPrimaryKeyViaIndex( 2963 IndexedDBBackingStore::Transaction* transaction, 2964 int64 database_id, 2965 int64 object_store_id, 2966 int64 index_id, 2967 const IndexedDBKey& key, 2968 scoped_ptr<IndexedDBKey>* primary_key) { 2969 IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex"); 2970 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2971 return InvalidDBKeyStatus(); 2972 2973 bool found = false; 2974 std::string found_encoded_primary_key; 2975 leveldb::Status s = FindKeyInIndex(transaction, 2976 database_id, 2977 object_store_id, 2978 index_id, 2979 key, 2980 &found_encoded_primary_key, 2981 &found); 2982 if (!s.ok()) { 2983 INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX); 2984 return s; 2985 } 2986 if (!found) 2987 return s; 2988 if (!found_encoded_primary_key.size()) { 2989 INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX); 2990 return InvalidDBKeyStatus(); 2991 } 2992 2993 StringPiece slice(found_encoded_primary_key); 2994 if (DecodeIDBKey(&slice, primary_key) && slice.empty()) 2995 return s; 2996 else 2997 return InvalidDBKeyStatus(); 2998 } 2999 3000 leveldb::Status IndexedDBBackingStore::KeyExistsInIndex( 3001 IndexedDBBackingStore::Transaction* transaction, 3002 int64 database_id, 3003 int64 object_store_id, 3004 int64 index_id, 3005 const IndexedDBKey& index_key, 3006 scoped_ptr<IndexedDBKey>* found_primary_key, 3007 bool* exists) { 3008 IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex"); 3009 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 3010 return InvalidDBKeyStatus(); 3011 3012 *exists = false; 3013 std::string found_encoded_primary_key; 3014 leveldb::Status s = FindKeyInIndex(transaction, 3015 database_id, 3016 object_store_id, 3017 index_id, 3018 index_key, 3019 &found_encoded_primary_key, 3020 exists); 3021 if (!s.ok()) { 3022 INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX); 3023 return s; 3024 } 3025 if (!*exists) 3026 return leveldb::Status::OK(); 3027 if (found_encoded_primary_key.empty()) { 3028 INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX); 3029 return InvalidDBKeyStatus(); 3030 } 3031 3032 StringPiece slice(found_encoded_primary_key); 3033 if (DecodeIDBKey(&slice, found_primary_key) && slice.empty()) 3034 return s; 3035 else 3036 return InvalidDBKeyStatus(); 3037 } 3038 3039 IndexedDBBackingStore::Cursor::Cursor( 3040 const IndexedDBBackingStore::Cursor* other) 3041 : backing_store_(other->backing_store_), 3042 transaction_(other->transaction_), 3043 database_id_(other->database_id_), 3044 cursor_options_(other->cursor_options_), 3045 current_key_(new IndexedDBKey(*other->current_key_)) { 3046 if (other->iterator_) { 3047 iterator_ = transaction_->transaction()->CreateIterator(); 3048 3049 if (other->iterator_->IsValid()) { 3050 leveldb::Status s = iterator_->Seek(other->iterator_->Key()); 3051 // TODO(cmumford): Handle this error (crbug.com/363397) 3052 DCHECK(iterator_->IsValid()); 3053 } 3054 } 3055 } 3056 3057 IndexedDBBackingStore::Cursor::Cursor( 3058 scoped_refptr<IndexedDBBackingStore> backing_store, 3059 IndexedDBBackingStore::Transaction* transaction, 3060 int64 database_id, 3061 const CursorOptions& cursor_options) 3062 : backing_store_(backing_store.get()), 3063 transaction_(transaction), 3064 database_id_(database_id), 3065 cursor_options_(cursor_options) { 3066 } 3067 IndexedDBBackingStore::Cursor::~Cursor() {} 3068 3069 bool IndexedDBBackingStore::Cursor::FirstSeek(leveldb::Status* s) { 3070 iterator_ = transaction_->transaction()->CreateIterator(); 3071 if (cursor_options_.forward) 3072 *s = iterator_->Seek(cursor_options_.low_key); 3073 else 3074 *s = iterator_->Seek(cursor_options_.high_key); 3075 if (!s->ok()) 3076 return false; 3077 3078 return Continue(0, READY, s); 3079 } 3080 3081 bool IndexedDBBackingStore::Cursor::Advance(uint32 count, leveldb::Status* s) { 3082 *s = leveldb::Status::OK(); 3083 while (count--) { 3084 if (!Continue(s)) 3085 return false; 3086 } 3087 return true; 3088 } 3089 3090 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key, 3091 const IndexedDBKey* primary_key, 3092 IteratorState next_state, 3093 leveldb::Status* s) { 3094 DCHECK(!key || key->IsValid()); 3095 DCHECK(!primary_key || primary_key->IsValid()); 3096 *s = leveldb::Status::OK(); 3097 3098 // TODO(alecflett): avoid a copy here? 3099 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); 3100 3101 // When iterating with PrevNoDuplicate, spec requires that the 3102 // value we yield for each key is the first duplicate in forwards 3103 // order. 3104 IndexedDBKey last_duplicate_key; 3105 3106 bool forward = cursor_options_.forward; 3107 bool first_iteration_forward = forward; 3108 bool flipped = false; 3109 3110 for (;;) { 3111 if (next_state == SEEK) { 3112 // TODO(jsbell): Optimize seeking for reverse cursors as well. 3113 if (first_iteration_forward && key) { 3114 first_iteration_forward = false; 3115 std::string leveldb_key; 3116 if (primary_key) { 3117 leveldb_key = EncodeKey(*key, *primary_key); 3118 } else { 3119 leveldb_key = EncodeKey(*key); 3120 } 3121 *s = iterator_->Seek(leveldb_key); 3122 } else if (forward) { 3123 *s = iterator_->Next(); 3124 } else { 3125 *s = iterator_->Prev(); 3126 } 3127 if (!s->ok()) 3128 return false; 3129 } else { 3130 next_state = SEEK; // for subsequent iterations 3131 } 3132 3133 if (!iterator_->IsValid()) { 3134 if (!forward && last_duplicate_key.IsValid()) { 3135 // We need to walk forward because we hit the end of 3136 // the data. 3137 forward = true; 3138 flipped = true; 3139 continue; 3140 } 3141 3142 return false; 3143 } 3144 3145 if (IsPastBounds()) { 3146 if (!forward && last_duplicate_key.IsValid()) { 3147 // We need to walk forward because now we're beyond the 3148 // bounds defined by the cursor. 3149 forward = true; 3150 flipped = true; 3151 continue; 3152 } 3153 3154 return false; 3155 } 3156 3157 if (!HaveEnteredRange()) 3158 continue; 3159 3160 // The row may not load because there's a stale entry in the 3161 // index. This is not fatal. 3162 if (!LoadCurrentRow()) 3163 continue; 3164 3165 if (key) { 3166 if (forward) { 3167 if (primary_key && current_key_->Equals(*key) && 3168 this->primary_key().IsLessThan(*primary_key)) 3169 continue; 3170 if (!flipped && current_key_->IsLessThan(*key)) 3171 continue; 3172 } else { 3173 if (primary_key && key->Equals(*current_key_) && 3174 primary_key->IsLessThan(this->primary_key())) 3175 continue; 3176 if (key->IsLessThan(*current_key_)) 3177 continue; 3178 } 3179 } 3180 3181 if (cursor_options_.unique) { 3182 if (previous_key.IsValid() && current_key_->Equals(previous_key)) { 3183 // We should never be able to walk forward all the way 3184 // to the previous key. 3185 DCHECK(!last_duplicate_key.IsValid()); 3186 continue; 3187 } 3188 3189 if (!forward) { 3190 if (!last_duplicate_key.IsValid()) { 3191 last_duplicate_key = *current_key_; 3192 continue; 3193 } 3194 3195 // We need to walk forward because we hit the boundary 3196 // between key ranges. 3197 if (!last_duplicate_key.Equals(*current_key_)) { 3198 forward = true; 3199 flipped = true; 3200 continue; 3201 } 3202 3203 continue; 3204 } 3205 } 3206 break; 3207 } 3208 3209 DCHECK(!last_duplicate_key.IsValid() || 3210 (forward && last_duplicate_key.Equals(*current_key_))); 3211 return true; 3212 } 3213 3214 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { 3215 if (cursor_options_.forward) { 3216 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 3217 if (cursor_options_.low_open) { 3218 return compare > 0; 3219 } 3220 return compare >= 0; 3221 } 3222 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 3223 if (cursor_options_.high_open) { 3224 return compare < 0; 3225 } 3226 return compare <= 0; 3227 } 3228 3229 bool IndexedDBBackingStore::Cursor::IsPastBounds() const { 3230 if (cursor_options_.forward) { 3231 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 3232 if (cursor_options_.high_open) { 3233 return compare >= 0; 3234 } 3235 return compare > 0; 3236 } 3237 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 3238 if (cursor_options_.low_open) { 3239 return compare <= 0; 3240 } 3241 return compare < 0; 3242 } 3243 3244 const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const { 3245 return *current_key_; 3246 } 3247 3248 const IndexedDBBackingStore::RecordIdentifier& 3249 IndexedDBBackingStore::Cursor::record_identifier() const { 3250 return record_identifier_; 3251 } 3252 3253 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { 3254 public: 3255 ObjectStoreKeyCursorImpl( 3256 scoped_refptr<IndexedDBBackingStore> backing_store, 3257 IndexedDBBackingStore::Transaction* transaction, 3258 int64 database_id, 3259 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 3260 : IndexedDBBackingStore::Cursor(backing_store, 3261 transaction, 3262 database_id, 3263 cursor_options) {} 3264 3265 virtual Cursor* Clone() OVERRIDE { 3266 return new ObjectStoreKeyCursorImpl(this); 3267 } 3268 3269 // IndexedDBBackingStore::Cursor 3270 virtual IndexedDBValue* value() OVERRIDE { 3271 NOTREACHED(); 3272 return NULL; 3273 } 3274 virtual bool LoadCurrentRow() OVERRIDE; 3275 3276 protected: 3277 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 3278 return ObjectStoreDataKey::Encode( 3279 cursor_options_.database_id, cursor_options_.object_store_id, key); 3280 } 3281 virtual std::string EncodeKey(const IndexedDBKey& key, 3282 const IndexedDBKey& primary_key) OVERRIDE { 3283 NOTREACHED(); 3284 return std::string(); 3285 } 3286 3287 private: 3288 explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other) 3289 : IndexedDBBackingStore::Cursor(other) {} 3290 3291 DISALLOW_COPY_AND_ASSIGN(ObjectStoreKeyCursorImpl); 3292 }; 3293 3294 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() { 3295 StringPiece slice(iterator_->Key()); 3296 ObjectStoreDataKey object_store_data_key; 3297 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { 3298 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3299 return false; 3300 } 3301 3302 current_key_ = object_store_data_key.user_key(); 3303 3304 int64 version; 3305 slice = StringPiece(iterator_->Value()); 3306 if (!DecodeVarInt(&slice, &version)) { 3307 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3308 return false; 3309 } 3310 3311 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 3312 std::string encoded_key; 3313 EncodeIDBKey(*current_key_, &encoded_key); 3314 record_identifier_.Reset(encoded_key, version); 3315 3316 return true; 3317 } 3318 3319 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { 3320 public: 3321 ObjectStoreCursorImpl( 3322 scoped_refptr<IndexedDBBackingStore> backing_store, 3323 IndexedDBBackingStore::Transaction* transaction, 3324 int64 database_id, 3325 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 3326 : IndexedDBBackingStore::Cursor(backing_store, 3327 transaction, 3328 database_id, 3329 cursor_options) {} 3330 3331 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } 3332 3333 // IndexedDBBackingStore::Cursor 3334 virtual IndexedDBValue* value() OVERRIDE { return ¤t_value_; } 3335 virtual bool LoadCurrentRow() OVERRIDE; 3336 3337 protected: 3338 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 3339 return ObjectStoreDataKey::Encode( 3340 cursor_options_.database_id, cursor_options_.object_store_id, key); 3341 } 3342 virtual std::string EncodeKey(const IndexedDBKey& key, 3343 const IndexedDBKey& primary_key) OVERRIDE { 3344 NOTREACHED(); 3345 return std::string(); 3346 } 3347 3348 private: 3349 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) 3350 : IndexedDBBackingStore::Cursor(other), 3351 current_value_(other->current_value_) {} 3352 3353 IndexedDBValue current_value_; 3354 3355 DISALLOW_COPY_AND_ASSIGN(ObjectStoreCursorImpl); 3356 }; 3357 3358 bool ObjectStoreCursorImpl::LoadCurrentRow() { 3359 StringPiece key_slice(iterator_->Key()); 3360 ObjectStoreDataKey object_store_data_key; 3361 if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) { 3362 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3363 return false; 3364 } 3365 3366 current_key_ = object_store_data_key.user_key(); 3367 3368 int64 version; 3369 StringPiece value_slice = StringPiece(iterator_->Value()); 3370 if (!DecodeVarInt(&value_slice, &version)) { 3371 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3372 return false; 3373 } 3374 3375 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 3376 std::string encoded_key; 3377 EncodeIDBKey(*current_key_, &encoded_key); 3378 record_identifier_.Reset(encoded_key, version); 3379 3380 if (!transaction_->GetBlobInfoForRecord(database_id_, 3381 iterator_->Key().as_string(), 3382 ¤t_value_).ok()) { 3383 return false; 3384 } 3385 current_value_.bits = value_slice.as_string(); 3386 return true; 3387 } 3388 3389 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { 3390 public: 3391 IndexKeyCursorImpl( 3392 scoped_refptr<IndexedDBBackingStore> backing_store, 3393 IndexedDBBackingStore::Transaction* transaction, 3394 int64 database_id, 3395 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 3396 : IndexedDBBackingStore::Cursor(backing_store, 3397 transaction, 3398 database_id, 3399 cursor_options) {} 3400 3401 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } 3402 3403 // IndexedDBBackingStore::Cursor 3404 virtual IndexedDBValue* value() OVERRIDE { 3405 NOTREACHED(); 3406 return NULL; 3407 } 3408 virtual const IndexedDBKey& primary_key() const OVERRIDE { 3409 return *primary_key_; 3410 } 3411 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 3412 const OVERRIDE { 3413 NOTREACHED(); 3414 return record_identifier_; 3415 } 3416 virtual bool LoadCurrentRow() OVERRIDE; 3417 3418 protected: 3419 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 3420 return IndexDataKey::Encode(cursor_options_.database_id, 3421 cursor_options_.object_store_id, 3422 cursor_options_.index_id, 3423 key); 3424 } 3425 virtual std::string EncodeKey(const IndexedDBKey& key, 3426 const IndexedDBKey& primary_key) OVERRIDE { 3427 return IndexDataKey::Encode(cursor_options_.database_id, 3428 cursor_options_.object_store_id, 3429 cursor_options_.index_id, 3430 key, 3431 primary_key); 3432 } 3433 3434 private: 3435 explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other) 3436 : IndexedDBBackingStore::Cursor(other), 3437 primary_key_(new IndexedDBKey(*other->primary_key_)) {} 3438 3439 scoped_ptr<IndexedDBKey> primary_key_; 3440 3441 DISALLOW_COPY_AND_ASSIGN(IndexKeyCursorImpl); 3442 }; 3443 3444 bool IndexKeyCursorImpl::LoadCurrentRow() { 3445 StringPiece slice(iterator_->Key()); 3446 IndexDataKey index_data_key; 3447 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 3448 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3449 return false; 3450 } 3451 3452 current_key_ = index_data_key.user_key(); 3453 DCHECK(current_key_); 3454 3455 slice = StringPiece(iterator_->Value()); 3456 int64 index_data_version; 3457 if (!DecodeVarInt(&slice, &index_data_version)) { 3458 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3459 return false; 3460 } 3461 3462 if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) { 3463 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3464 return false; 3465 } 3466 3467 std::string primary_leveldb_key = 3468 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 3469 index_data_key.ObjectStoreId(), 3470 *primary_key_); 3471 3472 std::string result; 3473 bool found = false; 3474 leveldb::Status s = 3475 transaction_->transaction()->Get(primary_leveldb_key, &result, &found); 3476 if (!s.ok()) { 3477 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3478 return false; 3479 } 3480 if (!found) { 3481 transaction_->transaction()->Remove(iterator_->Key()); 3482 return false; 3483 } 3484 if (!result.size()) { 3485 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3486 return false; 3487 } 3488 3489 int64 object_store_data_version; 3490 slice = StringPiece(result); 3491 if (!DecodeVarInt(&slice, &object_store_data_version)) { 3492 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3493 return false; 3494 } 3495 3496 if (object_store_data_version != index_data_version) { 3497 transaction_->transaction()->Remove(iterator_->Key()); 3498 return false; 3499 } 3500 3501 return true; 3502 } 3503 3504 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { 3505 public: 3506 IndexCursorImpl( 3507 scoped_refptr<IndexedDBBackingStore> backing_store, 3508 IndexedDBBackingStore::Transaction* transaction, 3509 int64 database_id, 3510 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 3511 : IndexedDBBackingStore::Cursor(backing_store, 3512 transaction, 3513 database_id, 3514 cursor_options) {} 3515 3516 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } 3517 3518 // IndexedDBBackingStore::Cursor 3519 virtual IndexedDBValue* value() OVERRIDE { return ¤t_value_; } 3520 virtual const IndexedDBKey& primary_key() const OVERRIDE { 3521 return *primary_key_; 3522 } 3523 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 3524 const OVERRIDE { 3525 NOTREACHED(); 3526 return record_identifier_; 3527 } 3528 virtual bool LoadCurrentRow() OVERRIDE; 3529 3530 protected: 3531 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 3532 return IndexDataKey::Encode(cursor_options_.database_id, 3533 cursor_options_.object_store_id, 3534 cursor_options_.index_id, 3535 key); 3536 } 3537 virtual std::string EncodeKey(const IndexedDBKey& key, 3538 const IndexedDBKey& primary_key) OVERRIDE { 3539 return IndexDataKey::Encode(cursor_options_.database_id, 3540 cursor_options_.object_store_id, 3541 cursor_options_.index_id, 3542 key, 3543 primary_key); 3544 } 3545 3546 private: 3547 explicit IndexCursorImpl(const IndexCursorImpl* other) 3548 : IndexedDBBackingStore::Cursor(other), 3549 primary_key_(new IndexedDBKey(*other->primary_key_)), 3550 current_value_(other->current_value_), 3551 primary_leveldb_key_(other->primary_leveldb_key_) {} 3552 3553 scoped_ptr<IndexedDBKey> primary_key_; 3554 IndexedDBValue current_value_; 3555 std::string primary_leveldb_key_; 3556 3557 DISALLOW_COPY_AND_ASSIGN(IndexCursorImpl); 3558 }; 3559 3560 bool IndexCursorImpl::LoadCurrentRow() { 3561 StringPiece slice(iterator_->Key()); 3562 IndexDataKey index_data_key; 3563 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 3564 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3565 return false; 3566 } 3567 3568 current_key_ = index_data_key.user_key(); 3569 DCHECK(current_key_); 3570 3571 slice = StringPiece(iterator_->Value()); 3572 int64 index_data_version; 3573 if (!DecodeVarInt(&slice, &index_data_version)) { 3574 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3575 return false; 3576 } 3577 if (!DecodeIDBKey(&slice, &primary_key_)) { 3578 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3579 return false; 3580 } 3581 3582 DCHECK_EQ(index_data_key.DatabaseId(), database_id_); 3583 primary_leveldb_key_ = 3584 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 3585 index_data_key.ObjectStoreId(), 3586 *primary_key_); 3587 3588 std::string result; 3589 bool found = false; 3590 leveldb::Status s = 3591 transaction_->transaction()->Get(primary_leveldb_key_, &result, &found); 3592 if (!s.ok()) { 3593 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3594 return false; 3595 } 3596 if (!found) { 3597 transaction_->transaction()->Remove(iterator_->Key()); 3598 return false; 3599 } 3600 if (!result.size()) { 3601 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3602 return false; 3603 } 3604 3605 int64 object_store_data_version; 3606 slice = StringPiece(result); 3607 if (!DecodeVarInt(&slice, &object_store_data_version)) { 3608 INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW); 3609 return false; 3610 } 3611 3612 if (object_store_data_version != index_data_version) { 3613 transaction_->transaction()->Remove(iterator_->Key()); 3614 return false; 3615 } 3616 3617 current_value_.bits = slice.as_string(); 3618 return transaction_->GetBlobInfoForRecord(database_id_, 3619 primary_leveldb_key_, 3620 ¤t_value_).ok(); 3621 } 3622 3623 bool ObjectStoreCursorOptions( 3624 LevelDBTransaction* transaction, 3625 int64 database_id, 3626 int64 object_store_id, 3627 const IndexedDBKeyRange& range, 3628 blink::WebIDBCursorDirection direction, 3629 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 3630 cursor_options->database_id = database_id; 3631 cursor_options->object_store_id = object_store_id; 3632 3633 bool lower_bound = range.lower().IsValid(); 3634 bool upper_bound = range.upper().IsValid(); 3635 cursor_options->forward = 3636 (direction == blink::WebIDBCursorDirectionNextNoDuplicate || 3637 direction == blink::WebIDBCursorDirectionNext); 3638 cursor_options->unique = 3639 (direction == blink::WebIDBCursorDirectionNextNoDuplicate || 3640 direction == blink::WebIDBCursorDirectionPrevNoDuplicate); 3641 3642 if (!lower_bound) { 3643 cursor_options->low_key = 3644 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 3645 cursor_options->low_open = true; // Not included. 3646 } else { 3647 cursor_options->low_key = 3648 ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower()); 3649 cursor_options->low_open = range.lowerOpen(); 3650 } 3651 3652 leveldb::Status s; 3653 3654 if (!upper_bound) { 3655 cursor_options->high_key = 3656 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 3657 3658 if (cursor_options->forward) { 3659 cursor_options->high_open = true; // Not included. 3660 } else { 3661 // We need a key that exists. 3662 // TODO(cmumford): Handle this error (crbug.com/363397) 3663 if (!FindGreatestKeyLessThanOrEqual(transaction, 3664 cursor_options->high_key, 3665 &cursor_options->high_key, 3666 &s)) 3667 return false; 3668 cursor_options->high_open = false; 3669 } 3670 } else { 3671 cursor_options->high_key = 3672 ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper()); 3673 cursor_options->high_open = range.upperOpen(); 3674 3675 if (!cursor_options->forward) { 3676 // For reverse cursors, we need a key that exists. 3677 std::string found_high_key; 3678 // TODO(cmumford): Handle this error (crbug.com/363397) 3679 if (!FindGreatestKeyLessThanOrEqual( 3680 transaction, cursor_options->high_key, &found_high_key, &s)) 3681 return false; 3682 3683 // If the target key should not be included, but we end up with a smaller 3684 // key, we should include that. 3685 if (cursor_options->high_open && 3686 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 3687 cursor_options->high_open = false; 3688 3689 cursor_options->high_key = found_high_key; 3690 } 3691 } 3692 3693 return true; 3694 } 3695 3696 bool IndexCursorOptions( 3697 LevelDBTransaction* transaction, 3698 int64 database_id, 3699 int64 object_store_id, 3700 int64 index_id, 3701 const IndexedDBKeyRange& range, 3702 blink::WebIDBCursorDirection direction, 3703 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 3704 DCHECK(transaction); 3705 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 3706 return false; 3707 3708 cursor_options->database_id = database_id; 3709 cursor_options->object_store_id = object_store_id; 3710 cursor_options->index_id = index_id; 3711 3712 bool lower_bound = range.lower().IsValid(); 3713 bool upper_bound = range.upper().IsValid(); 3714 cursor_options->forward = 3715 (direction == blink::WebIDBCursorDirectionNextNoDuplicate || 3716 direction == blink::WebIDBCursorDirectionNext); 3717 cursor_options->unique = 3718 (direction == blink::WebIDBCursorDirectionNextNoDuplicate || 3719 direction == blink::WebIDBCursorDirectionPrevNoDuplicate); 3720 3721 if (!lower_bound) { 3722 cursor_options->low_key = 3723 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 3724 cursor_options->low_open = false; // Included. 3725 } else { 3726 cursor_options->low_key = IndexDataKey::Encode( 3727 database_id, object_store_id, index_id, range.lower()); 3728 cursor_options->low_open = range.lowerOpen(); 3729 } 3730 3731 leveldb::Status s; 3732 3733 if (!upper_bound) { 3734 cursor_options->high_key = 3735 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 3736 cursor_options->high_open = false; // Included. 3737 3738 if (!cursor_options->forward) { // We need a key that exists. 3739 if (!FindGreatestKeyLessThanOrEqual(transaction, 3740 cursor_options->high_key, 3741 &cursor_options->high_key, 3742 &s)) 3743 return false; 3744 cursor_options->high_open = false; 3745 } 3746 } else { 3747 cursor_options->high_key = IndexDataKey::Encode( 3748 database_id, object_store_id, index_id, range.upper()); 3749 cursor_options->high_open = range.upperOpen(); 3750 3751 std::string found_high_key; 3752 // Seek to the *last* key in the set of non-unique keys 3753 // TODO(cmumford): Handle this error (crbug.com/363397) 3754 if (!FindGreatestKeyLessThanOrEqual( 3755 transaction, cursor_options->high_key, &found_high_key, &s)) 3756 return false; 3757 3758 // If the target key should not be included, but we end up with a smaller 3759 // key, we should include that. 3760 if (cursor_options->high_open && 3761 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 3762 cursor_options->high_open = false; 3763 3764 cursor_options->high_key = found_high_key; 3765 } 3766 3767 return true; 3768 } 3769 3770 scoped_ptr<IndexedDBBackingStore::Cursor> 3771 IndexedDBBackingStore::OpenObjectStoreCursor( 3772 IndexedDBBackingStore::Transaction* transaction, 3773 int64 database_id, 3774 int64 object_store_id, 3775 const IndexedDBKeyRange& range, 3776 blink::WebIDBCursorDirection direction, 3777 leveldb::Status* s) { 3778 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor"); 3779 *s = leveldb::Status::OK(); 3780 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 3781 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 3782 if (!ObjectStoreCursorOptions(leveldb_transaction, 3783 database_id, 3784 object_store_id, 3785 range, 3786 direction, 3787 &cursor_options)) 3788 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3789 scoped_ptr<ObjectStoreCursorImpl> cursor(new ObjectStoreCursorImpl( 3790 this, transaction, database_id, cursor_options)); 3791 if (!cursor->FirstSeek(s)) 3792 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3793 3794 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 3795 } 3796 3797 scoped_ptr<IndexedDBBackingStore::Cursor> 3798 IndexedDBBackingStore::OpenObjectStoreKeyCursor( 3799 IndexedDBBackingStore::Transaction* transaction, 3800 int64 database_id, 3801 int64 object_store_id, 3802 const IndexedDBKeyRange& range, 3803 blink::WebIDBCursorDirection direction, 3804 leveldb::Status* s) { 3805 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); 3806 *s = leveldb::Status::OK(); 3807 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 3808 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 3809 if (!ObjectStoreCursorOptions(leveldb_transaction, 3810 database_id, 3811 object_store_id, 3812 range, 3813 direction, 3814 &cursor_options)) 3815 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3816 scoped_ptr<ObjectStoreKeyCursorImpl> cursor(new ObjectStoreKeyCursorImpl( 3817 this, transaction, database_id, cursor_options)); 3818 if (!cursor->FirstSeek(s)) 3819 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3820 3821 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 3822 } 3823 3824 scoped_ptr<IndexedDBBackingStore::Cursor> 3825 IndexedDBBackingStore::OpenIndexKeyCursor( 3826 IndexedDBBackingStore::Transaction* transaction, 3827 int64 database_id, 3828 int64 object_store_id, 3829 int64 index_id, 3830 const IndexedDBKeyRange& range, 3831 blink::WebIDBCursorDirection direction, 3832 leveldb::Status* s) { 3833 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); 3834 *s = leveldb::Status::OK(); 3835 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 3836 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 3837 if (!IndexCursorOptions(leveldb_transaction, 3838 database_id, 3839 object_store_id, 3840 index_id, 3841 range, 3842 direction, 3843 &cursor_options)) 3844 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3845 scoped_ptr<IndexKeyCursorImpl> cursor( 3846 new IndexKeyCursorImpl(this, transaction, database_id, cursor_options)); 3847 if (!cursor->FirstSeek(s)) 3848 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3849 3850 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 3851 } 3852 3853 scoped_ptr<IndexedDBBackingStore::Cursor> 3854 IndexedDBBackingStore::OpenIndexCursor( 3855 IndexedDBBackingStore::Transaction* transaction, 3856 int64 database_id, 3857 int64 object_store_id, 3858 int64 index_id, 3859 const IndexedDBKeyRange& range, 3860 blink::WebIDBCursorDirection direction, 3861 leveldb::Status* s) { 3862 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); 3863 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 3864 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 3865 if (!IndexCursorOptions(leveldb_transaction, 3866 database_id, 3867 object_store_id, 3868 index_id, 3869 range, 3870 direction, 3871 &cursor_options)) 3872 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3873 scoped_ptr<IndexCursorImpl> cursor( 3874 new IndexCursorImpl(this, transaction, database_id, cursor_options)); 3875 if (!cursor->FirstSeek(s)) 3876 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 3877 3878 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 3879 } 3880 3881 IndexedDBBackingStore::Transaction::Transaction( 3882 IndexedDBBackingStore* backing_store) 3883 : backing_store_(backing_store), database_id_(-1) { 3884 } 3885 3886 IndexedDBBackingStore::Transaction::~Transaction() { 3887 STLDeleteContainerPairSecondPointers( 3888 blob_change_map_.begin(), blob_change_map_.end()); 3889 STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(), 3890 incognito_blob_map_.end()); 3891 } 3892 3893 void IndexedDBBackingStore::Transaction::Begin() { 3894 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); 3895 DCHECK(!transaction_.get()); 3896 transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction( 3897 backing_store_->db_.get()); 3898 3899 // If incognito, this snapshots blobs just as the above transaction_ 3900 // constructor snapshots the leveldb. 3901 BlobChangeMap::const_iterator iter; 3902 for (iter = backing_store_->incognito_blob_map_.begin(); 3903 iter != backing_store_->incognito_blob_map_.end(); 3904 ++iter) 3905 incognito_blob_map_[iter->first] = iter->second->Clone().release(); 3906 } 3907 3908 static GURL getURLFromUUID(const string& uuid) { 3909 return GURL("blob:uuid/" + uuid); 3910 } 3911 3912 leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction( 3913 BlobEntryKeyValuePairVec* new_blob_entries, 3914 WriteDescriptorVec* new_files_to_write) { 3915 if (backing_store_->is_incognito()) 3916 return leveldb::Status::OK(); 3917 3918 BlobChangeMap::iterator iter = blob_change_map_.begin(); 3919 new_blob_entries->clear(); 3920 new_files_to_write->clear(); 3921 if (iter != blob_change_map_.end()) { 3922 // Create LevelDBTransaction for the name generator seed and add-journal. 3923 scoped_refptr<LevelDBTransaction> pre_transaction = 3924 IndexedDBClassFactory::Get()->CreateLevelDBTransaction( 3925 backing_store_->db_.get()); 3926 BlobJournalType journal; 3927 for (; iter != blob_change_map_.end(); ++iter) { 3928 std::vector<IndexedDBBlobInfo>::iterator info_iter; 3929 std::vector<IndexedDBBlobInfo*> new_blob_keys; 3930 for (info_iter = iter->second->mutable_blob_info().begin(); 3931 info_iter != iter->second->mutable_blob_info().end(); 3932 ++info_iter) { 3933 int64 next_blob_key = -1; 3934 bool result = GetBlobKeyGeneratorCurrentNumber( 3935 pre_transaction.get(), database_id_, &next_blob_key); 3936 if (!result || next_blob_key < 0) 3937 return InternalInconsistencyStatus(); 3938 BlobJournalEntryType journal_entry = 3939 std::make_pair(database_id_, next_blob_key); 3940 journal.push_back(journal_entry); 3941 if (info_iter->is_file()) { 3942 new_files_to_write->push_back( 3943 WriteDescriptor(info_iter->file_path(), 3944 next_blob_key, 3945 info_iter->size(), 3946 info_iter->last_modified())); 3947 } else { 3948 new_files_to_write->push_back( 3949 WriteDescriptor(getURLFromUUID(info_iter->uuid()), 3950 next_blob_key, 3951 info_iter->size())); 3952 } 3953 info_iter->set_key(next_blob_key); 3954 new_blob_keys.push_back(&*info_iter); 3955 result = UpdateBlobKeyGeneratorCurrentNumber( 3956 pre_transaction.get(), database_id_, next_blob_key + 1); 3957 if (!result) 3958 return InternalInconsistencyStatus(); 3959 } 3960 BlobEntryKey blob_entry_key; 3961 StringPiece key_piece(iter->second->key()); 3962 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { 3963 NOTREACHED(); 3964 return InternalInconsistencyStatus(); 3965 } 3966 new_blob_entries->push_back( 3967 std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys))); 3968 } 3969 UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal); 3970 leveldb::Status s = pre_transaction->Commit(); 3971 if (!s.ok()) 3972 return InternalInconsistencyStatus(); 3973 } 3974 return leveldb::Status::OK(); 3975 } 3976 3977 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() { 3978 if (backing_store_->is_incognito()) 3979 return true; 3980 3981 BlobChangeMap::const_iterator iter = blob_change_map_.begin(); 3982 // Look up all old files to remove as part of the transaction, store their 3983 // names in blobs_to_remove_, and remove their old blob data entries. 3984 if (iter != blob_change_map_.end()) { 3985 for (; iter != blob_change_map_.end(); ++iter) { 3986 BlobEntryKey blob_entry_key; 3987 StringPiece key_piece(iter->second->key()); 3988 if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) { 3989 NOTREACHED(); 3990 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); 3991 transaction_ = NULL; 3992 return false; 3993 } 3994 if (database_id_ < 0) 3995 database_id_ = blob_entry_key.database_id(); 3996 else 3997 DCHECK_EQ(database_id_, blob_entry_key.database_id()); 3998 std::string blob_entry_key_bytes = blob_entry_key.Encode(); 3999 bool found; 4000 std::string blob_entry_value_bytes; 4001 leveldb::Status s = transaction_->Get( 4002 blob_entry_key_bytes, &blob_entry_value_bytes, &found); 4003 if (s.ok() && found) { 4004 std::vector<IndexedDBBlobInfo> blob_info; 4005 if (!DecodeBlobData(blob_entry_value_bytes, &blob_info)) { 4006 INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); 4007 transaction_ = NULL; 4008 return false; 4009 } 4010 std::vector<IndexedDBBlobInfo>::iterator blob_info_iter; 4011 for (blob_info_iter = blob_info.begin(); 4012 blob_info_iter != blob_info.end(); 4013 ++blob_info_iter) 4014 blobs_to_remove_.push_back( 4015 std::make_pair(database_id_, blob_info_iter->key())); 4016 transaction_->Remove(blob_entry_key_bytes); 4017 } 4018 } 4019 } 4020 return true; 4021 } 4022 4023 leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() { 4024 IndexedDBActiveBlobRegistry* registry = 4025 backing_store_->active_blob_registry(); 4026 BlobJournalType::iterator iter; 4027 BlobJournalType primary_journal, live_blob_journal; 4028 for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end(); 4029 ++iter) { 4030 if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second)) 4031 live_blob_journal.push_back(*iter); 4032 else 4033 primary_journal.push_back(*iter); 4034 } 4035 UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal); 4036 leveldb::Status s = 4037 MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal); 4038 if (!s.ok()) 4039 return s; 4040 // To signal how many blobs need attention right now. 4041 blobs_to_remove_.swap(primary_journal); 4042 return leveldb::Status::OK(); 4043 } 4044 4045 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne( 4046 scoped_refptr<BlobWriteCallback> callback) { 4047 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne"); 4048 DCHECK(transaction_.get()); 4049 DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread()); 4050 4051 leveldb::Status s; 4052 4053 s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); 4054 if (!s.ok()) { 4055 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); 4056 transaction_ = NULL; 4057 return s; 4058 } 4059 4060 BlobEntryKeyValuePairVec new_blob_entries; 4061 WriteDescriptorVec new_files_to_write; 4062 s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write); 4063 if (!s.ok()) { 4064 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); 4065 transaction_ = NULL; 4066 return s; 4067 } 4068 4069 DCHECK(!new_files_to_write.size() || 4070 KeyPrefix::IsValidDatabaseId(database_id_)); 4071 if (!CollectBlobFilesToRemove()) { 4072 INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); 4073 transaction_ = NULL; 4074 return InternalInconsistencyStatus(); 4075 } 4076 4077 if (new_files_to_write.size()) { 4078 // This kicks off the writes of the new blobs, if any. 4079 // This call will zero out new_blob_entries and new_files_to_write. 4080 WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback); 4081 // Remove the add journal, if any; once the blobs are written, and we 4082 // commit, this will do the cleanup. 4083 ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode()); 4084 } else { 4085 callback->Run(true); 4086 } 4087 4088 return leveldb::Status::OK(); 4089 } 4090 4091 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() { 4092 IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo"); 4093 leveldb::Status s; 4094 if (blobs_to_remove_.size()) { 4095 s = SortBlobsToRemove(); 4096 if (!s.ok()) { 4097 INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD); 4098 transaction_ = NULL; 4099 return s; 4100 } 4101 } 4102 4103 s = transaction_->Commit(); 4104 transaction_ = NULL; 4105 4106 if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) { 4107 BlobChangeMap& target_map = backing_store_->incognito_blob_map_; 4108 BlobChangeMap::iterator iter; 4109 for (iter = blob_change_map_.begin(); iter != blob_change_map_.end(); 4110 ++iter) { 4111 BlobChangeMap::iterator target_record = target_map.find(iter->first); 4112 if (target_record != target_map.end()) { 4113 delete target_record->second; 4114 target_map.erase(target_record); 4115 } 4116 if (iter->second) { 4117 target_map[iter->first] = iter->second; 4118 iter->second = NULL; 4119 } 4120 } 4121 } 4122 if (!s.ok()) 4123 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); 4124 else if (blobs_to_remove_.size()) 4125 s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode()); 4126 4127 return s; 4128 } 4129 4130 4131 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper 4132 : public IndexedDBBackingStore::BlobWriteCallback { 4133 public: 4134 BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction, 4135 scoped_refptr<BlobWriteCallback> callback) 4136 : transaction_(transaction), callback_(callback) {} 4137 virtual void Run(bool succeeded) OVERRIDE { 4138 callback_->Run(succeeded); 4139 if (succeeded) // Else it's already been deleted during rollback. 4140 transaction_->chained_blob_writer_ = NULL; 4141 } 4142 4143 private: 4144 virtual ~BlobWriteCallbackWrapper() {} 4145 friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>; 4146 4147 IndexedDBBackingStore::Transaction* transaction_; 4148 scoped_refptr<BlobWriteCallback> callback_; 4149 4150 DISALLOW_COPY_AND_ASSIGN(BlobWriteCallbackWrapper); 4151 }; 4152 4153 void IndexedDBBackingStore::Transaction::WriteNewBlobs( 4154 BlobEntryKeyValuePairVec* new_blob_entries, 4155 WriteDescriptorVec* new_files_to_write, 4156 scoped_refptr<BlobWriteCallback> callback) { 4157 DCHECK_GT(new_files_to_write->size(), 0UL); 4158 DCHECK_GT(database_id_, 0); 4159 BlobEntryKeyValuePairVec::iterator blob_entry_iter; 4160 for (blob_entry_iter = new_blob_entries->begin(); 4161 blob_entry_iter != new_blob_entries->end(); 4162 ++blob_entry_iter) { 4163 // Add the new blob-table entry for each blob to the main transaction, or 4164 // remove any entry that may exist if there's no new one. 4165 if (!blob_entry_iter->second.size()) 4166 transaction_->Remove(blob_entry_iter->first.Encode()); 4167 else 4168 transaction_->Put(blob_entry_iter->first.Encode(), 4169 &blob_entry_iter->second); 4170 } 4171 // Creating the writer will start it going asynchronously. 4172 chained_blob_writer_ = 4173 new ChainedBlobWriterImpl(database_id_, 4174 backing_store_, 4175 new_files_to_write, 4176 new BlobWriteCallbackWrapper(this, callback)); 4177 } 4178 4179 void IndexedDBBackingStore::Transaction::Rollback() { 4180 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); 4181 if (chained_blob_writer_.get()) { 4182 chained_blob_writer_->Abort(); 4183 chained_blob_writer_ = NULL; 4184 } 4185 if (transaction_.get() == NULL) 4186 return; 4187 transaction_->Rollback(); 4188 transaction_ = NULL; 4189 } 4190 4191 IndexedDBBackingStore::BlobChangeRecord::BlobChangeRecord( 4192 const std::string& key, 4193 int64 object_store_id) 4194 : key_(key), object_store_id_(object_store_id) { 4195 } 4196 4197 IndexedDBBackingStore::BlobChangeRecord::~BlobChangeRecord() { 4198 } 4199 4200 void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo( 4201 std::vector<IndexedDBBlobInfo>* blob_info) { 4202 blob_info_.clear(); 4203 if (blob_info) 4204 blob_info_.swap(*blob_info); 4205 } 4206 4207 void IndexedDBBackingStore::BlobChangeRecord::SetHandles( 4208 ScopedVector<storage::BlobDataHandle>* handles) { 4209 handles_.clear(); 4210 if (handles) 4211 handles_.swap(*handles); 4212 } 4213 4214 scoped_ptr<IndexedDBBackingStore::BlobChangeRecord> 4215 IndexedDBBackingStore::BlobChangeRecord::Clone() const { 4216 scoped_ptr<IndexedDBBackingStore::BlobChangeRecord> record( 4217 new BlobChangeRecord(key_, object_store_id_)); 4218 record->blob_info_ = blob_info_; 4219 4220 ScopedVector<storage::BlobDataHandle>::const_iterator iter; 4221 for (iter = handles_.begin(); iter != handles_.end(); ++iter) 4222 record->handles_.push_back(new storage::BlobDataHandle(**iter)); 4223 return record.Pass(); 4224 } 4225 4226 leveldb::Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded( 4227 int64 database_id, 4228 int64 object_store_id, 4229 const std::string& object_store_data_key, 4230 std::vector<IndexedDBBlobInfo>* blob_info, 4231 ScopedVector<storage::BlobDataHandle>* handles) { 4232 if (!blob_info || blob_info->empty()) { 4233 blob_change_map_.erase(object_store_data_key); 4234 incognito_blob_map_.erase(object_store_data_key); 4235 4236 BlobEntryKey blob_entry_key; 4237 StringPiece leveldb_key_piece(object_store_data_key); 4238 if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece, 4239 &blob_entry_key)) { 4240 NOTREACHED(); 4241 return InternalInconsistencyStatus(); 4242 } 4243 std::string value; 4244 bool found = false; 4245 leveldb::Status s = 4246 transaction()->Get(blob_entry_key.Encode(), &value, &found); 4247 if (!s.ok()) 4248 return s; 4249 if (!found) 4250 return leveldb::Status::OK(); 4251 } 4252 PutBlobInfo( 4253 database_id, object_store_id, object_store_data_key, blob_info, handles); 4254 return leveldb::Status::OK(); 4255 } 4256 4257 // This is storing an info, even if empty, even if the previous key had no blob 4258 // info that we know of. It duplicates a bunch of information stored in the 4259 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the 4260 // changes to exists or index keys here. 4261 void IndexedDBBackingStore::Transaction::PutBlobInfo( 4262 int64 database_id, 4263 int64 object_store_id, 4264 const std::string& object_store_data_key, 4265 std::vector<IndexedDBBlobInfo>* blob_info, 4266 ScopedVector<storage::BlobDataHandle>* handles) { 4267 DCHECK_GT(object_store_data_key.size(), 0UL); 4268 if (database_id_ < 0) 4269 database_id_ = database_id; 4270 DCHECK_EQ(database_id_, database_id); 4271 4272 BlobChangeMap::iterator it = blob_change_map_.find(object_store_data_key); 4273 BlobChangeRecord* record = NULL; 4274 if (it == blob_change_map_.end()) { 4275 record = new BlobChangeRecord(object_store_data_key, object_store_id); 4276 blob_change_map_[object_store_data_key] = record; 4277 } else { 4278 record = it->second; 4279 } 4280 DCHECK_EQ(record->object_store_id(), object_store_id); 4281 record->SetBlobInfo(blob_info); 4282 record->SetHandles(handles); 4283 DCHECK(!handles || !handles->size()); 4284 } 4285 4286 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( 4287 const GURL& url, 4288 int64_t key, 4289 int64_t size) 4290 : is_file_(false), url_(url), key_(key), size_(size) { 4291 } 4292 4293 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor( 4294 const FilePath& file_path, 4295 int64_t key, 4296 int64_t size, 4297 base::Time last_modified) 4298 : is_file_(true), 4299 file_path_(file_path), 4300 key_(key), 4301 size_(size), 4302 last_modified_(last_modified) { 4303 } 4304 4305 } // namespace content 4306