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