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/file_util.h" 8 #include "base/logging.h" 9 #include "base/metrics/histogram.h" 10 #include "base/strings/string_piece.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" 14 #include "content/browser/indexed_db/indexed_db_metadata.h" 15 #include "content/browser/indexed_db/indexed_db_tracing.h" 16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" 17 #include "content/browser/indexed_db/leveldb/leveldb_database.h" 18 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" 19 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" 20 #include "content/common/indexed_db/indexed_db_key.h" 21 #include "content/common/indexed_db/indexed_db_key_path.h" 22 #include "content/common/indexed_db/indexed_db_key_range.h" 23 #include "third_party/WebKit/public/platform/WebIDBTypes.h" 24 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" 25 #include "third_party/leveldatabase/env_chromium.h" 26 #include "webkit/common/database/database_identifier.h" 27 28 using base::StringPiece; 29 30 namespace content { 31 32 namespace { 33 34 static std::string ComputeOriginIdentifier(const GURL& origin_url) { 35 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; 36 } 37 38 static base::FilePath ComputeFileName(const GURL& origin_url) { 39 return base::FilePath() 40 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url)) 41 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb")); 42 } 43 44 } // namespace 45 46 static const int64 kKeyGeneratorInitialNumber = 47 1; // From the IndexedDB specification. 48 49 enum IndexedDBBackingStoreErrorSource { 50 // 0 - 2 are no longer used. 51 FIND_KEY_IN_INDEX = 3, 52 GET_IDBDATABASE_METADATA, 53 GET_INDEXES, 54 GET_KEY_GENERATOR_CURRENT_NUMBER, 55 GET_OBJECT_STORES, 56 GET_RECORD, 57 KEY_EXISTS_IN_OBJECT_STORE, 58 LOAD_CURRENT_ROW, 59 SET_UP_METADATA, 60 GET_PRIMARY_KEY_VIA_INDEX, 61 KEY_EXISTS_IN_INDEX, 62 VERSION_EXISTS, 63 DELETE_OBJECT_STORE, 64 SET_MAX_OBJECT_STORE_ID, 65 SET_MAX_INDEX_ID, 66 GET_NEW_DATABASE_ID, 67 GET_NEW_VERSION_NUMBER, 68 CREATE_IDBDATABASE_METADATA, 69 DELETE_DATABASE, 70 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro 71 GET_DATABASE_NAMES, 72 INTERNAL_ERROR_MAX, 73 }; 74 75 static void RecordInternalError(const char* type, 76 IndexedDBBackingStoreErrorSource location) { 77 std::string name; 78 name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); 79 base::Histogram::FactoryGet(name, 80 1, 81 INTERNAL_ERROR_MAX, 82 INTERNAL_ERROR_MAX + 1, 83 base::HistogramBase::kUmaTargetedHistogramFlag) 84 ->Add(location); 85 } 86 87 // Use to signal conditions that usually indicate developer error, but 88 // could be caused by data corruption. A macro is used instead of an 89 // inline function so that the assert and log report the line number. 90 #define REPORT_ERROR(type, location) \ 91 do { \ 92 LOG(ERROR) << "IndexedDB " type " Error: " #location; \ 93 NOTREACHED(); \ 94 RecordInternalError(type, location); \ 95 } while (0) 96 97 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location) 98 #define INTERNAL_CONSISTENCY_ERROR(location) \ 99 REPORT_ERROR("Consistency", location) 100 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location) 101 102 static void PutBool(LevelDBTransaction* transaction, 103 const StringPiece& key, 104 bool value) { 105 std::string buffer; 106 EncodeBool(value, &buffer); 107 transaction->Put(key, &buffer); 108 } 109 110 template <typename DBOrTransaction> 111 static bool GetInt(DBOrTransaction* db, 112 const StringPiece& key, 113 int64* found_int, 114 bool* found) { 115 std::string result; 116 bool ok = db->Get(key, &result, found); 117 if (!ok) 118 return false; 119 if (!*found) 120 return true; 121 StringPiece slice(result); 122 return DecodeInt(&slice, found_int) && slice.empty(); 123 } 124 125 static void PutInt(LevelDBTransaction* transaction, 126 const StringPiece& key, 127 int64 value) { 128 DCHECK_GE(value, 0); 129 std::string buffer; 130 EncodeInt(value, &buffer); 131 transaction->Put(key, &buffer); 132 } 133 134 template <typename DBOrTransaction> 135 WARN_UNUSED_RESULT static bool GetVarInt(DBOrTransaction* db, 136 const StringPiece& key, 137 int64* found_int, 138 bool* found) { 139 std::string result; 140 bool ok = db->Get(key, &result, found); 141 if (!ok) 142 return false; 143 if (!*found) 144 return true; 145 StringPiece slice(result); 146 return DecodeVarInt(&slice, found_int) && slice.empty(); 147 } 148 149 static void PutVarInt(LevelDBTransaction* transaction, 150 const StringPiece& key, 151 int64 value) { 152 std::string buffer; 153 EncodeVarInt(value, &buffer); 154 transaction->Put(key, &buffer); 155 } 156 157 template <typename DBOrTransaction> 158 WARN_UNUSED_RESULT static bool GetString(DBOrTransaction* db, 159 const StringPiece& key, 160 base::string16* found_string, 161 bool* found) { 162 std::string result; 163 *found = false; 164 bool ok = db->Get(key, &result, found); 165 if (!ok) 166 return false; 167 if (!*found) 168 return true; 169 StringPiece slice(result); 170 return DecodeString(&slice, found_string) && slice.empty(); 171 } 172 173 static void PutString(LevelDBTransaction* transaction, 174 const StringPiece& key, 175 const base::string16& value) { 176 std::string buffer; 177 EncodeString(value, &buffer); 178 transaction->Put(key, &buffer); 179 } 180 181 static void PutIDBKeyPath(LevelDBTransaction* transaction, 182 const StringPiece& key, 183 const IndexedDBKeyPath& value) { 184 std::string buffer; 185 EncodeIDBKeyPath(value, &buffer); 186 transaction->Put(key, &buffer); 187 } 188 189 static int CompareKeys(const StringPiece& a, const StringPiece& b) { 190 return Compare(a, b, false /*index_keys*/); 191 } 192 193 static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) { 194 return Compare(a, b, true /*index_keys*/); 195 } 196 197 class Comparator : public LevelDBComparator { 198 public: 199 virtual int Compare(const StringPiece& a, const StringPiece& b) const 200 OVERRIDE { 201 return content::Compare(a, b, false /*index_keys*/); 202 } 203 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } 204 }; 205 206 // 0 - Initial version. 207 // 1 - Adds UserIntVersion to DatabaseMetaData. 208 // 2 - Adds DataVersion to to global metadata. 209 static const int64 kLatestKnownSchemaVersion = 2; 210 WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) { 211 int64 db_schema_version = 0; 212 bool found = false; 213 bool ok = GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found); 214 if (!ok) 215 return false; 216 if (!found) { 217 *known = true; 218 return true; 219 } 220 if (db_schema_version > kLatestKnownSchemaVersion) { 221 *known = false; 222 return true; 223 } 224 225 const uint32 latest_known_data_version = 226 blink::kSerializedScriptValueVersion; 227 int64 db_data_version = 0; 228 ok = GetInt(db, DataVersionKey::Encode(), &db_data_version, &found); 229 if (!ok) 230 return false; 231 if (!found) { 232 *known = true; 233 return true; 234 } 235 236 if (db_data_version > latest_known_data_version) { 237 *known = false; 238 return true; 239 } 240 241 *known = true; 242 return true; 243 } 244 245 WARN_UNUSED_RESULT static bool SetUpMetadata( 246 LevelDBDatabase* db, 247 const std::string& origin_identifier) { 248 const uint32 latest_known_data_version = 249 blink::kSerializedScriptValueVersion; 250 const std::string schema_version_key = SchemaVersionKey::Encode(); 251 const std::string data_version_key = DataVersionKey::Encode(); 252 253 scoped_refptr<LevelDBTransaction> transaction = new LevelDBTransaction(db); 254 255 int64 db_schema_version = 0; 256 int64 db_data_version = 0; 257 bool found = false; 258 bool ok = 259 GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); 260 if (!ok) { 261 INTERNAL_READ_ERROR(SET_UP_METADATA); 262 return false; 263 } 264 if (!found) { 265 // Initialize new backing store. 266 db_schema_version = kLatestKnownSchemaVersion; 267 PutInt(transaction.get(), schema_version_key, db_schema_version); 268 db_data_version = latest_known_data_version; 269 PutInt(transaction.get(), data_version_key, db_data_version); 270 } else { 271 // Upgrade old backing store. 272 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); 273 if (db_schema_version < 1) { 274 db_schema_version = 1; 275 PutInt(transaction.get(), schema_version_key, db_schema_version); 276 const std::string start_key = 277 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier); 278 const std::string stop_key = 279 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier); 280 scoped_ptr<LevelDBIterator> it = db->CreateIterator(); 281 for (it->Seek(start_key); 282 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 283 it->Next()) { 284 int64 database_id = 0; 285 found = false; 286 bool ok = GetInt(transaction.get(), it->Key(), &database_id, &found); 287 if (!ok) { 288 INTERNAL_READ_ERROR(SET_UP_METADATA); 289 return false; 290 } 291 if (!found) { 292 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA); 293 return false; 294 } 295 std::string int_version_key = DatabaseMetaDataKey::Encode( 296 database_id, DatabaseMetaDataKey::USER_INT_VERSION); 297 PutVarInt(transaction.get(), 298 int_version_key, 299 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 300 } 301 } 302 if (db_schema_version < 2) { 303 db_schema_version = 2; 304 PutInt(transaction.get(), schema_version_key, db_schema_version); 305 db_data_version = blink::kSerializedScriptValueVersion; 306 PutInt(transaction.get(), data_version_key, db_data_version); 307 } 308 } 309 310 // All new values will be written using this serialization version. 311 found = false; 312 ok = GetInt(transaction.get(), data_version_key, &db_data_version, &found); 313 if (!ok) { 314 INTERNAL_READ_ERROR(SET_UP_METADATA); 315 return false; 316 } 317 if (!found) { 318 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA); 319 return false; 320 } 321 if (db_data_version < latest_known_data_version) { 322 db_data_version = latest_known_data_version; 323 PutInt(transaction.get(), data_version_key, db_data_version); 324 } 325 326 DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion); 327 DCHECK_EQ(db_data_version, latest_known_data_version); 328 329 if (!transaction->Commit()) { 330 INTERNAL_WRITE_ERROR(SET_UP_METADATA); 331 return false; 332 } 333 return true; 334 } 335 336 template <typename DBOrTransaction> 337 WARN_UNUSED_RESULT static bool GetMaxObjectStoreId(DBOrTransaction* db, 338 int64 database_id, 339 int64* max_object_store_id) { 340 const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode( 341 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); 342 bool ok = 343 GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id); 344 return ok; 345 } 346 347 template <typename DBOrTransaction> 348 WARN_UNUSED_RESULT static bool GetMaxObjectStoreId( 349 DBOrTransaction* db, 350 const std::string& max_object_store_id_key, 351 int64* max_object_store_id) { 352 *max_object_store_id = -1; 353 bool found = false; 354 bool ok = GetInt(db, max_object_store_id_key, max_object_store_id, &found); 355 if (!ok) 356 return false; 357 if (!found) 358 *max_object_store_id = 0; 359 360 DCHECK_GE(*max_object_store_id, 0); 361 return true; 362 } 363 364 class DefaultLevelDBFactory : public LevelDBFactory { 365 public: 366 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, 367 const LevelDBComparator* comparator, 368 scoped_ptr<LevelDBDatabase>* db, 369 bool* is_disk_full) OVERRIDE { 370 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); 371 } 372 virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { 373 return LevelDBDatabase::Destroy(file_name); 374 } 375 }; 376 377 IndexedDBBackingStore::IndexedDBBackingStore( 378 const GURL& origin_url, 379 scoped_ptr<LevelDBDatabase> db, 380 scoped_ptr<LevelDBComparator> comparator) 381 : origin_url_(origin_url), 382 origin_identifier_(ComputeOriginIdentifier(origin_url)), 383 db_(db.Pass()), 384 comparator_(comparator.Pass()) {} 385 386 IndexedDBBackingStore::~IndexedDBBackingStore() { 387 // db_'s destructor uses comparator_. The order of destruction is important. 388 db_.reset(); 389 comparator_.reset(); 390 } 391 392 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( 393 const std::string& primary_key, 394 int64 version) 395 : primary_key_(primary_key), version_(version) { 396 DCHECK(!primary_key.empty()); 397 } 398 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier() 399 : primary_key_(), version_(-1) {} 400 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {} 401 402 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {} 403 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {} 404 405 enum IndexedDBBackingStoreOpenResult { 406 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, 407 INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, 408 INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, 409 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, 410 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, 411 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, 412 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, 413 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, 414 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, 415 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, 416 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, 417 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED, 418 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, 419 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, 420 INDEXED_DB_BACKING_STORE_OPEN_MAX, 421 }; 422 423 // static 424 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( 425 const GURL& origin_url, 426 const base::FilePath& path_base, 427 blink::WebIDBDataLoss* data_loss, 428 std::string* data_loss_message, 429 bool* disk_full) { 430 *data_loss = blink::WebIDBDataLossNone; 431 DefaultLevelDBFactory leveldb_factory; 432 return IndexedDBBackingStore::Open(origin_url, 433 path_base, 434 data_loss, 435 data_loss_message, 436 disk_full, 437 &leveldb_factory); 438 } 439 440 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { 441 if (origin_url.host() == "docs.google.com") 442 return ".Docs"; 443 return std::string(); 444 } 445 446 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, 447 const GURL& origin_url) { 448 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus", 449 result, 450 INDEXED_DB_BACKING_STORE_OPEN_MAX); 451 const std::string suffix = OriginToCustomHistogramSuffix(origin_url); 452 // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used 453 // to generate a graph. So as not to alter the meaning of that graph, 454 // continue to collect all stats there (above) but also now collect docs stats 455 // separately (below). 456 if (!suffix.empty()) { 457 base::LinearHistogram::FactoryGet( 458 "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix, 459 1, 460 INDEXED_DB_BACKING_STORE_OPEN_MAX, 461 INDEXED_DB_BACKING_STORE_OPEN_MAX + 1, 462 base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result); 463 } 464 } 465 466 static bool IsPathTooLong(const base::FilePath& leveldb_dir) { 467 int limit = file_util::GetMaximumPathComponentLength(leveldb_dir.DirName()); 468 if (limit == -1) { 469 DLOG(WARNING) << "GetMaximumPathComponentLength returned -1"; 470 // In limited testing, ChromeOS returns 143, other OSes 255. 471 #if defined(OS_CHROMEOS) 472 limit = 143; 473 #else 474 limit = 255; 475 #endif 476 } 477 size_t component_length = leveldb_dir.BaseName().value().length(); 478 if (component_length > static_cast<uint32_t>(limit)) { 479 DLOG(WARNING) << "Path component length (" << component_length 480 << ") exceeds maximum (" << limit 481 << ") allowed by this filesystem."; 482 const int min = 140; 483 const int max = 300; 484 const int num_buckets = 12; 485 UMA_HISTOGRAM_CUSTOM_COUNTS( 486 "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength", 487 component_length, 488 min, 489 max, 490 num_buckets); 491 return true; 492 } 493 return false; 494 } 495 496 // static 497 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( 498 const GURL& origin_url, 499 const base::FilePath& path_base, 500 blink::WebIDBDataLoss* data_loss, 501 std::string* data_loss_message, 502 bool* is_disk_full, 503 LevelDBFactory* leveldb_factory) { 504 IDB_TRACE("IndexedDBBackingStore::Open"); 505 DCHECK(!path_base.empty()); 506 *data_loss = blink::WebIDBDataLossNone; 507 *data_loss_message = ""; 508 *is_disk_full = false; 509 510 scoped_ptr<LevelDBComparator> comparator(new Comparator()); 511 512 if (!IsStringASCII(path_base.AsUTF8Unsafe())) { 513 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, 514 origin_url); 515 } 516 if (!base::CreateDirectory(path_base)) { 517 LOG(ERROR) << "Unable to create IndexedDB database path " 518 << path_base.AsUTF8Unsafe(); 519 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, 520 origin_url); 521 return scoped_refptr<IndexedDBBackingStore>(); 522 } 523 524 const base::FilePath file_path = 525 path_base.Append(ComputeFileName(origin_url)); 526 527 if (IsPathTooLong(file_path)) { 528 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, 529 origin_url); 530 return scoped_refptr<IndexedDBBackingStore>(); 531 } 532 533 scoped_ptr<LevelDBDatabase> db; 534 leveldb::Status status = leveldb_factory->OpenLevelDB( 535 file_path, comparator.get(), &db, is_disk_full); 536 537 DCHECK(!db == !status.ok()); 538 if (!status.ok()) { 539 if (leveldb_env::IndicatesDiskFull(status)) { 540 *is_disk_full = true; 541 } else if (leveldb_env::IsCorruption(status)) { 542 *data_loss = blink::WebIDBDataLossTotal; 543 *data_loss_message = leveldb_env::GetCorruptionMessage(status); 544 } 545 } 546 547 bool is_schema_known = false; 548 if (db) { 549 bool ok = IsSchemaKnown(db.get(), &is_schema_known); 550 if (!ok) { 551 LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as " 552 "failure to open"; 553 HistogramOpenStatus( 554 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, 555 origin_url); 556 db.reset(); 557 *data_loss = blink::WebIDBDataLossTotal; 558 *data_loss_message = "I/O error checking schema"; 559 } else if (!is_schema_known) { 560 LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it " 561 "as failure to open"; 562 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, 563 origin_url); 564 db.reset(); 565 *data_loss = blink::WebIDBDataLossTotal; 566 *data_loss_message = "Unknown schema"; 567 } 568 } 569 570 DCHECK(status.ok() || !is_schema_known || leveldb_env::IsIOError(status) || 571 leveldb_env::IsCorruption(status)); 572 573 if (db) { 574 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url); 575 } else if (leveldb_env::IsIOError(status)) { 576 LOG(ERROR) << "Unable to open backing store, not trying to recover - " 577 << status.ToString(); 578 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, origin_url); 579 return scoped_refptr<IndexedDBBackingStore>(); 580 } else { 581 DCHECK(!is_schema_known || leveldb_env::IsCorruption(status)); 582 LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup"; 583 bool success = leveldb_factory->DestroyLevelDB(file_path); 584 if (!success) { 585 LOG(ERROR) << "IndexedDB backing store cleanup failed"; 586 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, 587 origin_url); 588 return scoped_refptr<IndexedDBBackingStore>(); 589 } 590 591 LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening"; 592 leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, NULL); 593 if (!db) { 594 LOG(ERROR) << "IndexedDB backing store reopen after recovery failed"; 595 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, 596 origin_url); 597 return scoped_refptr<IndexedDBBackingStore>(); 598 } 599 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, 600 origin_url); 601 } 602 603 if (!db) { 604 NOTREACHED(); 605 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, 606 origin_url); 607 return scoped_refptr<IndexedDBBackingStore>(); 608 } 609 610 return Create(origin_url, db.Pass(), comparator.Pass()); 611 } 612 613 // static 614 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( 615 const GURL& origin_url) { 616 DefaultLevelDBFactory leveldb_factory; 617 return IndexedDBBackingStore::OpenInMemory(origin_url, &leveldb_factory); 618 } 619 620 // static 621 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( 622 const GURL& origin_url, 623 LevelDBFactory* leveldb_factory) { 624 IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); 625 626 scoped_ptr<LevelDBComparator> comparator(new Comparator()); 627 scoped_ptr<LevelDBDatabase> db = 628 LevelDBDatabase::OpenInMemory(comparator.get()); 629 if (!db) { 630 LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; 631 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, 632 origin_url); 633 return scoped_refptr<IndexedDBBackingStore>(); 634 } 635 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url); 636 637 return Create(origin_url, db.Pass(), comparator.Pass()); 638 } 639 640 // static 641 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( 642 const GURL& origin_url, 643 scoped_ptr<LevelDBDatabase> db, 644 scoped_ptr<LevelDBComparator> comparator) { 645 // TODO(jsbell): Handle comparator name changes. 646 647 scoped_refptr<IndexedDBBackingStore> backing_store( 648 new IndexedDBBackingStore(origin_url, db.Pass(), comparator.Pass())); 649 if (!SetUpMetadata(backing_store->db_.get(), 650 backing_store->origin_identifier_)) 651 return scoped_refptr<IndexedDBBackingStore>(); 652 653 return backing_store; 654 } 655 656 std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames() { 657 std::vector<base::string16> found_names; 658 const std::string start_key = 659 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_); 660 const std::string stop_key = 661 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_); 662 663 DCHECK(found_names.empty()); 664 665 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 666 for (it->Seek(start_key); 667 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 668 it->Next()) { 669 StringPiece slice(it->Key()); 670 DatabaseNameKey database_name_key; 671 if (!DatabaseNameKey::Decode(&slice, &database_name_key)) { 672 INTERNAL_CONSISTENCY_ERROR(GET_DATABASE_NAMES); 673 continue; 674 } 675 found_names.push_back(database_name_key.database_name()); 676 } 677 return found_names; 678 } 679 680 bool IndexedDBBackingStore::GetIDBDatabaseMetaData( 681 const base::string16& name, 682 IndexedDBDatabaseMetadata* metadata, 683 bool* found) { 684 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); 685 *found = false; 686 687 bool ok = GetInt(db_.get(), key, &metadata->id, found); 688 if (!ok) { 689 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); 690 return false; 691 } 692 if (!*found) 693 return true; 694 695 ok = GetString(db_.get(), 696 DatabaseMetaDataKey::Encode(metadata->id, 697 DatabaseMetaDataKey::USER_VERSION), 698 &metadata->version, 699 found); 700 if (!ok) { 701 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); 702 return false; 703 } 704 if (!*found) { 705 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); 706 return false; 707 } 708 709 ok = GetVarInt(db_.get(), 710 DatabaseMetaDataKey::Encode( 711 metadata->id, DatabaseMetaDataKey::USER_INT_VERSION), 712 &metadata->int_version, 713 found); 714 if (!ok) { 715 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); 716 return false; 717 } 718 if (!*found) { 719 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); 720 return false; 721 } 722 723 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) 724 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; 725 726 ok = GetMaxObjectStoreId( 727 db_.get(), metadata->id, &metadata->max_object_store_id); 728 if (!ok) { 729 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); 730 return false; 731 } 732 733 return true; 734 } 735 736 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBTransaction* transaction, 737 int64* new_id) { 738 *new_id = -1; 739 int64 max_database_id = -1; 740 bool found = false; 741 bool ok = 742 GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found); 743 if (!ok) { 744 INTERNAL_READ_ERROR(GET_NEW_DATABASE_ID); 745 return false; 746 } 747 if (!found) 748 max_database_id = 0; 749 750 DCHECK_GE(max_database_id, 0); 751 752 int64 database_id = max_database_id + 1; 753 PutInt(transaction, MaxDatabaseIdKey::Encode(), database_id); 754 *new_id = database_id; 755 return true; 756 } 757 758 bool IndexedDBBackingStore::CreateIDBDatabaseMetaData( 759 const base::string16& name, 760 const base::string16& version, 761 int64 int_version, 762 int64* row_id) { 763 scoped_refptr<LevelDBTransaction> transaction = 764 new LevelDBTransaction(db_.get()); 765 766 bool ok = GetNewDatabaseId(transaction.get(), row_id); 767 if (!ok) 768 return false; 769 DCHECK_GE(*row_id, 0); 770 771 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 772 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; 773 774 PutInt(transaction.get(), 775 DatabaseNameKey::Encode(origin_identifier_, name), 776 *row_id); 777 PutString( 778 transaction.get(), 779 DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION), 780 version); 781 PutVarInt(transaction.get(), 782 DatabaseMetaDataKey::Encode(*row_id, 783 DatabaseMetaDataKey::USER_INT_VERSION), 784 int_version); 785 if (!transaction->Commit()) { 786 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); 787 return false; 788 } 789 return true; 790 } 791 792 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( 793 IndexedDBBackingStore::Transaction* transaction, 794 int64 row_id, 795 int64 int_version) { 796 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 797 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; 798 DCHECK_GE(int_version, 0) << "int_version was " << int_version; 799 PutVarInt(transaction->transaction(), 800 DatabaseMetaDataKey::Encode(row_id, 801 DatabaseMetaDataKey::USER_INT_VERSION), 802 int_version); 803 return true; 804 } 805 806 static void DeleteRange(LevelDBTransaction* transaction, 807 const std::string& begin, 808 const std::string& end) { 809 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); 810 for (it->Seek(begin); it->IsValid() && CompareKeys(it->Key(), end) < 0; 811 it->Next()) 812 transaction->Remove(it->Key()); 813 } 814 815 bool IndexedDBBackingStore::DeleteDatabase(const base::string16& name) { 816 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); 817 scoped_ptr<LevelDBWriteOnlyTransaction> transaction = 818 LevelDBWriteOnlyTransaction::Create(db_.get()); 819 820 IndexedDBDatabaseMetadata metadata; 821 bool success = false; 822 bool ok = GetIDBDatabaseMetaData(name, &metadata, &success); 823 if (!ok) 824 return false; 825 if (!success) 826 return true; 827 828 const std::string start_key = DatabaseMetaDataKey::Encode( 829 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); 830 const std::string stop_key = DatabaseMetaDataKey::Encode( 831 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); 832 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 833 for (it->Seek(start_key); 834 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 835 it->Next()) 836 transaction->Remove(it->Key()); 837 838 const std::string key = DatabaseNameKey::Encode(origin_identifier_, name); 839 transaction->Remove(key); 840 841 if (!transaction->Commit()) { 842 INTERNAL_WRITE_ERROR(DELETE_DATABASE); 843 return false; 844 } 845 return true; 846 } 847 848 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, 849 const std::string& stop_key, 850 int64 object_store_id, 851 int64 meta_data_type) { 852 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 853 return false; 854 855 StringPiece slice(it->Key()); 856 ObjectStoreMetaDataKey meta_data_key; 857 bool ok = ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key); 858 DCHECK(ok); 859 if (meta_data_key.ObjectStoreId() != object_store_id) 860 return false; 861 if (meta_data_key.MetaDataType() != meta_data_type) 862 return false; 863 return true; 864 } 865 866 // TODO(jsbell): This should do some error handling rather than 867 // plowing ahead when bad data is encountered. 868 bool IndexedDBBackingStore::GetObjectStores( 869 int64 database_id, 870 IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) { 871 IDB_TRACE("IndexedDBBackingStore::GetObjectStores"); 872 if (!KeyPrefix::IsValidDatabaseId(database_id)) 873 return false; 874 const std::string start_key = 875 ObjectStoreMetaDataKey::Encode(database_id, 1, 0); 876 const std::string stop_key = 877 ObjectStoreMetaDataKey::EncodeMaxKey(database_id); 878 879 DCHECK(object_stores->empty()); 880 881 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 882 it->Seek(start_key); 883 while (it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 884 StringPiece slice(it->Key()); 885 ObjectStoreMetaDataKey meta_data_key; 886 bool ok = ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key); 887 DCHECK(ok); 888 if (meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) { 889 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 890 // Possible stale metadata, but don't fail the load. 891 it->Next(); 892 continue; 893 } 894 895 int64 object_store_id = meta_data_key.ObjectStoreId(); 896 897 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 898 // simplify. 899 base::string16 object_store_name; 900 { 901 StringPiece slice(it->Value()); 902 if (!DecodeString(&slice, &object_store_name) || !slice.empty()) 903 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 904 } 905 906 it->Next(); 907 if (!CheckObjectStoreAndMetaDataType(it.get(), 908 stop_key, 909 object_store_id, 910 ObjectStoreMetaDataKey::KEY_PATH)) { 911 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 912 break; 913 } 914 IndexedDBKeyPath key_path; 915 { 916 StringPiece slice(it->Value()); 917 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 918 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 919 } 920 921 it->Next(); 922 if (!CheckObjectStoreAndMetaDataType( 923 it.get(), 924 stop_key, 925 object_store_id, 926 ObjectStoreMetaDataKey::AUTO_INCREMENT)) { 927 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 928 break; 929 } 930 bool auto_increment; 931 { 932 StringPiece slice(it->Value()); 933 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) 934 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 935 } 936 937 it->Next(); // Is evicatble. 938 if (!CheckObjectStoreAndMetaDataType(it.get(), 939 stop_key, 940 object_store_id, 941 ObjectStoreMetaDataKey::EVICTABLE)) { 942 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 943 break; 944 } 945 946 it->Next(); // Last version. 947 if (!CheckObjectStoreAndMetaDataType( 948 it.get(), 949 stop_key, 950 object_store_id, 951 ObjectStoreMetaDataKey::LAST_VERSION)) { 952 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 953 break; 954 } 955 956 it->Next(); // Maximum index id allocated. 957 if (!CheckObjectStoreAndMetaDataType( 958 it.get(), 959 stop_key, 960 object_store_id, 961 ObjectStoreMetaDataKey::MAX_INDEX_ID)) { 962 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 963 break; 964 } 965 int64 max_index_id; 966 { 967 StringPiece slice(it->Value()); 968 if (!DecodeInt(&slice, &max_index_id) || !slice.empty()) 969 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 970 } 971 972 it->Next(); // [optional] has key path (is not null) 973 if (CheckObjectStoreAndMetaDataType(it.get(), 974 stop_key, 975 object_store_id, 976 ObjectStoreMetaDataKey::HAS_KEY_PATH)) { 977 bool has_key_path; 978 { 979 StringPiece slice(it->Value()); 980 if (!DecodeBool(&slice, &has_key_path)) 981 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 982 } 983 // This check accounts for two layers of legacy coding: 984 // (1) Initially, has_key_path was added to distinguish null vs. string. 985 // (2) Later, null vs. string vs. array was stored in the key_path itself. 986 // So this check is only relevant for string-type key_paths. 987 if (!has_key_path && 988 (key_path.type() == blink::WebIDBKeyPathTypeString && 989 !key_path.string().empty())) { 990 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 991 break; 992 } 993 if (!has_key_path) 994 key_path = IndexedDBKeyPath(); 995 it->Next(); 996 } 997 998 int64 key_generator_current_number = -1; 999 if (CheckObjectStoreAndMetaDataType( 1000 it.get(), 1001 stop_key, 1002 object_store_id, 1003 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) { 1004 StringPiece slice(it->Value()); 1005 if (!DecodeInt(&slice, &key_generator_current_number) || !slice.empty()) 1006 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 1007 1008 // TODO(jsbell): Return key_generator_current_number, cache in 1009 // object store, and write lazily to backing store. For now, 1010 // just assert that if it was written it was valid. 1011 DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber); 1012 it->Next(); 1013 } 1014 1015 IndexedDBObjectStoreMetadata metadata(object_store_name, 1016 object_store_id, 1017 key_path, 1018 auto_increment, 1019 max_index_id); 1020 if (!GetIndexes(database_id, object_store_id, &metadata.indexes)) 1021 return false; 1022 (*object_stores)[object_store_id] = metadata; 1023 } 1024 return true; 1025 } 1026 1027 WARN_UNUSED_RESULT static bool SetMaxObjectStoreId( 1028 LevelDBTransaction* transaction, 1029 int64 database_id, 1030 int64 object_store_id) { 1031 const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode( 1032 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); 1033 int64 max_object_store_id = -1; 1034 bool ok = GetMaxObjectStoreId( 1035 transaction, max_object_store_id_key, &max_object_store_id); 1036 if (!ok) { 1037 INTERNAL_READ_ERROR(SET_MAX_OBJECT_STORE_ID); 1038 return false; 1039 } 1040 1041 if (object_store_id <= max_object_store_id) { 1042 INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID); 1043 return false; 1044 } 1045 PutInt(transaction, max_object_store_id_key, object_store_id); 1046 return true; 1047 } 1048 1049 bool IndexedDBBackingStore::CreateObjectStore( 1050 IndexedDBBackingStore::Transaction* transaction, 1051 int64 database_id, 1052 int64 object_store_id, 1053 const base::string16& name, 1054 const IndexedDBKeyPath& key_path, 1055 bool auto_increment) { 1056 IDB_TRACE("IndexedDBBackingStore::CreateObjectStore"); 1057 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1058 return false; 1059 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1060 if (!SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id)) 1061 return false; 1062 1063 const std::string name_key = ObjectStoreMetaDataKey::Encode( 1064 database_id, object_store_id, ObjectStoreMetaDataKey::NAME); 1065 const std::string key_path_key = ObjectStoreMetaDataKey::Encode( 1066 database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH); 1067 const std::string auto_increment_key = ObjectStoreMetaDataKey::Encode( 1068 database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT); 1069 const std::string evictable_key = ObjectStoreMetaDataKey::Encode( 1070 database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE); 1071 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1072 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1073 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 1074 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 1075 const std::string has_key_path_key = ObjectStoreMetaDataKey::Encode( 1076 database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH); 1077 const std::string key_generator_current_number_key = 1078 ObjectStoreMetaDataKey::Encode( 1079 database_id, 1080 object_store_id, 1081 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1082 const std::string names_key = ObjectStoreNamesKey::Encode(database_id, name); 1083 1084 PutString(leveldb_transaction, name_key, name); 1085 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 1086 PutInt(leveldb_transaction, auto_increment_key, auto_increment); 1087 PutInt(leveldb_transaction, evictable_key, false); 1088 PutInt(leveldb_transaction, last_version_key, 1); 1089 PutInt(leveldb_transaction, max_index_id_key, kMinimumIndexId); 1090 PutBool(leveldb_transaction, has_key_path_key, !key_path.IsNull()); 1091 PutInt(leveldb_transaction, 1092 key_generator_current_number_key, 1093 kKeyGeneratorInitialNumber); 1094 PutInt(leveldb_transaction, names_key, object_store_id); 1095 return true; 1096 } 1097 1098 bool IndexedDBBackingStore::DeleteObjectStore( 1099 IndexedDBBackingStore::Transaction* transaction, 1100 int64 database_id, 1101 int64 object_store_id) { 1102 IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore"); 1103 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1104 return false; 1105 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1106 1107 base::string16 object_store_name; 1108 bool found = false; 1109 bool ok = GetString( 1110 leveldb_transaction, 1111 ObjectStoreMetaDataKey::Encode( 1112 database_id, object_store_id, ObjectStoreMetaDataKey::NAME), 1113 &object_store_name, 1114 &found); 1115 if (!ok) { 1116 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); 1117 return false; 1118 } 1119 if (!found) { 1120 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); 1121 return false; 1122 } 1123 1124 DeleteRange( 1125 leveldb_transaction, 1126 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), 1127 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); 1128 1129 leveldb_transaction->Remove( 1130 ObjectStoreNamesKey::Encode(database_id, object_store_name)); 1131 1132 DeleteRange(leveldb_transaction, 1133 IndexFreeListKey::Encode(database_id, object_store_id, 0), 1134 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); 1135 DeleteRange(leveldb_transaction, 1136 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), 1137 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); 1138 1139 return ClearObjectStore(transaction, database_id, object_store_id); 1140 } 1141 1142 bool IndexedDBBackingStore::GetRecord( 1143 IndexedDBBackingStore::Transaction* transaction, 1144 int64 database_id, 1145 int64 object_store_id, 1146 const IndexedDBKey& key, 1147 std::string* record) { 1148 IDB_TRACE("IndexedDBBackingStore::GetRecord"); 1149 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1150 return false; 1151 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1152 1153 const std::string leveldb_key = 1154 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1155 std::string data; 1156 1157 record->clear(); 1158 1159 bool found = false; 1160 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); 1161 if (!ok) { 1162 INTERNAL_READ_ERROR(GET_RECORD); 1163 return false; 1164 } 1165 if (!found) 1166 return true; 1167 if (data.empty()) { 1168 INTERNAL_READ_ERROR(GET_RECORD); 1169 return false; 1170 } 1171 1172 int64 version; 1173 StringPiece slice(data); 1174 if (!DecodeVarInt(&slice, &version)) { 1175 INTERNAL_READ_ERROR(GET_RECORD); 1176 return false; 1177 } 1178 1179 *record = slice.as_string(); 1180 return true; 1181 } 1182 1183 WARN_UNUSED_RESULT static bool GetNewVersionNumber( 1184 LevelDBTransaction* transaction, 1185 int64 database_id, 1186 int64 object_store_id, 1187 int64* new_version_number) { 1188 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1189 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1190 1191 *new_version_number = -1; 1192 int64 last_version = -1; 1193 bool found = false; 1194 bool ok = GetInt(transaction, last_version_key, &last_version, &found); 1195 if (!ok) { 1196 INTERNAL_READ_ERROR(GET_NEW_VERSION_NUMBER); 1197 return false; 1198 } 1199 if (!found) 1200 last_version = 0; 1201 1202 DCHECK_GE(last_version, 0); 1203 1204 int64 version = last_version + 1; 1205 PutInt(transaction, last_version_key, version); 1206 1207 // TODO(jsbell): Think about how we want to handle the overflow scenario. 1208 DCHECK(version > last_version); 1209 1210 *new_version_number = version; 1211 return true; 1212 } 1213 1214 bool IndexedDBBackingStore::PutRecord( 1215 IndexedDBBackingStore::Transaction* transaction, 1216 int64 database_id, 1217 int64 object_store_id, 1218 const IndexedDBKey& key, 1219 const std::string& value, 1220 RecordIdentifier* record_identifier) { 1221 IDB_TRACE("IndexedDBBackingStore::PutRecord"); 1222 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1223 return false; 1224 DCHECK(key.IsValid()); 1225 1226 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1227 int64 version = -1; 1228 bool ok = GetNewVersionNumber( 1229 leveldb_transaction, database_id, object_store_id, &version); 1230 if (!ok) 1231 return false; 1232 DCHECK_GE(version, 0); 1233 const std::string object_storedata_key = 1234 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1235 1236 std::string v; 1237 EncodeVarInt(version, &v); 1238 v.append(value); 1239 1240 leveldb_transaction->Put(object_storedata_key, &v); 1241 1242 const std::string exists_entry_key = 1243 ExistsEntryKey::Encode(database_id, object_store_id, key); 1244 std::string version_encoded; 1245 EncodeInt(version, &version_encoded); 1246 leveldb_transaction->Put(exists_entry_key, &version_encoded); 1247 1248 std::string key_encoded; 1249 EncodeIDBKey(key, &key_encoded); 1250 record_identifier->Reset(key_encoded, version); 1251 return true; 1252 } 1253 1254 bool IndexedDBBackingStore::ClearObjectStore( 1255 IndexedDBBackingStore::Transaction* transaction, 1256 int64 database_id, 1257 int64 object_store_id) { 1258 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); 1259 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1260 return false; 1261 const std::string start_key = 1262 KeyPrefix(database_id, object_store_id).Encode(); 1263 const std::string stop_key = 1264 KeyPrefix(database_id, object_store_id + 1).Encode(); 1265 1266 DeleteRange(transaction->transaction(), start_key, stop_key); 1267 return true; 1268 } 1269 1270 bool IndexedDBBackingStore::DeleteRecord( 1271 IndexedDBBackingStore::Transaction* transaction, 1272 int64 database_id, 1273 int64 object_store_id, 1274 const RecordIdentifier& record_identifier) { 1275 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); 1276 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1277 return false; 1278 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1279 1280 const std::string object_store_data_key = ObjectStoreDataKey::Encode( 1281 database_id, object_store_id, record_identifier.primary_key()); 1282 leveldb_transaction->Remove(object_store_data_key); 1283 1284 const std::string exists_entry_key = ExistsEntryKey::Encode( 1285 database_id, object_store_id, record_identifier.primary_key()); 1286 leveldb_transaction->Remove(exists_entry_key); 1287 return true; 1288 } 1289 1290 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( 1291 IndexedDBBackingStore::Transaction* transaction, 1292 int64 database_id, 1293 int64 object_store_id, 1294 int64* key_generator_current_number) { 1295 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1296 return false; 1297 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1298 1299 const std::string key_generator_current_number_key = 1300 ObjectStoreMetaDataKey::Encode( 1301 database_id, 1302 object_store_id, 1303 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1304 1305 *key_generator_current_number = -1; 1306 std::string data; 1307 1308 bool found = false; 1309 bool ok = 1310 leveldb_transaction->Get(key_generator_current_number_key, &data, &found); 1311 if (!ok) { 1312 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1313 return false; 1314 } 1315 if (found && !data.empty()) { 1316 StringPiece slice(data); 1317 if (!DecodeInt(&slice, key_generator_current_number) || !slice.empty()) { 1318 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1319 return false; 1320 } 1321 return true; 1322 } 1323 1324 // Previously, the key generator state was not stored explicitly 1325 // but derived from the maximum numeric key present in existing 1326 // data. This violates the spec as the data may be cleared but the 1327 // key generator state must be preserved. 1328 // TODO(jsbell): Fix this for all stores on database open? 1329 const std::string start_key = 1330 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 1331 const std::string stop_key = 1332 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 1333 1334 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 1335 int64 max_numeric_key = 0; 1336 1337 for (it->Seek(start_key); 1338 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 1339 it->Next()) { 1340 StringPiece slice(it->Key()); 1341 ObjectStoreDataKey data_key; 1342 if (!ObjectStoreDataKey::Decode(&slice, &data_key)) { 1343 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1344 return false; 1345 } 1346 scoped_ptr<IndexedDBKey> user_key = data_key.user_key(); 1347 if (user_key->type() == blink::WebIDBKeyTypeNumber) { 1348 int64 n = static_cast<int64>(user_key->number()); 1349 if (n > max_numeric_key) 1350 max_numeric_key = n; 1351 } 1352 } 1353 1354 *key_generator_current_number = max_numeric_key + 1; 1355 return true; 1356 } 1357 1358 bool IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber( 1359 IndexedDBBackingStore::Transaction* transaction, 1360 int64 database_id, 1361 int64 object_store_id, 1362 int64 new_number, 1363 bool check_current) { 1364 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1365 return false; 1366 1367 if (check_current) { 1368 int64 current_number; 1369 bool ok = GetKeyGeneratorCurrentNumber( 1370 transaction, database_id, object_store_id, ¤t_number); 1371 if (!ok) 1372 return false; 1373 if (new_number <= current_number) 1374 return true; 1375 } 1376 1377 const std::string key_generator_current_number_key = 1378 ObjectStoreMetaDataKey::Encode( 1379 database_id, 1380 object_store_id, 1381 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1382 PutInt( 1383 transaction->transaction(), key_generator_current_number_key, new_number); 1384 return true; 1385 } 1386 1387 bool IndexedDBBackingStore::KeyExistsInObjectStore( 1388 IndexedDBBackingStore::Transaction* transaction, 1389 int64 database_id, 1390 int64 object_store_id, 1391 const IndexedDBKey& key, 1392 RecordIdentifier* found_record_identifier, 1393 bool* found) { 1394 IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore"); 1395 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1396 return false; 1397 *found = false; 1398 const std::string leveldb_key = 1399 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1400 std::string data; 1401 1402 bool ok = transaction->transaction()->Get(leveldb_key, &data, found); 1403 if (!ok) { 1404 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); 1405 return false; 1406 } 1407 if (!*found) 1408 return true; 1409 if (!data.size()) { 1410 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); 1411 return false; 1412 } 1413 1414 int64 version; 1415 StringPiece slice(data); 1416 if (!DecodeVarInt(&slice, &version)) 1417 return false; 1418 1419 std::string encoded_key; 1420 EncodeIDBKey(key, &encoded_key); 1421 found_record_identifier->Reset(encoded_key, version); 1422 return true; 1423 } 1424 1425 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, 1426 const std::string& stop_key, 1427 int64 index_id, 1428 unsigned char meta_data_type) { 1429 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 1430 return false; 1431 1432 StringPiece slice(it->Key()); 1433 IndexMetaDataKey meta_data_key; 1434 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 1435 DCHECK(ok); 1436 if (meta_data_key.IndexId() != index_id) 1437 return false; 1438 if (meta_data_key.meta_data_type() != meta_data_type) 1439 return false; 1440 return true; 1441 } 1442 1443 // TODO(jsbell): This should do some error handling rather than plowing ahead 1444 // when bad data is encountered. 1445 bool IndexedDBBackingStore::GetIndexes( 1446 int64 database_id, 1447 int64 object_store_id, 1448 IndexedDBObjectStoreMetadata::IndexMap* indexes) { 1449 IDB_TRACE("IndexedDBBackingStore::GetIndexes"); 1450 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1451 return false; 1452 const std::string start_key = 1453 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0); 1454 const std::string stop_key = 1455 IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0); 1456 1457 DCHECK(indexes->empty()); 1458 1459 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 1460 it->Seek(start_key); 1461 while (it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 1462 StringPiece slice(it->Key()); 1463 IndexMetaDataKey meta_data_key; 1464 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 1465 DCHECK(ok); 1466 if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) { 1467 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1468 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail 1469 // the load. 1470 it->Next(); 1471 continue; 1472 } 1473 1474 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 1475 // simplify. 1476 int64 index_id = meta_data_key.IndexId(); 1477 base::string16 index_name; 1478 { 1479 StringPiece slice(it->Value()); 1480 if (!DecodeString(&slice, &index_name) || !slice.empty()) 1481 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1482 } 1483 1484 it->Next(); // unique flag 1485 if (!CheckIndexAndMetaDataKey( 1486 it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) { 1487 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1488 break; 1489 } 1490 bool index_unique; 1491 { 1492 StringPiece slice(it->Value()); 1493 if (!DecodeBool(&slice, &index_unique) || !slice.empty()) 1494 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1495 } 1496 1497 it->Next(); // key_path 1498 if (!CheckIndexAndMetaDataKey( 1499 it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) { 1500 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1501 break; 1502 } 1503 IndexedDBKeyPath key_path; 1504 { 1505 StringPiece slice(it->Value()); 1506 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 1507 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1508 } 1509 1510 it->Next(); // [optional] multi_entry flag 1511 bool index_multi_entry = false; 1512 if (CheckIndexAndMetaDataKey( 1513 it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) { 1514 StringPiece slice(it->Value()); 1515 if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty()) 1516 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1517 1518 it->Next(); 1519 } 1520 1521 (*indexes)[index_id] = IndexedDBIndexMetadata( 1522 index_name, index_id, key_path, index_unique, index_multi_entry); 1523 } 1524 return true; 1525 } 1526 1527 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, 1528 int64 database_id, 1529 int64 object_store_id, 1530 int64 index_id) { 1531 int64 max_index_id = -1; 1532 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 1533 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 1534 bool found = false; 1535 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); 1536 if (!ok) { 1537 INTERNAL_READ_ERROR(SET_MAX_INDEX_ID); 1538 return false; 1539 } 1540 if (!found) 1541 max_index_id = kMinimumIndexId; 1542 1543 if (index_id <= max_index_id) { 1544 INTERNAL_CONSISTENCY_ERROR(SET_MAX_INDEX_ID); 1545 return false; 1546 } 1547 1548 PutInt(transaction, max_index_id_key, index_id); 1549 return true; 1550 } 1551 1552 bool IndexedDBBackingStore::CreateIndex( 1553 IndexedDBBackingStore::Transaction* transaction, 1554 int64 database_id, 1555 int64 object_store_id, 1556 int64 index_id, 1557 const base::string16& name, 1558 const IndexedDBKeyPath& key_path, 1559 bool is_unique, 1560 bool is_multi_entry) { 1561 IDB_TRACE("IndexedDBBackingStore::CreateIndex"); 1562 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1563 return false; 1564 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1565 if (!SetMaxIndexId( 1566 leveldb_transaction, database_id, object_store_id, index_id)) 1567 return false; 1568 1569 const std::string name_key = IndexMetaDataKey::Encode( 1570 database_id, object_store_id, index_id, IndexMetaDataKey::NAME); 1571 const std::string unique_key = IndexMetaDataKey::Encode( 1572 database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE); 1573 const std::string key_path_key = IndexMetaDataKey::Encode( 1574 database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH); 1575 const std::string multi_entry_key = IndexMetaDataKey::Encode( 1576 database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY); 1577 1578 PutString(leveldb_transaction, name_key, name); 1579 PutBool(leveldb_transaction, unique_key, is_unique); 1580 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 1581 PutBool(leveldb_transaction, multi_entry_key, is_multi_entry); 1582 return true; 1583 } 1584 1585 bool IndexedDBBackingStore::DeleteIndex( 1586 IndexedDBBackingStore::Transaction* transaction, 1587 int64 database_id, 1588 int64 object_store_id, 1589 int64 index_id) { 1590 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); 1591 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1592 return false; 1593 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1594 1595 const std::string index_meta_data_start = 1596 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); 1597 const std::string index_meta_data_end = 1598 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 1599 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); 1600 1601 const std::string index_data_start = 1602 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 1603 const std::string index_data_end = 1604 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 1605 DeleteRange(leveldb_transaction, index_data_start, index_data_end); 1606 return true; 1607 } 1608 1609 bool IndexedDBBackingStore::PutIndexDataForRecord( 1610 IndexedDBBackingStore::Transaction* transaction, 1611 int64 database_id, 1612 int64 object_store_id, 1613 int64 index_id, 1614 const IndexedDBKey& key, 1615 const RecordIdentifier& record_identifier) { 1616 IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord"); 1617 DCHECK(key.IsValid()); 1618 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1619 return false; 1620 1621 std::string encoded_key; 1622 EncodeIDBKey(key, &encoded_key); 1623 1624 const std::string index_data_key = 1625 IndexDataKey::Encode(database_id, 1626 object_store_id, 1627 index_id, 1628 encoded_key, 1629 record_identifier.primary_key(), 1630 0); 1631 1632 std::string data; 1633 EncodeVarInt(record_identifier.version(), &data); 1634 data.append(record_identifier.primary_key()); 1635 1636 transaction->transaction()->Put(index_data_key, &data); 1637 return true; 1638 } 1639 1640 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, 1641 const std::string& target, 1642 std::string* found_key) { 1643 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); 1644 it->Seek(target); 1645 1646 if (!it->IsValid()) { 1647 it->SeekToLast(); 1648 if (!it->IsValid()) 1649 return false; 1650 } 1651 1652 while (CompareIndexKeys(it->Key(), target) > 0) { 1653 it->Prev(); 1654 if (!it->IsValid()) 1655 return false; 1656 } 1657 1658 do { 1659 *found_key = it->Key().as_string(); 1660 1661 // There can be several index keys that compare equal. We want the last one. 1662 it->Next(); 1663 } while (it->IsValid() && !CompareIndexKeys(it->Key(), target)); 1664 1665 return true; 1666 } 1667 1668 static bool VersionExists(LevelDBTransaction* transaction, 1669 int64 database_id, 1670 int64 object_store_id, 1671 int64 version, 1672 const std::string& encoded_primary_key, 1673 bool* exists) { 1674 const std::string key = 1675 ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key); 1676 std::string data; 1677 1678 bool ok = transaction->Get(key, &data, exists); 1679 if (!ok) { 1680 INTERNAL_READ_ERROR(VERSION_EXISTS); 1681 return false; 1682 } 1683 if (!*exists) 1684 return true; 1685 1686 StringPiece slice(data); 1687 int64 decoded; 1688 if (!DecodeInt(&slice, &decoded) || !slice.empty()) 1689 return false; 1690 *exists = (decoded == version); 1691 return true; 1692 } 1693 1694 bool IndexedDBBackingStore::FindKeyInIndex( 1695 IndexedDBBackingStore::Transaction* transaction, 1696 int64 database_id, 1697 int64 object_store_id, 1698 int64 index_id, 1699 const IndexedDBKey& key, 1700 std::string* found_encoded_primary_key, 1701 bool* found) { 1702 IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex"); 1703 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id)); 1704 1705 DCHECK(found_encoded_primary_key->empty()); 1706 *found = false; 1707 1708 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1709 const std::string leveldb_key = 1710 IndexDataKey::Encode(database_id, object_store_id, index_id, key); 1711 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 1712 it->Seek(leveldb_key); 1713 1714 for (;;) { 1715 if (!it->IsValid()) 1716 return true; 1717 if (CompareIndexKeys(it->Key(), leveldb_key) > 0) 1718 return true; 1719 1720 StringPiece slice(it->Value()); 1721 1722 int64 version; 1723 if (!DecodeVarInt(&slice, &version)) { 1724 INTERNAL_READ_ERROR(FIND_KEY_IN_INDEX); 1725 return false; 1726 } 1727 *found_encoded_primary_key = slice.as_string(); 1728 1729 bool exists = false; 1730 bool ok = VersionExists(leveldb_transaction, 1731 database_id, 1732 object_store_id, 1733 version, 1734 *found_encoded_primary_key, 1735 &exists); 1736 if (!ok) 1737 return false; 1738 if (!exists) { 1739 // Delete stale index data entry and continue. 1740 leveldb_transaction->Remove(it->Key()); 1741 it->Next(); 1742 continue; 1743 } 1744 *found = true; 1745 return true; 1746 } 1747 } 1748 1749 bool IndexedDBBackingStore::GetPrimaryKeyViaIndex( 1750 IndexedDBBackingStore::Transaction* transaction, 1751 int64 database_id, 1752 int64 object_store_id, 1753 int64 index_id, 1754 const IndexedDBKey& key, 1755 scoped_ptr<IndexedDBKey>* primary_key) { 1756 IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex"); 1757 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1758 return false; 1759 1760 bool found = false; 1761 std::string found_encoded_primary_key; 1762 bool ok = FindKeyInIndex(transaction, 1763 database_id, 1764 object_store_id, 1765 index_id, 1766 key, 1767 &found_encoded_primary_key, 1768 &found); 1769 if (!ok) { 1770 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX); 1771 return false; 1772 } 1773 if (!found) 1774 return true; 1775 if (!found_encoded_primary_key.size()) { 1776 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX); 1777 return false; 1778 } 1779 1780 StringPiece slice(found_encoded_primary_key); 1781 return DecodeIDBKey(&slice, primary_key) && slice.empty(); 1782 } 1783 1784 bool IndexedDBBackingStore::KeyExistsInIndex( 1785 IndexedDBBackingStore::Transaction* transaction, 1786 int64 database_id, 1787 int64 object_store_id, 1788 int64 index_id, 1789 const IndexedDBKey& index_key, 1790 scoped_ptr<IndexedDBKey>* found_primary_key, 1791 bool* exists) { 1792 IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex"); 1793 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1794 return false; 1795 1796 *exists = false; 1797 std::string found_encoded_primary_key; 1798 bool ok = FindKeyInIndex(transaction, 1799 database_id, 1800 object_store_id, 1801 index_id, 1802 index_key, 1803 &found_encoded_primary_key, 1804 exists); 1805 if (!ok) { 1806 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); 1807 return false; 1808 } 1809 if (!*exists) 1810 return true; 1811 if (found_encoded_primary_key.empty()) { 1812 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); 1813 return false; 1814 } 1815 1816 StringPiece slice(found_encoded_primary_key); 1817 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); 1818 } 1819 1820 IndexedDBBackingStore::Cursor::Cursor( 1821 const IndexedDBBackingStore::Cursor* other) 1822 : transaction_(other->transaction_), 1823 cursor_options_(other->cursor_options_), 1824 current_key_(new IndexedDBKey(*other->current_key_)) { 1825 if (other->iterator_) { 1826 iterator_ = transaction_->CreateIterator(); 1827 1828 if (other->iterator_->IsValid()) { 1829 iterator_->Seek(other->iterator_->Key()); 1830 DCHECK(iterator_->IsValid()); 1831 } 1832 } 1833 } 1834 1835 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, 1836 const CursorOptions& cursor_options) 1837 : transaction_(transaction), cursor_options_(cursor_options) {} 1838 IndexedDBBackingStore::Cursor::~Cursor() {} 1839 1840 bool IndexedDBBackingStore::Cursor::FirstSeek() { 1841 iterator_ = transaction_->CreateIterator(); 1842 if (cursor_options_.forward) 1843 iterator_->Seek(cursor_options_.low_key); 1844 else 1845 iterator_->Seek(cursor_options_.high_key); 1846 1847 return Continue(0, READY); 1848 } 1849 1850 bool IndexedDBBackingStore::Cursor::Advance(uint32 count) { 1851 while (count--) { 1852 if (!Continue()) 1853 return false; 1854 } 1855 return true; 1856 } 1857 1858 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key, 1859 const IndexedDBKey* primary_key, 1860 IteratorState next_state) { 1861 DCHECK(!key || key->IsValid()); 1862 DCHECK(!primary_key || primary_key->IsValid()); 1863 1864 // TODO(alecflett): avoid a copy here? 1865 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); 1866 1867 bool first_iteration = true; 1868 1869 // When iterating with PrevNoDuplicate, spec requires that the 1870 // value we yield for each key is the first duplicate in forwards 1871 // order. 1872 IndexedDBKey last_duplicate_key; 1873 1874 bool forward = cursor_options_.forward; 1875 1876 for (;;) { 1877 if (next_state == SEEK) { 1878 // TODO(jsbell): Optimize seeking for reverse cursors as well. 1879 if (first_iteration && key && forward) { 1880 std::string leveldb_key; 1881 if (primary_key) { 1882 leveldb_key = EncodeKey(*key, *primary_key); 1883 } else { 1884 leveldb_key = EncodeKey(*key); 1885 } 1886 iterator_->Seek(leveldb_key); 1887 first_iteration = false; 1888 } else if (forward) { 1889 iterator_->Next(); 1890 } else { 1891 iterator_->Prev(); 1892 } 1893 } else { 1894 next_state = SEEK; // for subsequent iterations 1895 } 1896 1897 if (!iterator_->IsValid()) { 1898 if (!forward && last_duplicate_key.IsValid()) { 1899 // We need to walk forward because we hit the end of 1900 // the data. 1901 forward = true; 1902 continue; 1903 } 1904 1905 return false; 1906 } 1907 1908 if (IsPastBounds()) { 1909 if (!forward && last_duplicate_key.IsValid()) { 1910 // We need to walk forward because now we're beyond the 1911 // bounds defined by the cursor. 1912 forward = true; 1913 continue; 1914 } 1915 1916 return false; 1917 } 1918 1919 if (!HaveEnteredRange()) 1920 continue; 1921 1922 // The row may not load because there's a stale entry in the 1923 // index. This is not fatal. 1924 if (!LoadCurrentRow()) 1925 continue; 1926 1927 if (key) { 1928 if (forward) { 1929 if (primary_key && current_key_->IsEqual(*key) && 1930 this->primary_key().IsLessThan(*primary_key)) 1931 continue; 1932 if (current_key_->IsLessThan(*key)) 1933 continue; 1934 } else { 1935 if (primary_key && key->IsEqual(*current_key_) && 1936 primary_key->IsLessThan(this->primary_key())) 1937 continue; 1938 if (key->IsLessThan(*current_key_)) 1939 continue; 1940 } 1941 } 1942 1943 if (cursor_options_.unique) { 1944 if (previous_key.IsValid() && current_key_->IsEqual(previous_key)) { 1945 // We should never be able to walk forward all the way 1946 // to the previous key. 1947 DCHECK(!last_duplicate_key.IsValid()); 1948 continue; 1949 } 1950 1951 if (!forward) { 1952 if (!last_duplicate_key.IsValid()) { 1953 last_duplicate_key = *current_key_; 1954 continue; 1955 } 1956 1957 // We need to walk forward because we hit the boundary 1958 // between key ranges. 1959 if (!last_duplicate_key.IsEqual(*current_key_)) { 1960 forward = true; 1961 continue; 1962 } 1963 1964 continue; 1965 } 1966 } 1967 break; 1968 } 1969 1970 DCHECK(!last_duplicate_key.IsValid() || 1971 (forward && last_duplicate_key.IsEqual(*current_key_))); 1972 return true; 1973 } 1974 1975 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { 1976 if (cursor_options_.forward) { 1977 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 1978 if (cursor_options_.low_open) { 1979 return compare > 0; 1980 } 1981 return compare >= 0; 1982 } 1983 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 1984 if (cursor_options_.high_open) { 1985 return compare < 0; 1986 } 1987 return compare <= 0; 1988 } 1989 1990 bool IndexedDBBackingStore::Cursor::IsPastBounds() const { 1991 if (cursor_options_.forward) { 1992 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 1993 if (cursor_options_.high_open) { 1994 return compare >= 0; 1995 } 1996 return compare > 0; 1997 } 1998 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 1999 if (cursor_options_.low_open) { 2000 return compare <= 0; 2001 } 2002 return compare < 0; 2003 } 2004 2005 const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const { 2006 return *current_key_; 2007 } 2008 2009 const IndexedDBBackingStore::RecordIdentifier& 2010 IndexedDBBackingStore::Cursor::record_identifier() const { 2011 return record_identifier_; 2012 } 2013 2014 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { 2015 public: 2016 ObjectStoreKeyCursorImpl( 2017 LevelDBTransaction* transaction, 2018 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2019 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2020 2021 virtual Cursor* Clone() OVERRIDE { 2022 return new ObjectStoreKeyCursorImpl(this); 2023 } 2024 2025 // IndexedDBBackingStore::Cursor 2026 virtual std::string* value() OVERRIDE { 2027 NOTREACHED(); 2028 return NULL; 2029 } 2030 virtual bool LoadCurrentRow() OVERRIDE; 2031 2032 protected: 2033 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2034 return ObjectStoreDataKey::Encode( 2035 cursor_options_.database_id, cursor_options_.object_store_id, key); 2036 } 2037 virtual std::string EncodeKey(const IndexedDBKey& key, 2038 const IndexedDBKey& primary_key) OVERRIDE { 2039 NOTREACHED(); 2040 return std::string(); 2041 } 2042 2043 private: 2044 explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other) 2045 : IndexedDBBackingStore::Cursor(other) {} 2046 }; 2047 2048 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() { 2049 StringPiece slice(iterator_->Key()); 2050 ObjectStoreDataKey object_store_data_key; 2051 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { 2052 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2053 return false; 2054 } 2055 2056 current_key_ = object_store_data_key.user_key(); 2057 2058 int64 version; 2059 slice = StringPiece(iterator_->Value()); 2060 if (!DecodeVarInt(&slice, &version)) { 2061 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2062 return false; 2063 } 2064 2065 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 2066 std::string encoded_key; 2067 EncodeIDBKey(*current_key_, &encoded_key); 2068 record_identifier_.Reset(encoded_key, version); 2069 2070 return true; 2071 } 2072 2073 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { 2074 public: 2075 ObjectStoreCursorImpl( 2076 LevelDBTransaction* transaction, 2077 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2078 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2079 2080 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } 2081 2082 // IndexedDBBackingStore::Cursor 2083 virtual std::string* value() OVERRIDE { return ¤t_value_; } 2084 virtual bool LoadCurrentRow() OVERRIDE; 2085 2086 protected: 2087 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2088 return ObjectStoreDataKey::Encode( 2089 cursor_options_.database_id, cursor_options_.object_store_id, key); 2090 } 2091 virtual std::string EncodeKey(const IndexedDBKey& key, 2092 const IndexedDBKey& primary_key) OVERRIDE { 2093 NOTREACHED(); 2094 return std::string(); 2095 } 2096 2097 private: 2098 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) 2099 : IndexedDBBackingStore::Cursor(other), 2100 current_value_(other->current_value_) {} 2101 2102 std::string current_value_; 2103 }; 2104 2105 bool ObjectStoreCursorImpl::LoadCurrentRow() { 2106 StringPiece slice(iterator_->Key()); 2107 ObjectStoreDataKey object_store_data_key; 2108 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { 2109 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2110 return false; 2111 } 2112 2113 current_key_ = object_store_data_key.user_key(); 2114 2115 int64 version; 2116 slice = StringPiece(iterator_->Value()); 2117 if (!DecodeVarInt(&slice, &version)) { 2118 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2119 return false; 2120 } 2121 2122 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 2123 std::string encoded_key; 2124 EncodeIDBKey(*current_key_, &encoded_key); 2125 record_identifier_.Reset(encoded_key, version); 2126 2127 current_value_ = slice.as_string(); 2128 return true; 2129 } 2130 2131 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { 2132 public: 2133 IndexKeyCursorImpl( 2134 LevelDBTransaction* transaction, 2135 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2136 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2137 2138 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } 2139 2140 // IndexedDBBackingStore::Cursor 2141 virtual std::string* value() OVERRIDE { 2142 NOTREACHED(); 2143 return NULL; 2144 } 2145 virtual const IndexedDBKey& primary_key() const OVERRIDE { 2146 return *primary_key_; 2147 } 2148 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 2149 const OVERRIDE { 2150 NOTREACHED(); 2151 return record_identifier_; 2152 } 2153 virtual bool LoadCurrentRow() OVERRIDE; 2154 2155 protected: 2156 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2157 return IndexDataKey::Encode(cursor_options_.database_id, 2158 cursor_options_.object_store_id, 2159 cursor_options_.index_id, 2160 key); 2161 } 2162 virtual std::string EncodeKey(const IndexedDBKey& key, 2163 const IndexedDBKey& primary_key) OVERRIDE { 2164 return IndexDataKey::Encode(cursor_options_.database_id, 2165 cursor_options_.object_store_id, 2166 cursor_options_.index_id, 2167 key, 2168 primary_key); 2169 } 2170 2171 private: 2172 explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other) 2173 : IndexedDBBackingStore::Cursor(other), 2174 primary_key_(new IndexedDBKey(*other->primary_key_)) {} 2175 2176 scoped_ptr<IndexedDBKey> primary_key_; 2177 }; 2178 2179 bool IndexKeyCursorImpl::LoadCurrentRow() { 2180 StringPiece slice(iterator_->Key()); 2181 IndexDataKey index_data_key; 2182 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 2183 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2184 return false; 2185 } 2186 2187 current_key_ = index_data_key.user_key(); 2188 DCHECK(current_key_); 2189 2190 slice = StringPiece(iterator_->Value()); 2191 int64 index_data_version; 2192 if (!DecodeVarInt(&slice, &index_data_version)) { 2193 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2194 return false; 2195 } 2196 2197 if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) { 2198 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2199 return false; 2200 } 2201 2202 std::string primary_leveldb_key = 2203 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 2204 index_data_key.ObjectStoreId(), 2205 *primary_key_); 2206 2207 std::string result; 2208 bool found = false; 2209 bool ok = transaction_->Get(primary_leveldb_key, &result, &found); 2210 if (!ok) { 2211 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2212 return false; 2213 } 2214 if (!found) { 2215 transaction_->Remove(iterator_->Key()); 2216 return false; 2217 } 2218 if (!result.size()) { 2219 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2220 return false; 2221 } 2222 2223 int64 object_store_data_version; 2224 slice = StringPiece(result); 2225 if (!DecodeVarInt(&slice, &object_store_data_version)) { 2226 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2227 return false; 2228 } 2229 2230 if (object_store_data_version != index_data_version) { 2231 transaction_->Remove(iterator_->Key()); 2232 return false; 2233 } 2234 2235 return true; 2236 } 2237 2238 class IndexCursorImpl : public IndexedDBBackingStore::Cursor { 2239 public: 2240 IndexCursorImpl( 2241 LevelDBTransaction* transaction, 2242 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2243 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2244 2245 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } 2246 2247 // IndexedDBBackingStore::Cursor 2248 virtual std::string* value() OVERRIDE { return ¤t_value_; } 2249 virtual const IndexedDBKey& primary_key() const OVERRIDE { 2250 return *primary_key_; 2251 } 2252 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 2253 const OVERRIDE { 2254 NOTREACHED(); 2255 return record_identifier_; 2256 } 2257 virtual bool LoadCurrentRow() OVERRIDE; 2258 2259 protected: 2260 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2261 return IndexDataKey::Encode(cursor_options_.database_id, 2262 cursor_options_.object_store_id, 2263 cursor_options_.index_id, 2264 key); 2265 } 2266 virtual std::string EncodeKey(const IndexedDBKey& key, 2267 const IndexedDBKey& primary_key) OVERRIDE { 2268 return IndexDataKey::Encode(cursor_options_.database_id, 2269 cursor_options_.object_store_id, 2270 cursor_options_.index_id, 2271 key, 2272 primary_key); 2273 } 2274 2275 private: 2276 explicit IndexCursorImpl(const IndexCursorImpl* other) 2277 : IndexedDBBackingStore::Cursor(other), 2278 primary_key_(new IndexedDBKey(*other->primary_key_)), 2279 current_value_(other->current_value_), 2280 primary_leveldb_key_(other->primary_leveldb_key_) {} 2281 2282 scoped_ptr<IndexedDBKey> primary_key_; 2283 std::string current_value_; 2284 std::string primary_leveldb_key_; 2285 }; 2286 2287 bool IndexCursorImpl::LoadCurrentRow() { 2288 StringPiece slice(iterator_->Key()); 2289 IndexDataKey index_data_key; 2290 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 2291 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2292 return false; 2293 } 2294 2295 current_key_ = index_data_key.user_key(); 2296 DCHECK(current_key_); 2297 2298 slice = StringPiece(iterator_->Value()); 2299 int64 index_data_version; 2300 if (!DecodeVarInt(&slice, &index_data_version)) { 2301 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2302 return false; 2303 } 2304 if (!DecodeIDBKey(&slice, &primary_key_)) { 2305 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2306 return false; 2307 } 2308 2309 primary_leveldb_key_ = 2310 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 2311 index_data_key.ObjectStoreId(), 2312 *primary_key_); 2313 2314 std::string result; 2315 bool found = false; 2316 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); 2317 if (!ok) { 2318 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2319 return false; 2320 } 2321 if (!found) { 2322 transaction_->Remove(iterator_->Key()); 2323 return false; 2324 } 2325 if (!result.size()) { 2326 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2327 return false; 2328 } 2329 2330 int64 object_store_data_version; 2331 slice = StringPiece(result); 2332 if (!DecodeVarInt(&slice, &object_store_data_version)) { 2333 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2334 return false; 2335 } 2336 2337 if (object_store_data_version != index_data_version) { 2338 transaction_->Remove(iterator_->Key()); 2339 return false; 2340 } 2341 2342 current_value_ = slice.as_string(); 2343 return true; 2344 } 2345 2346 bool ObjectStoreCursorOptions( 2347 LevelDBTransaction* transaction, 2348 int64 database_id, 2349 int64 object_store_id, 2350 const IndexedDBKeyRange& range, 2351 indexed_db::CursorDirection direction, 2352 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 2353 cursor_options->database_id = database_id; 2354 cursor_options->object_store_id = object_store_id; 2355 2356 bool lower_bound = range.lower().IsValid(); 2357 bool upper_bound = range.upper().IsValid(); 2358 cursor_options->forward = 2359 (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2360 direction == indexed_db::CURSOR_NEXT); 2361 cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2362 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); 2363 2364 if (!lower_bound) { 2365 cursor_options->low_key = 2366 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 2367 cursor_options->low_open = true; // Not included. 2368 } else { 2369 cursor_options->low_key = 2370 ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower()); 2371 cursor_options->low_open = range.lowerOpen(); 2372 } 2373 2374 if (!upper_bound) { 2375 cursor_options->high_key = 2376 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 2377 2378 if (cursor_options->forward) { 2379 cursor_options->high_open = true; // Not included. 2380 } else { 2381 // We need a key that exists. 2382 if (!FindGreatestKeyLessThanOrEqual(transaction, 2383 cursor_options->high_key, 2384 &cursor_options->high_key)) 2385 return false; 2386 cursor_options->high_open = false; 2387 } 2388 } else { 2389 cursor_options->high_key = 2390 ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper()); 2391 cursor_options->high_open = range.upperOpen(); 2392 2393 if (!cursor_options->forward) { 2394 // For reverse cursors, we need a key that exists. 2395 std::string found_high_key; 2396 if (!FindGreatestKeyLessThanOrEqual( 2397 transaction, cursor_options->high_key, &found_high_key)) 2398 return false; 2399 2400 // If the target key should not be included, but we end up with a smaller 2401 // key, we should include that. 2402 if (cursor_options->high_open && 2403 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 2404 cursor_options->high_open = false; 2405 2406 cursor_options->high_key = found_high_key; 2407 } 2408 } 2409 2410 return true; 2411 } 2412 2413 bool IndexCursorOptions( 2414 LevelDBTransaction* transaction, 2415 int64 database_id, 2416 int64 object_store_id, 2417 int64 index_id, 2418 const IndexedDBKeyRange& range, 2419 indexed_db::CursorDirection direction, 2420 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 2421 DCHECK(transaction); 2422 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2423 return false; 2424 2425 cursor_options->database_id = database_id; 2426 cursor_options->object_store_id = object_store_id; 2427 cursor_options->index_id = index_id; 2428 2429 bool lower_bound = range.lower().IsValid(); 2430 bool upper_bound = range.upper().IsValid(); 2431 cursor_options->forward = 2432 (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2433 direction == indexed_db::CURSOR_NEXT); 2434 cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2435 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); 2436 2437 if (!lower_bound) { 2438 cursor_options->low_key = 2439 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 2440 cursor_options->low_open = false; // Included. 2441 } else { 2442 cursor_options->low_key = IndexDataKey::Encode( 2443 database_id, object_store_id, index_id, range.lower()); 2444 cursor_options->low_open = range.lowerOpen(); 2445 } 2446 2447 if (!upper_bound) { 2448 cursor_options->high_key = 2449 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 2450 cursor_options->high_open = false; // Included. 2451 2452 if (!cursor_options->forward) { // We need a key that exists. 2453 if (!FindGreatestKeyLessThanOrEqual(transaction, 2454 cursor_options->high_key, 2455 &cursor_options->high_key)) 2456 return false; 2457 cursor_options->high_open = false; 2458 } 2459 } else { 2460 cursor_options->high_key = IndexDataKey::Encode( 2461 database_id, object_store_id, index_id, range.upper()); 2462 cursor_options->high_open = range.upperOpen(); 2463 2464 std::string found_high_key; 2465 // Seek to the *last* key in the set of non-unique keys 2466 if (!FindGreatestKeyLessThanOrEqual( 2467 transaction, cursor_options->high_key, &found_high_key)) 2468 return false; 2469 2470 // If the target key should not be included, but we end up with a smaller 2471 // key, we should include that. 2472 if (cursor_options->high_open && 2473 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 2474 cursor_options->high_open = false; 2475 2476 cursor_options->high_key = found_high_key; 2477 } 2478 2479 return true; 2480 } 2481 2482 scoped_ptr<IndexedDBBackingStore::Cursor> 2483 IndexedDBBackingStore::OpenObjectStoreCursor( 2484 IndexedDBBackingStore::Transaction* transaction, 2485 int64 database_id, 2486 int64 object_store_id, 2487 const IndexedDBKeyRange& range, 2488 indexed_db::CursorDirection direction) { 2489 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor"); 2490 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2491 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2492 if (!ObjectStoreCursorOptions(leveldb_transaction, 2493 database_id, 2494 object_store_id, 2495 range, 2496 direction, 2497 &cursor_options)) 2498 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2499 scoped_ptr<ObjectStoreCursorImpl> cursor( 2500 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); 2501 if (!cursor->FirstSeek()) 2502 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2503 2504 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2505 } 2506 2507 scoped_ptr<IndexedDBBackingStore::Cursor> 2508 IndexedDBBackingStore::OpenObjectStoreKeyCursor( 2509 IndexedDBBackingStore::Transaction* transaction, 2510 int64 database_id, 2511 int64 object_store_id, 2512 const IndexedDBKeyRange& range, 2513 indexed_db::CursorDirection direction) { 2514 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); 2515 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2516 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2517 if (!ObjectStoreCursorOptions(leveldb_transaction, 2518 database_id, 2519 object_store_id, 2520 range, 2521 direction, 2522 &cursor_options)) 2523 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2524 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( 2525 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); 2526 if (!cursor->FirstSeek()) 2527 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2528 2529 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2530 } 2531 2532 scoped_ptr<IndexedDBBackingStore::Cursor> 2533 IndexedDBBackingStore::OpenIndexKeyCursor( 2534 IndexedDBBackingStore::Transaction* transaction, 2535 int64 database_id, 2536 int64 object_store_id, 2537 int64 index_id, 2538 const IndexedDBKeyRange& range, 2539 indexed_db::CursorDirection direction) { 2540 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); 2541 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2542 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2543 if (!IndexCursorOptions(leveldb_transaction, 2544 database_id, 2545 object_store_id, 2546 index_id, 2547 range, 2548 direction, 2549 &cursor_options)) 2550 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2551 scoped_ptr<IndexKeyCursorImpl> cursor( 2552 new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); 2553 if (!cursor->FirstSeek()) 2554 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2555 2556 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2557 } 2558 2559 scoped_ptr<IndexedDBBackingStore::Cursor> 2560 IndexedDBBackingStore::OpenIndexCursor( 2561 IndexedDBBackingStore::Transaction* transaction, 2562 int64 database_id, 2563 int64 object_store_id, 2564 int64 index_id, 2565 const IndexedDBKeyRange& range, 2566 indexed_db::CursorDirection direction) { 2567 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); 2568 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2569 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2570 if (!IndexCursorOptions(leveldb_transaction, 2571 database_id, 2572 object_store_id, 2573 index_id, 2574 range, 2575 direction, 2576 &cursor_options)) 2577 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2578 scoped_ptr<IndexCursorImpl> cursor( 2579 new IndexCursorImpl(leveldb_transaction, cursor_options)); 2580 if (!cursor->FirstSeek()) 2581 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2582 2583 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2584 } 2585 2586 IndexedDBBackingStore::Transaction::Transaction( 2587 IndexedDBBackingStore* backing_store) 2588 : backing_store_(backing_store) {} 2589 2590 IndexedDBBackingStore::Transaction::~Transaction() {} 2591 2592 void IndexedDBBackingStore::Transaction::Begin() { 2593 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); 2594 DCHECK(!transaction_.get()); 2595 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); 2596 } 2597 2598 bool IndexedDBBackingStore::Transaction::Commit() { 2599 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); 2600 DCHECK(transaction_.get()); 2601 bool result = transaction_->Commit(); 2602 transaction_ = NULL; 2603 if (!result) 2604 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); 2605 return result; 2606 } 2607 2608 void IndexedDBBackingStore::Transaction::Rollback() { 2609 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); 2610 DCHECK(transaction_.get()); 2611 transaction_->Rollback(); 2612 transaction_ = NULL; 2613 } 2614 2615 } // namespace content 2616