indexed_db_backing_store.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 28using base::StringPiece; 29 30namespace content { 31 32namespace { 33 34static std::string ComputeOriginIdentifier(const GURL& origin_url) { 35 return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; 36} 37 38static 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 46static const int64 kKeyGeneratorInitialNumber = 47 1; // From the IndexedDB specification. 48 49enum 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 75static 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 102static 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 110template <typename DBOrTransaction> 111static 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 125static 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 134template <typename DBOrTransaction> 135WARN_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 149static 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 157template <typename DBOrTransaction> 158WARN_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 173static 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 181static 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 189static int CompareKeys(const StringPiece& a, const StringPiece& b) { 190 return Compare(a, b, false /*index_keys*/); 191} 192 193static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) { 194 return Compare(a, b, true /*index_keys*/); 195} 196 197class 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. 209static const int64 kLatestKnownSchemaVersion = 2; 210WARN_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 245WARN_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 336template <typename DBOrTransaction> 337WARN_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 347template <typename DBOrTransaction> 348WARN_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 364class 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 377IndexedDBBackingStore::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 386IndexedDBBackingStore::~IndexedDBBackingStore() { 387 // db_'s destructor uses comparator_. The order of destruction is important. 388 db_.reset(); 389 comparator_.reset(); 390} 391 392IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( 393 const std::string& primary_key, 394 int64 version) 395 : primary_key_(primary_key), version_(version) { 396 DCHECK(!primary_key.empty()); 397} 398IndexedDBBackingStore::RecordIdentifier::RecordIdentifier() 399 : primary_key_(), version_(-1) {} 400IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {} 401 402IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {} 403IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {} 404 405enum 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 424scoped_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 440static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) { 441 if (origin_url.host() == "docs.google.com") 442 return ".Docs"; 443 return std::string(); 444} 445 446static 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 466static 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 497scoped_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 614scoped_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 621scoped_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 641scoped_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 656std::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 680bool 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 736WARN_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 758bool 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 792bool 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 806static 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 815bool 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 db_->Compact(start_key, stop_key); 846 return true; 847} 848 849static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, 850 const std::string& stop_key, 851 int64 object_store_id, 852 int64 meta_data_type) { 853 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 854 return false; 855 856 StringPiece slice(it->Key()); 857 ObjectStoreMetaDataKey meta_data_key; 858 bool ok = ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key); 859 DCHECK(ok); 860 if (meta_data_key.ObjectStoreId() != object_store_id) 861 return false; 862 if (meta_data_key.MetaDataType() != meta_data_type) 863 return false; 864 return true; 865} 866 867// TODO(jsbell): This should do some error handling rather than 868// plowing ahead when bad data is encountered. 869bool IndexedDBBackingStore::GetObjectStores( 870 int64 database_id, 871 IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) { 872 IDB_TRACE("IndexedDBBackingStore::GetObjectStores"); 873 if (!KeyPrefix::IsValidDatabaseId(database_id)) 874 return false; 875 const std::string start_key = 876 ObjectStoreMetaDataKey::Encode(database_id, 1, 0); 877 const std::string stop_key = 878 ObjectStoreMetaDataKey::EncodeMaxKey(database_id); 879 880 DCHECK(object_stores->empty()); 881 882 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 883 it->Seek(start_key); 884 while (it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 885 StringPiece slice(it->Key()); 886 ObjectStoreMetaDataKey meta_data_key; 887 bool ok = ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key); 888 DCHECK(ok); 889 if (meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) { 890 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 891 // Possible stale metadata, but don't fail the load. 892 it->Next(); 893 continue; 894 } 895 896 int64 object_store_id = meta_data_key.ObjectStoreId(); 897 898 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 899 // simplify. 900 base::string16 object_store_name; 901 { 902 StringPiece slice(it->Value()); 903 if (!DecodeString(&slice, &object_store_name) || !slice.empty()) 904 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 905 } 906 907 it->Next(); 908 if (!CheckObjectStoreAndMetaDataType(it.get(), 909 stop_key, 910 object_store_id, 911 ObjectStoreMetaDataKey::KEY_PATH)) { 912 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 913 break; 914 } 915 IndexedDBKeyPath key_path; 916 { 917 StringPiece slice(it->Value()); 918 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 919 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 920 } 921 922 it->Next(); 923 if (!CheckObjectStoreAndMetaDataType( 924 it.get(), 925 stop_key, 926 object_store_id, 927 ObjectStoreMetaDataKey::AUTO_INCREMENT)) { 928 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 929 break; 930 } 931 bool auto_increment; 932 { 933 StringPiece slice(it->Value()); 934 if (!DecodeBool(&slice, &auto_increment) || !slice.empty()) 935 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 936 } 937 938 it->Next(); // Is evicatble. 939 if (!CheckObjectStoreAndMetaDataType(it.get(), 940 stop_key, 941 object_store_id, 942 ObjectStoreMetaDataKey::EVICTABLE)) { 943 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 944 break; 945 } 946 947 it->Next(); // Last version. 948 if (!CheckObjectStoreAndMetaDataType( 949 it.get(), 950 stop_key, 951 object_store_id, 952 ObjectStoreMetaDataKey::LAST_VERSION)) { 953 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 954 break; 955 } 956 957 it->Next(); // Maximum index id allocated. 958 if (!CheckObjectStoreAndMetaDataType( 959 it.get(), 960 stop_key, 961 object_store_id, 962 ObjectStoreMetaDataKey::MAX_INDEX_ID)) { 963 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 964 break; 965 } 966 int64 max_index_id; 967 { 968 StringPiece slice(it->Value()); 969 if (!DecodeInt(&slice, &max_index_id) || !slice.empty()) 970 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 971 } 972 973 it->Next(); // [optional] has key path (is not null) 974 if (CheckObjectStoreAndMetaDataType(it.get(), 975 stop_key, 976 object_store_id, 977 ObjectStoreMetaDataKey::HAS_KEY_PATH)) { 978 bool has_key_path; 979 { 980 StringPiece slice(it->Value()); 981 if (!DecodeBool(&slice, &has_key_path)) 982 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 983 } 984 // This check accounts for two layers of legacy coding: 985 // (1) Initially, has_key_path was added to distinguish null vs. string. 986 // (2) Later, null vs. string vs. array was stored in the key_path itself. 987 // So this check is only relevant for string-type key_paths. 988 if (!has_key_path && 989 (key_path.type() == blink::WebIDBKeyPathTypeString && 990 !key_path.string().empty())) { 991 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 992 break; 993 } 994 if (!has_key_path) 995 key_path = IndexedDBKeyPath(); 996 it->Next(); 997 } 998 999 int64 key_generator_current_number = -1; 1000 if (CheckObjectStoreAndMetaDataType( 1001 it.get(), 1002 stop_key, 1003 object_store_id, 1004 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) { 1005 StringPiece slice(it->Value()); 1006 if (!DecodeInt(&slice, &key_generator_current_number) || !slice.empty()) 1007 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); 1008 1009 // TODO(jsbell): Return key_generator_current_number, cache in 1010 // object store, and write lazily to backing store. For now, 1011 // just assert that if it was written it was valid. 1012 DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber); 1013 it->Next(); 1014 } 1015 1016 IndexedDBObjectStoreMetadata metadata(object_store_name, 1017 object_store_id, 1018 key_path, 1019 auto_increment, 1020 max_index_id); 1021 if (!GetIndexes(database_id, object_store_id, &metadata.indexes)) 1022 return false; 1023 (*object_stores)[object_store_id] = metadata; 1024 } 1025 return true; 1026} 1027 1028WARN_UNUSED_RESULT static bool SetMaxObjectStoreId( 1029 LevelDBTransaction* transaction, 1030 int64 database_id, 1031 int64 object_store_id) { 1032 const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode( 1033 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); 1034 int64 max_object_store_id = -1; 1035 bool ok = GetMaxObjectStoreId( 1036 transaction, max_object_store_id_key, &max_object_store_id); 1037 if (!ok) { 1038 INTERNAL_READ_ERROR(SET_MAX_OBJECT_STORE_ID); 1039 return false; 1040 } 1041 1042 if (object_store_id <= max_object_store_id) { 1043 INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID); 1044 return false; 1045 } 1046 PutInt(transaction, max_object_store_id_key, object_store_id); 1047 return true; 1048} 1049 1050bool IndexedDBBackingStore::CreateObjectStore( 1051 IndexedDBBackingStore::Transaction* transaction, 1052 int64 database_id, 1053 int64 object_store_id, 1054 const base::string16& name, 1055 const IndexedDBKeyPath& key_path, 1056 bool auto_increment) { 1057 IDB_TRACE("IndexedDBBackingStore::CreateObjectStore"); 1058 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1059 return false; 1060 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1061 if (!SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id)) 1062 return false; 1063 1064 const std::string name_key = ObjectStoreMetaDataKey::Encode( 1065 database_id, object_store_id, ObjectStoreMetaDataKey::NAME); 1066 const std::string key_path_key = ObjectStoreMetaDataKey::Encode( 1067 database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH); 1068 const std::string auto_increment_key = ObjectStoreMetaDataKey::Encode( 1069 database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT); 1070 const std::string evictable_key = ObjectStoreMetaDataKey::Encode( 1071 database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE); 1072 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1073 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1074 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 1075 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 1076 const std::string has_key_path_key = ObjectStoreMetaDataKey::Encode( 1077 database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH); 1078 const std::string key_generator_current_number_key = 1079 ObjectStoreMetaDataKey::Encode( 1080 database_id, 1081 object_store_id, 1082 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1083 const std::string names_key = ObjectStoreNamesKey::Encode(database_id, name); 1084 1085 PutString(leveldb_transaction, name_key, name); 1086 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 1087 PutInt(leveldb_transaction, auto_increment_key, auto_increment); 1088 PutInt(leveldb_transaction, evictable_key, false); 1089 PutInt(leveldb_transaction, last_version_key, 1); 1090 PutInt(leveldb_transaction, max_index_id_key, kMinimumIndexId); 1091 PutBool(leveldb_transaction, has_key_path_key, !key_path.IsNull()); 1092 PutInt(leveldb_transaction, 1093 key_generator_current_number_key, 1094 kKeyGeneratorInitialNumber); 1095 PutInt(leveldb_transaction, names_key, object_store_id); 1096 return true; 1097} 1098 1099bool IndexedDBBackingStore::DeleteObjectStore( 1100 IndexedDBBackingStore::Transaction* transaction, 1101 int64 database_id, 1102 int64 object_store_id) { 1103 IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore"); 1104 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1105 return false; 1106 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1107 1108 base::string16 object_store_name; 1109 bool found = false; 1110 bool ok = GetString( 1111 leveldb_transaction, 1112 ObjectStoreMetaDataKey::Encode( 1113 database_id, object_store_id, ObjectStoreMetaDataKey::NAME), 1114 &object_store_name, 1115 &found); 1116 if (!ok) { 1117 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); 1118 return false; 1119 } 1120 if (!found) { 1121 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); 1122 return false; 1123 } 1124 1125 DeleteRange( 1126 leveldb_transaction, 1127 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), 1128 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); 1129 1130 leveldb_transaction->Remove( 1131 ObjectStoreNamesKey::Encode(database_id, object_store_name)); 1132 1133 DeleteRange(leveldb_transaction, 1134 IndexFreeListKey::Encode(database_id, object_store_id, 0), 1135 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); 1136 DeleteRange(leveldb_transaction, 1137 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), 1138 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); 1139 1140 return ClearObjectStore(transaction, database_id, object_store_id); 1141} 1142 1143bool IndexedDBBackingStore::GetRecord( 1144 IndexedDBBackingStore::Transaction* transaction, 1145 int64 database_id, 1146 int64 object_store_id, 1147 const IndexedDBKey& key, 1148 std::string* record) { 1149 IDB_TRACE("IndexedDBBackingStore::GetRecord"); 1150 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1151 return false; 1152 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1153 1154 const std::string leveldb_key = 1155 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1156 std::string data; 1157 1158 record->clear(); 1159 1160 bool found = false; 1161 bool ok = leveldb_transaction->Get(leveldb_key, &data, &found); 1162 if (!ok) { 1163 INTERNAL_READ_ERROR(GET_RECORD); 1164 return false; 1165 } 1166 if (!found) 1167 return true; 1168 if (data.empty()) { 1169 INTERNAL_READ_ERROR(GET_RECORD); 1170 return false; 1171 } 1172 1173 int64 version; 1174 StringPiece slice(data); 1175 if (!DecodeVarInt(&slice, &version)) { 1176 INTERNAL_READ_ERROR(GET_RECORD); 1177 return false; 1178 } 1179 1180 *record = slice.as_string(); 1181 return true; 1182} 1183 1184WARN_UNUSED_RESULT static bool GetNewVersionNumber( 1185 LevelDBTransaction* transaction, 1186 int64 database_id, 1187 int64 object_store_id, 1188 int64* new_version_number) { 1189 const std::string last_version_key = ObjectStoreMetaDataKey::Encode( 1190 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); 1191 1192 *new_version_number = -1; 1193 int64 last_version = -1; 1194 bool found = false; 1195 bool ok = GetInt(transaction, last_version_key, &last_version, &found); 1196 if (!ok) { 1197 INTERNAL_READ_ERROR(GET_NEW_VERSION_NUMBER); 1198 return false; 1199 } 1200 if (!found) 1201 last_version = 0; 1202 1203 DCHECK_GE(last_version, 0); 1204 1205 int64 version = last_version + 1; 1206 PutInt(transaction, last_version_key, version); 1207 1208 // TODO(jsbell): Think about how we want to handle the overflow scenario. 1209 DCHECK(version > last_version); 1210 1211 *new_version_number = version; 1212 return true; 1213} 1214 1215bool IndexedDBBackingStore::PutRecord( 1216 IndexedDBBackingStore::Transaction* transaction, 1217 int64 database_id, 1218 int64 object_store_id, 1219 const IndexedDBKey& key, 1220 const std::string& value, 1221 RecordIdentifier* record_identifier) { 1222 IDB_TRACE("IndexedDBBackingStore::PutRecord"); 1223 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1224 return false; 1225 DCHECK(key.IsValid()); 1226 1227 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1228 int64 version = -1; 1229 bool ok = GetNewVersionNumber( 1230 leveldb_transaction, database_id, object_store_id, &version); 1231 if (!ok) 1232 return false; 1233 DCHECK_GE(version, 0); 1234 const std::string object_storedata_key = 1235 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1236 1237 std::string v; 1238 EncodeVarInt(version, &v); 1239 v.append(value); 1240 1241 leveldb_transaction->Put(object_storedata_key, &v); 1242 1243 const std::string exists_entry_key = 1244 ExistsEntryKey::Encode(database_id, object_store_id, key); 1245 std::string version_encoded; 1246 EncodeInt(version, &version_encoded); 1247 leveldb_transaction->Put(exists_entry_key, &version_encoded); 1248 1249 std::string key_encoded; 1250 EncodeIDBKey(key, &key_encoded); 1251 record_identifier->Reset(key_encoded, version); 1252 return true; 1253} 1254 1255bool IndexedDBBackingStore::ClearObjectStore( 1256 IndexedDBBackingStore::Transaction* transaction, 1257 int64 database_id, 1258 int64 object_store_id) { 1259 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); 1260 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1261 return false; 1262 const std::string start_key = 1263 KeyPrefix(database_id, object_store_id).Encode(); 1264 const std::string stop_key = 1265 KeyPrefix(database_id, object_store_id + 1).Encode(); 1266 1267 DeleteRange(transaction->transaction(), start_key, stop_key); 1268 return true; 1269} 1270 1271bool IndexedDBBackingStore::DeleteRecord( 1272 IndexedDBBackingStore::Transaction* transaction, 1273 int64 database_id, 1274 int64 object_store_id, 1275 const RecordIdentifier& record_identifier) { 1276 IDB_TRACE("IndexedDBBackingStore::DeleteRecord"); 1277 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1278 return false; 1279 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1280 1281 const std::string object_store_data_key = ObjectStoreDataKey::Encode( 1282 database_id, object_store_id, record_identifier.primary_key()); 1283 leveldb_transaction->Remove(object_store_data_key); 1284 1285 const std::string exists_entry_key = ExistsEntryKey::Encode( 1286 database_id, object_store_id, record_identifier.primary_key()); 1287 leveldb_transaction->Remove(exists_entry_key); 1288 return true; 1289} 1290 1291bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( 1292 IndexedDBBackingStore::Transaction* transaction, 1293 int64 database_id, 1294 int64 object_store_id, 1295 int64* key_generator_current_number) { 1296 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1297 return false; 1298 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1299 1300 const std::string key_generator_current_number_key = 1301 ObjectStoreMetaDataKey::Encode( 1302 database_id, 1303 object_store_id, 1304 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1305 1306 *key_generator_current_number = -1; 1307 std::string data; 1308 1309 bool found = false; 1310 bool ok = 1311 leveldb_transaction->Get(key_generator_current_number_key, &data, &found); 1312 if (!ok) { 1313 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1314 return false; 1315 } 1316 if (found && !data.empty()) { 1317 StringPiece slice(data); 1318 if (!DecodeInt(&slice, key_generator_current_number) || !slice.empty()) { 1319 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1320 return false; 1321 } 1322 return true; 1323 } 1324 1325 // Previously, the key generator state was not stored explicitly 1326 // but derived from the maximum numeric key present in existing 1327 // data. This violates the spec as the data may be cleared but the 1328 // key generator state must be preserved. 1329 // TODO(jsbell): Fix this for all stores on database open? 1330 const std::string start_key = 1331 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 1332 const std::string stop_key = 1333 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 1334 1335 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 1336 int64 max_numeric_key = 0; 1337 1338 for (it->Seek(start_key); 1339 it->IsValid() && CompareKeys(it->Key(), stop_key) < 0; 1340 it->Next()) { 1341 StringPiece slice(it->Key()); 1342 ObjectStoreDataKey data_key; 1343 if (!ObjectStoreDataKey::Decode(&slice, &data_key)) { 1344 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); 1345 return false; 1346 } 1347 scoped_ptr<IndexedDBKey> user_key = data_key.user_key(); 1348 if (user_key->type() == blink::WebIDBKeyTypeNumber) { 1349 int64 n = static_cast<int64>(user_key->number()); 1350 if (n > max_numeric_key) 1351 max_numeric_key = n; 1352 } 1353 } 1354 1355 *key_generator_current_number = max_numeric_key + 1; 1356 return true; 1357} 1358 1359bool IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber( 1360 IndexedDBBackingStore::Transaction* transaction, 1361 int64 database_id, 1362 int64 object_store_id, 1363 int64 new_number, 1364 bool check_current) { 1365 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1366 return false; 1367 1368 if (check_current) { 1369 int64 current_number; 1370 bool ok = GetKeyGeneratorCurrentNumber( 1371 transaction, database_id, object_store_id, ¤t_number); 1372 if (!ok) 1373 return false; 1374 if (new_number <= current_number) 1375 return true; 1376 } 1377 1378 const std::string key_generator_current_number_key = 1379 ObjectStoreMetaDataKey::Encode( 1380 database_id, 1381 object_store_id, 1382 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); 1383 PutInt( 1384 transaction->transaction(), key_generator_current_number_key, new_number); 1385 return true; 1386} 1387 1388bool IndexedDBBackingStore::KeyExistsInObjectStore( 1389 IndexedDBBackingStore::Transaction* transaction, 1390 int64 database_id, 1391 int64 object_store_id, 1392 const IndexedDBKey& key, 1393 RecordIdentifier* found_record_identifier, 1394 bool* found) { 1395 IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore"); 1396 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1397 return false; 1398 *found = false; 1399 const std::string leveldb_key = 1400 ObjectStoreDataKey::Encode(database_id, object_store_id, key); 1401 std::string data; 1402 1403 bool ok = transaction->transaction()->Get(leveldb_key, &data, found); 1404 if (!ok) { 1405 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); 1406 return false; 1407 } 1408 if (!*found) 1409 return true; 1410 if (!data.size()) { 1411 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); 1412 return false; 1413 } 1414 1415 int64 version; 1416 StringPiece slice(data); 1417 if (!DecodeVarInt(&slice, &version)) 1418 return false; 1419 1420 std::string encoded_key; 1421 EncodeIDBKey(key, &encoded_key); 1422 found_record_identifier->Reset(encoded_key, version); 1423 return true; 1424} 1425 1426static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, 1427 const std::string& stop_key, 1428 int64 index_id, 1429 unsigned char meta_data_type) { 1430 if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0) 1431 return false; 1432 1433 StringPiece slice(it->Key()); 1434 IndexMetaDataKey meta_data_key; 1435 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 1436 DCHECK(ok); 1437 if (meta_data_key.IndexId() != index_id) 1438 return false; 1439 if (meta_data_key.meta_data_type() != meta_data_type) 1440 return false; 1441 return true; 1442} 1443 1444// TODO(jsbell): This should do some error handling rather than plowing ahead 1445// when bad data is encountered. 1446bool IndexedDBBackingStore::GetIndexes( 1447 int64 database_id, 1448 int64 object_store_id, 1449 IndexedDBObjectStoreMetadata::IndexMap* indexes) { 1450 IDB_TRACE("IndexedDBBackingStore::GetIndexes"); 1451 if (!KeyPrefix::ValidIds(database_id, object_store_id)) 1452 return false; 1453 const std::string start_key = 1454 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0); 1455 const std::string stop_key = 1456 IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0); 1457 1458 DCHECK(indexes->empty()); 1459 1460 scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); 1461 it->Seek(start_key); 1462 while (it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) { 1463 StringPiece slice(it->Key()); 1464 IndexMetaDataKey meta_data_key; 1465 bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key); 1466 DCHECK(ok); 1467 if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) { 1468 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1469 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail 1470 // the load. 1471 it->Next(); 1472 continue; 1473 } 1474 1475 // TODO(jsbell): Do this by direct key lookup rather than iteration, to 1476 // simplify. 1477 int64 index_id = meta_data_key.IndexId(); 1478 base::string16 index_name; 1479 { 1480 StringPiece slice(it->Value()); 1481 if (!DecodeString(&slice, &index_name) || !slice.empty()) 1482 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1483 } 1484 1485 it->Next(); // unique flag 1486 if (!CheckIndexAndMetaDataKey( 1487 it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) { 1488 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1489 break; 1490 } 1491 bool index_unique; 1492 { 1493 StringPiece slice(it->Value()); 1494 if (!DecodeBool(&slice, &index_unique) || !slice.empty()) 1495 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1496 } 1497 1498 it->Next(); // key_path 1499 if (!CheckIndexAndMetaDataKey( 1500 it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) { 1501 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1502 break; 1503 } 1504 IndexedDBKeyPath key_path; 1505 { 1506 StringPiece slice(it->Value()); 1507 if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty()) 1508 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1509 } 1510 1511 it->Next(); // [optional] multi_entry flag 1512 bool index_multi_entry = false; 1513 if (CheckIndexAndMetaDataKey( 1514 it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) { 1515 StringPiece slice(it->Value()); 1516 if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty()) 1517 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); 1518 1519 it->Next(); 1520 } 1521 1522 (*indexes)[index_id] = IndexedDBIndexMetadata( 1523 index_name, index_id, key_path, index_unique, index_multi_entry); 1524 } 1525 return true; 1526} 1527 1528WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, 1529 int64 database_id, 1530 int64 object_store_id, 1531 int64 index_id) { 1532 int64 max_index_id = -1; 1533 const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode( 1534 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); 1535 bool found = false; 1536 bool ok = GetInt(transaction, max_index_id_key, &max_index_id, &found); 1537 if (!ok) { 1538 INTERNAL_READ_ERROR(SET_MAX_INDEX_ID); 1539 return false; 1540 } 1541 if (!found) 1542 max_index_id = kMinimumIndexId; 1543 1544 if (index_id <= max_index_id) { 1545 INTERNAL_CONSISTENCY_ERROR(SET_MAX_INDEX_ID); 1546 return false; 1547 } 1548 1549 PutInt(transaction, max_index_id_key, index_id); 1550 return true; 1551} 1552 1553bool IndexedDBBackingStore::CreateIndex( 1554 IndexedDBBackingStore::Transaction* transaction, 1555 int64 database_id, 1556 int64 object_store_id, 1557 int64 index_id, 1558 const base::string16& name, 1559 const IndexedDBKeyPath& key_path, 1560 bool is_unique, 1561 bool is_multi_entry) { 1562 IDB_TRACE("IndexedDBBackingStore::CreateIndex"); 1563 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1564 return false; 1565 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1566 if (!SetMaxIndexId( 1567 leveldb_transaction, database_id, object_store_id, index_id)) 1568 return false; 1569 1570 const std::string name_key = IndexMetaDataKey::Encode( 1571 database_id, object_store_id, index_id, IndexMetaDataKey::NAME); 1572 const std::string unique_key = IndexMetaDataKey::Encode( 1573 database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE); 1574 const std::string key_path_key = IndexMetaDataKey::Encode( 1575 database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH); 1576 const std::string multi_entry_key = IndexMetaDataKey::Encode( 1577 database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY); 1578 1579 PutString(leveldb_transaction, name_key, name); 1580 PutBool(leveldb_transaction, unique_key, is_unique); 1581 PutIDBKeyPath(leveldb_transaction, key_path_key, key_path); 1582 PutBool(leveldb_transaction, multi_entry_key, is_multi_entry); 1583 return true; 1584} 1585 1586bool IndexedDBBackingStore::DeleteIndex( 1587 IndexedDBBackingStore::Transaction* transaction, 1588 int64 database_id, 1589 int64 object_store_id, 1590 int64 index_id) { 1591 IDB_TRACE("IndexedDBBackingStore::DeleteIndex"); 1592 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1593 return false; 1594 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1595 1596 const std::string index_meta_data_start = 1597 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); 1598 const std::string index_meta_data_end = 1599 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 1600 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); 1601 1602 const std::string index_data_start = 1603 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 1604 const std::string index_data_end = 1605 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 1606 DeleteRange(leveldb_transaction, index_data_start, index_data_end); 1607 return true; 1608} 1609 1610bool IndexedDBBackingStore::PutIndexDataForRecord( 1611 IndexedDBBackingStore::Transaction* transaction, 1612 int64 database_id, 1613 int64 object_store_id, 1614 int64 index_id, 1615 const IndexedDBKey& key, 1616 const RecordIdentifier& record_identifier) { 1617 IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord"); 1618 DCHECK(key.IsValid()); 1619 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1620 return false; 1621 1622 std::string encoded_key; 1623 EncodeIDBKey(key, &encoded_key); 1624 1625 const std::string index_data_key = 1626 IndexDataKey::Encode(database_id, 1627 object_store_id, 1628 index_id, 1629 encoded_key, 1630 record_identifier.primary_key(), 1631 0); 1632 1633 std::string data; 1634 EncodeVarInt(record_identifier.version(), &data); 1635 data.append(record_identifier.primary_key()); 1636 1637 transaction->transaction()->Put(index_data_key, &data); 1638 return true; 1639} 1640 1641static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, 1642 const std::string& target, 1643 std::string* found_key) { 1644 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); 1645 it->Seek(target); 1646 1647 if (!it->IsValid()) { 1648 it->SeekToLast(); 1649 if (!it->IsValid()) 1650 return false; 1651 } 1652 1653 while (CompareIndexKeys(it->Key(), target) > 0) { 1654 it->Prev(); 1655 if (!it->IsValid()) 1656 return false; 1657 } 1658 1659 do { 1660 *found_key = it->Key().as_string(); 1661 1662 // There can be several index keys that compare equal. We want the last one. 1663 it->Next(); 1664 } while (it->IsValid() && !CompareIndexKeys(it->Key(), target)); 1665 1666 return true; 1667} 1668 1669static bool VersionExists(LevelDBTransaction* transaction, 1670 int64 database_id, 1671 int64 object_store_id, 1672 int64 version, 1673 const std::string& encoded_primary_key, 1674 bool* exists) { 1675 const std::string key = 1676 ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key); 1677 std::string data; 1678 1679 bool ok = transaction->Get(key, &data, exists); 1680 if (!ok) { 1681 INTERNAL_READ_ERROR(VERSION_EXISTS); 1682 return false; 1683 } 1684 if (!*exists) 1685 return true; 1686 1687 StringPiece slice(data); 1688 int64 decoded; 1689 if (!DecodeInt(&slice, &decoded) || !slice.empty()) 1690 return false; 1691 *exists = (decoded == version); 1692 return true; 1693} 1694 1695bool IndexedDBBackingStore::FindKeyInIndex( 1696 IndexedDBBackingStore::Transaction* transaction, 1697 int64 database_id, 1698 int64 object_store_id, 1699 int64 index_id, 1700 const IndexedDBKey& key, 1701 std::string* found_encoded_primary_key, 1702 bool* found) { 1703 IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex"); 1704 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id)); 1705 1706 DCHECK(found_encoded_primary_key->empty()); 1707 *found = false; 1708 1709 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 1710 const std::string leveldb_key = 1711 IndexDataKey::Encode(database_id, object_store_id, index_id, key); 1712 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); 1713 it->Seek(leveldb_key); 1714 1715 for (;;) { 1716 if (!it->IsValid()) 1717 return true; 1718 if (CompareIndexKeys(it->Key(), leveldb_key) > 0) 1719 return true; 1720 1721 StringPiece slice(it->Value()); 1722 1723 int64 version; 1724 if (!DecodeVarInt(&slice, &version)) { 1725 INTERNAL_READ_ERROR(FIND_KEY_IN_INDEX); 1726 return false; 1727 } 1728 *found_encoded_primary_key = slice.as_string(); 1729 1730 bool exists = false; 1731 bool ok = VersionExists(leveldb_transaction, 1732 database_id, 1733 object_store_id, 1734 version, 1735 *found_encoded_primary_key, 1736 &exists); 1737 if (!ok) 1738 return false; 1739 if (!exists) { 1740 // Delete stale index data entry and continue. 1741 leveldb_transaction->Remove(it->Key()); 1742 it->Next(); 1743 continue; 1744 } 1745 *found = true; 1746 return true; 1747 } 1748} 1749 1750bool IndexedDBBackingStore::GetPrimaryKeyViaIndex( 1751 IndexedDBBackingStore::Transaction* transaction, 1752 int64 database_id, 1753 int64 object_store_id, 1754 int64 index_id, 1755 const IndexedDBKey& key, 1756 scoped_ptr<IndexedDBKey>* primary_key) { 1757 IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex"); 1758 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1759 return false; 1760 1761 bool found = false; 1762 std::string found_encoded_primary_key; 1763 bool ok = FindKeyInIndex(transaction, 1764 database_id, 1765 object_store_id, 1766 index_id, 1767 key, 1768 &found_encoded_primary_key, 1769 &found); 1770 if (!ok) { 1771 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX); 1772 return false; 1773 } 1774 if (!found) 1775 return true; 1776 if (!found_encoded_primary_key.size()) { 1777 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX); 1778 return false; 1779 } 1780 1781 StringPiece slice(found_encoded_primary_key); 1782 return DecodeIDBKey(&slice, primary_key) && slice.empty(); 1783} 1784 1785bool IndexedDBBackingStore::KeyExistsInIndex( 1786 IndexedDBBackingStore::Transaction* transaction, 1787 int64 database_id, 1788 int64 object_store_id, 1789 int64 index_id, 1790 const IndexedDBKey& index_key, 1791 scoped_ptr<IndexedDBKey>* found_primary_key, 1792 bool* exists) { 1793 IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex"); 1794 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 1795 return false; 1796 1797 *exists = false; 1798 std::string found_encoded_primary_key; 1799 bool ok = FindKeyInIndex(transaction, 1800 database_id, 1801 object_store_id, 1802 index_id, 1803 index_key, 1804 &found_encoded_primary_key, 1805 exists); 1806 if (!ok) { 1807 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); 1808 return false; 1809 } 1810 if (!*exists) 1811 return true; 1812 if (found_encoded_primary_key.empty()) { 1813 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); 1814 return false; 1815 } 1816 1817 StringPiece slice(found_encoded_primary_key); 1818 return DecodeIDBKey(&slice, found_primary_key) && slice.empty(); 1819} 1820 1821IndexedDBBackingStore::Cursor::Cursor( 1822 const IndexedDBBackingStore::Cursor* other) 1823 : transaction_(other->transaction_), 1824 cursor_options_(other->cursor_options_), 1825 current_key_(new IndexedDBKey(*other->current_key_)) { 1826 if (other->iterator_) { 1827 iterator_ = transaction_->CreateIterator(); 1828 1829 if (other->iterator_->IsValid()) { 1830 iterator_->Seek(other->iterator_->Key()); 1831 DCHECK(iterator_->IsValid()); 1832 } 1833 } 1834} 1835 1836IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, 1837 const CursorOptions& cursor_options) 1838 : transaction_(transaction), cursor_options_(cursor_options) {} 1839IndexedDBBackingStore::Cursor::~Cursor() {} 1840 1841bool IndexedDBBackingStore::Cursor::FirstSeek() { 1842 iterator_ = transaction_->CreateIterator(); 1843 if (cursor_options_.forward) 1844 iterator_->Seek(cursor_options_.low_key); 1845 else 1846 iterator_->Seek(cursor_options_.high_key); 1847 1848 return Continue(0, READY); 1849} 1850 1851bool IndexedDBBackingStore::Cursor::Advance(uint32 count) { 1852 while (count--) { 1853 if (!Continue()) 1854 return false; 1855 } 1856 return true; 1857} 1858 1859bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key, 1860 const IndexedDBKey* primary_key, 1861 IteratorState next_state) { 1862 DCHECK(!key || key->IsValid()); 1863 DCHECK(!primary_key || primary_key->IsValid()); 1864 1865 // TODO(alecflett): avoid a copy here? 1866 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); 1867 1868 bool first_iteration = true; 1869 1870 // When iterating with PrevNoDuplicate, spec requires that the 1871 // value we yield for each key is the first duplicate in forwards 1872 // order. 1873 IndexedDBKey last_duplicate_key; 1874 1875 bool forward = cursor_options_.forward; 1876 1877 for (;;) { 1878 if (next_state == SEEK) { 1879 // TODO(jsbell): Optimize seeking for reverse cursors as well. 1880 if (first_iteration && key && forward) { 1881 std::string leveldb_key; 1882 if (primary_key) { 1883 leveldb_key = EncodeKey(*key, *primary_key); 1884 } else { 1885 leveldb_key = EncodeKey(*key); 1886 } 1887 iterator_->Seek(leveldb_key); 1888 first_iteration = false; 1889 } else if (forward) { 1890 iterator_->Next(); 1891 } else { 1892 iterator_->Prev(); 1893 } 1894 } else { 1895 next_state = SEEK; // for subsequent iterations 1896 } 1897 1898 if (!iterator_->IsValid()) { 1899 if (!forward && last_duplicate_key.IsValid()) { 1900 // We need to walk forward because we hit the end of 1901 // the data. 1902 forward = true; 1903 continue; 1904 } 1905 1906 return false; 1907 } 1908 1909 if (IsPastBounds()) { 1910 if (!forward && last_duplicate_key.IsValid()) { 1911 // We need to walk forward because now we're beyond the 1912 // bounds defined by the cursor. 1913 forward = true; 1914 continue; 1915 } 1916 1917 return false; 1918 } 1919 1920 if (!HaveEnteredRange()) 1921 continue; 1922 1923 // The row may not load because there's a stale entry in the 1924 // index. This is not fatal. 1925 if (!LoadCurrentRow()) 1926 continue; 1927 1928 if (key) { 1929 if (forward) { 1930 if (primary_key && current_key_->IsEqual(*key) && 1931 this->primary_key().IsLessThan(*primary_key)) 1932 continue; 1933 if (current_key_->IsLessThan(*key)) 1934 continue; 1935 } else { 1936 if (primary_key && key->IsEqual(*current_key_) && 1937 primary_key->IsLessThan(this->primary_key())) 1938 continue; 1939 if (key->IsLessThan(*current_key_)) 1940 continue; 1941 } 1942 } 1943 1944 if (cursor_options_.unique) { 1945 if (previous_key.IsValid() && current_key_->IsEqual(previous_key)) { 1946 // We should never be able to walk forward all the way 1947 // to the previous key. 1948 DCHECK(!last_duplicate_key.IsValid()); 1949 continue; 1950 } 1951 1952 if (!forward) { 1953 if (!last_duplicate_key.IsValid()) { 1954 last_duplicate_key = *current_key_; 1955 continue; 1956 } 1957 1958 // We need to walk forward because we hit the boundary 1959 // between key ranges. 1960 if (!last_duplicate_key.IsEqual(*current_key_)) { 1961 forward = true; 1962 continue; 1963 } 1964 1965 continue; 1966 } 1967 } 1968 break; 1969 } 1970 1971 DCHECK(!last_duplicate_key.IsValid() || 1972 (forward && last_duplicate_key.IsEqual(*current_key_))); 1973 return true; 1974} 1975 1976bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { 1977 if (cursor_options_.forward) { 1978 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 1979 if (cursor_options_.low_open) { 1980 return compare > 0; 1981 } 1982 return compare >= 0; 1983 } 1984 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 1985 if (cursor_options_.high_open) { 1986 return compare < 0; 1987 } 1988 return compare <= 0; 1989} 1990 1991bool IndexedDBBackingStore::Cursor::IsPastBounds() const { 1992 if (cursor_options_.forward) { 1993 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key); 1994 if (cursor_options_.high_open) { 1995 return compare >= 0; 1996 } 1997 return compare > 0; 1998 } 1999 int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key); 2000 if (cursor_options_.low_open) { 2001 return compare <= 0; 2002 } 2003 return compare < 0; 2004} 2005 2006const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const { 2007 return *current_key_; 2008} 2009 2010const IndexedDBBackingStore::RecordIdentifier& 2011IndexedDBBackingStore::Cursor::record_identifier() const { 2012 return record_identifier_; 2013} 2014 2015class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { 2016 public: 2017 ObjectStoreKeyCursorImpl( 2018 LevelDBTransaction* transaction, 2019 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2020 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2021 2022 virtual Cursor* Clone() OVERRIDE { 2023 return new ObjectStoreKeyCursorImpl(this); 2024 } 2025 2026 // IndexedDBBackingStore::Cursor 2027 virtual std::string* value() OVERRIDE { 2028 NOTREACHED(); 2029 return NULL; 2030 } 2031 virtual bool LoadCurrentRow() OVERRIDE; 2032 2033 protected: 2034 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2035 return ObjectStoreDataKey::Encode( 2036 cursor_options_.database_id, cursor_options_.object_store_id, key); 2037 } 2038 virtual std::string EncodeKey(const IndexedDBKey& key, 2039 const IndexedDBKey& primary_key) OVERRIDE { 2040 NOTREACHED(); 2041 return std::string(); 2042 } 2043 2044 private: 2045 explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other) 2046 : IndexedDBBackingStore::Cursor(other) {} 2047}; 2048 2049bool ObjectStoreKeyCursorImpl::LoadCurrentRow() { 2050 StringPiece slice(iterator_->Key()); 2051 ObjectStoreDataKey object_store_data_key; 2052 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { 2053 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2054 return false; 2055 } 2056 2057 current_key_ = object_store_data_key.user_key(); 2058 2059 int64 version; 2060 slice = StringPiece(iterator_->Value()); 2061 if (!DecodeVarInt(&slice, &version)) { 2062 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2063 return false; 2064 } 2065 2066 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 2067 std::string encoded_key; 2068 EncodeIDBKey(*current_key_, &encoded_key); 2069 record_identifier_.Reset(encoded_key, version); 2070 2071 return true; 2072} 2073 2074class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { 2075 public: 2076 ObjectStoreCursorImpl( 2077 LevelDBTransaction* transaction, 2078 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2079 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2080 2081 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } 2082 2083 // IndexedDBBackingStore::Cursor 2084 virtual std::string* value() OVERRIDE { return ¤t_value_; } 2085 virtual bool LoadCurrentRow() OVERRIDE; 2086 2087 protected: 2088 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2089 return ObjectStoreDataKey::Encode( 2090 cursor_options_.database_id, cursor_options_.object_store_id, key); 2091 } 2092 virtual std::string EncodeKey(const IndexedDBKey& key, 2093 const IndexedDBKey& primary_key) OVERRIDE { 2094 NOTREACHED(); 2095 return std::string(); 2096 } 2097 2098 private: 2099 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) 2100 : IndexedDBBackingStore::Cursor(other), 2101 current_value_(other->current_value_) {} 2102 2103 std::string current_value_; 2104}; 2105 2106bool ObjectStoreCursorImpl::LoadCurrentRow() { 2107 StringPiece slice(iterator_->Key()); 2108 ObjectStoreDataKey object_store_data_key; 2109 if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) { 2110 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2111 return false; 2112 } 2113 2114 current_key_ = object_store_data_key.user_key(); 2115 2116 int64 version; 2117 slice = StringPiece(iterator_->Value()); 2118 if (!DecodeVarInt(&slice, &version)) { 2119 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2120 return false; 2121 } 2122 2123 // TODO(jsbell): This re-encodes what was just decoded; try and optimize. 2124 std::string encoded_key; 2125 EncodeIDBKey(*current_key_, &encoded_key); 2126 record_identifier_.Reset(encoded_key, version); 2127 2128 current_value_ = slice.as_string(); 2129 return true; 2130} 2131 2132class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { 2133 public: 2134 IndexKeyCursorImpl( 2135 LevelDBTransaction* transaction, 2136 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2137 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2138 2139 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } 2140 2141 // IndexedDBBackingStore::Cursor 2142 virtual std::string* value() OVERRIDE { 2143 NOTREACHED(); 2144 return NULL; 2145 } 2146 virtual const IndexedDBKey& primary_key() const OVERRIDE { 2147 return *primary_key_; 2148 } 2149 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 2150 const OVERRIDE { 2151 NOTREACHED(); 2152 return record_identifier_; 2153 } 2154 virtual bool LoadCurrentRow() OVERRIDE; 2155 2156 protected: 2157 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2158 return IndexDataKey::Encode(cursor_options_.database_id, 2159 cursor_options_.object_store_id, 2160 cursor_options_.index_id, 2161 key); 2162 } 2163 virtual std::string EncodeKey(const IndexedDBKey& key, 2164 const IndexedDBKey& primary_key) OVERRIDE { 2165 return IndexDataKey::Encode(cursor_options_.database_id, 2166 cursor_options_.object_store_id, 2167 cursor_options_.index_id, 2168 key, 2169 primary_key); 2170 } 2171 2172 private: 2173 explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other) 2174 : IndexedDBBackingStore::Cursor(other), 2175 primary_key_(new IndexedDBKey(*other->primary_key_)) {} 2176 2177 scoped_ptr<IndexedDBKey> primary_key_; 2178}; 2179 2180bool IndexKeyCursorImpl::LoadCurrentRow() { 2181 StringPiece slice(iterator_->Key()); 2182 IndexDataKey index_data_key; 2183 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 2184 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2185 return false; 2186 } 2187 2188 current_key_ = index_data_key.user_key(); 2189 DCHECK(current_key_); 2190 2191 slice = StringPiece(iterator_->Value()); 2192 int64 index_data_version; 2193 if (!DecodeVarInt(&slice, &index_data_version)) { 2194 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2195 return false; 2196 } 2197 2198 if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) { 2199 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2200 return false; 2201 } 2202 2203 std::string primary_leveldb_key = 2204 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 2205 index_data_key.ObjectStoreId(), 2206 *primary_key_); 2207 2208 std::string result; 2209 bool found = false; 2210 bool ok = transaction_->Get(primary_leveldb_key, &result, &found); 2211 if (!ok) { 2212 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2213 return false; 2214 } 2215 if (!found) { 2216 transaction_->Remove(iterator_->Key()); 2217 return false; 2218 } 2219 if (!result.size()) { 2220 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2221 return false; 2222 } 2223 2224 int64 object_store_data_version; 2225 slice = StringPiece(result); 2226 if (!DecodeVarInt(&slice, &object_store_data_version)) { 2227 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2228 return false; 2229 } 2230 2231 if (object_store_data_version != index_data_version) { 2232 transaction_->Remove(iterator_->Key()); 2233 return false; 2234 } 2235 2236 return true; 2237} 2238 2239class IndexCursorImpl : public IndexedDBBackingStore::Cursor { 2240 public: 2241 IndexCursorImpl( 2242 LevelDBTransaction* transaction, 2243 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) 2244 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} 2245 2246 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } 2247 2248 // IndexedDBBackingStore::Cursor 2249 virtual std::string* value() OVERRIDE { return ¤t_value_; } 2250 virtual const IndexedDBKey& primary_key() const OVERRIDE { 2251 return *primary_key_; 2252 } 2253 virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier() 2254 const OVERRIDE { 2255 NOTREACHED(); 2256 return record_identifier_; 2257 } 2258 virtual bool LoadCurrentRow() OVERRIDE; 2259 2260 protected: 2261 virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE { 2262 return IndexDataKey::Encode(cursor_options_.database_id, 2263 cursor_options_.object_store_id, 2264 cursor_options_.index_id, 2265 key); 2266 } 2267 virtual std::string EncodeKey(const IndexedDBKey& key, 2268 const IndexedDBKey& primary_key) OVERRIDE { 2269 return IndexDataKey::Encode(cursor_options_.database_id, 2270 cursor_options_.object_store_id, 2271 cursor_options_.index_id, 2272 key, 2273 primary_key); 2274 } 2275 2276 private: 2277 explicit IndexCursorImpl(const IndexCursorImpl* other) 2278 : IndexedDBBackingStore::Cursor(other), 2279 primary_key_(new IndexedDBKey(*other->primary_key_)), 2280 current_value_(other->current_value_), 2281 primary_leveldb_key_(other->primary_leveldb_key_) {} 2282 2283 scoped_ptr<IndexedDBKey> primary_key_; 2284 std::string current_value_; 2285 std::string primary_leveldb_key_; 2286}; 2287 2288bool IndexCursorImpl::LoadCurrentRow() { 2289 StringPiece slice(iterator_->Key()); 2290 IndexDataKey index_data_key; 2291 if (!IndexDataKey::Decode(&slice, &index_data_key)) { 2292 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2293 return false; 2294 } 2295 2296 current_key_ = index_data_key.user_key(); 2297 DCHECK(current_key_); 2298 2299 slice = StringPiece(iterator_->Value()); 2300 int64 index_data_version; 2301 if (!DecodeVarInt(&slice, &index_data_version)) { 2302 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2303 return false; 2304 } 2305 if (!DecodeIDBKey(&slice, &primary_key_)) { 2306 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2307 return false; 2308 } 2309 2310 primary_leveldb_key_ = 2311 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), 2312 index_data_key.ObjectStoreId(), 2313 *primary_key_); 2314 2315 std::string result; 2316 bool found = false; 2317 bool ok = transaction_->Get(primary_leveldb_key_, &result, &found); 2318 if (!ok) { 2319 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2320 return false; 2321 } 2322 if (!found) { 2323 transaction_->Remove(iterator_->Key()); 2324 return false; 2325 } 2326 if (!result.size()) { 2327 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2328 return false; 2329 } 2330 2331 int64 object_store_data_version; 2332 slice = StringPiece(result); 2333 if (!DecodeVarInt(&slice, &object_store_data_version)) { 2334 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); 2335 return false; 2336 } 2337 2338 if (object_store_data_version != index_data_version) { 2339 transaction_->Remove(iterator_->Key()); 2340 return false; 2341 } 2342 2343 current_value_ = slice.as_string(); 2344 return true; 2345} 2346 2347bool ObjectStoreCursorOptions( 2348 LevelDBTransaction* transaction, 2349 int64 database_id, 2350 int64 object_store_id, 2351 const IndexedDBKeyRange& range, 2352 indexed_db::CursorDirection direction, 2353 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 2354 cursor_options->database_id = database_id; 2355 cursor_options->object_store_id = object_store_id; 2356 2357 bool lower_bound = range.lower().IsValid(); 2358 bool upper_bound = range.upper().IsValid(); 2359 cursor_options->forward = 2360 (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2361 direction == indexed_db::CURSOR_NEXT); 2362 cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2363 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); 2364 2365 if (!lower_bound) { 2366 cursor_options->low_key = 2367 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); 2368 cursor_options->low_open = true; // Not included. 2369 } else { 2370 cursor_options->low_key = 2371 ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower()); 2372 cursor_options->low_open = range.lowerOpen(); 2373 } 2374 2375 if (!upper_bound) { 2376 cursor_options->high_key = 2377 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); 2378 2379 if (cursor_options->forward) { 2380 cursor_options->high_open = true; // Not included. 2381 } else { 2382 // We need a key that exists. 2383 if (!FindGreatestKeyLessThanOrEqual(transaction, 2384 cursor_options->high_key, 2385 &cursor_options->high_key)) 2386 return false; 2387 cursor_options->high_open = false; 2388 } 2389 } else { 2390 cursor_options->high_key = 2391 ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper()); 2392 cursor_options->high_open = range.upperOpen(); 2393 2394 if (!cursor_options->forward) { 2395 // For reverse cursors, we need a key that exists. 2396 std::string found_high_key; 2397 if (!FindGreatestKeyLessThanOrEqual( 2398 transaction, cursor_options->high_key, &found_high_key)) 2399 return false; 2400 2401 // If the target key should not be included, but we end up with a smaller 2402 // key, we should include that. 2403 if (cursor_options->high_open && 2404 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 2405 cursor_options->high_open = false; 2406 2407 cursor_options->high_key = found_high_key; 2408 } 2409 } 2410 2411 return true; 2412} 2413 2414bool IndexCursorOptions( 2415 LevelDBTransaction* transaction, 2416 int64 database_id, 2417 int64 object_store_id, 2418 int64 index_id, 2419 const IndexedDBKeyRange& range, 2420 indexed_db::CursorDirection direction, 2421 IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) { 2422 DCHECK(transaction); 2423 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) 2424 return false; 2425 2426 cursor_options->database_id = database_id; 2427 cursor_options->object_store_id = object_store_id; 2428 cursor_options->index_id = index_id; 2429 2430 bool lower_bound = range.lower().IsValid(); 2431 bool upper_bound = range.upper().IsValid(); 2432 cursor_options->forward = 2433 (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2434 direction == indexed_db::CURSOR_NEXT); 2435 cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || 2436 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); 2437 2438 if (!lower_bound) { 2439 cursor_options->low_key = 2440 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); 2441 cursor_options->low_open = false; // Included. 2442 } else { 2443 cursor_options->low_key = IndexDataKey::Encode( 2444 database_id, object_store_id, index_id, range.lower()); 2445 cursor_options->low_open = range.lowerOpen(); 2446 } 2447 2448 if (!upper_bound) { 2449 cursor_options->high_key = 2450 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); 2451 cursor_options->high_open = false; // Included. 2452 2453 if (!cursor_options->forward) { // We need a key that exists. 2454 if (!FindGreatestKeyLessThanOrEqual(transaction, 2455 cursor_options->high_key, 2456 &cursor_options->high_key)) 2457 return false; 2458 cursor_options->high_open = false; 2459 } 2460 } else { 2461 cursor_options->high_key = IndexDataKey::Encode( 2462 database_id, object_store_id, index_id, range.upper()); 2463 cursor_options->high_open = range.upperOpen(); 2464 2465 std::string found_high_key; 2466 // Seek to the *last* key in the set of non-unique keys 2467 if (!FindGreatestKeyLessThanOrEqual( 2468 transaction, cursor_options->high_key, &found_high_key)) 2469 return false; 2470 2471 // If the target key should not be included, but we end up with a smaller 2472 // key, we should include that. 2473 if (cursor_options->high_open && 2474 CompareIndexKeys(found_high_key, cursor_options->high_key) < 0) 2475 cursor_options->high_open = false; 2476 2477 cursor_options->high_key = found_high_key; 2478 } 2479 2480 return true; 2481} 2482 2483scoped_ptr<IndexedDBBackingStore::Cursor> 2484IndexedDBBackingStore::OpenObjectStoreCursor( 2485 IndexedDBBackingStore::Transaction* transaction, 2486 int64 database_id, 2487 int64 object_store_id, 2488 const IndexedDBKeyRange& range, 2489 indexed_db::CursorDirection direction) { 2490 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor"); 2491 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2492 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2493 if (!ObjectStoreCursorOptions(leveldb_transaction, 2494 database_id, 2495 object_store_id, 2496 range, 2497 direction, 2498 &cursor_options)) 2499 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2500 scoped_ptr<ObjectStoreCursorImpl> cursor( 2501 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); 2502 if (!cursor->FirstSeek()) 2503 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2504 2505 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2506} 2507 2508scoped_ptr<IndexedDBBackingStore::Cursor> 2509IndexedDBBackingStore::OpenObjectStoreKeyCursor( 2510 IndexedDBBackingStore::Transaction* transaction, 2511 int64 database_id, 2512 int64 object_store_id, 2513 const IndexedDBKeyRange& range, 2514 indexed_db::CursorDirection direction) { 2515 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor"); 2516 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2517 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2518 if (!ObjectStoreCursorOptions(leveldb_transaction, 2519 database_id, 2520 object_store_id, 2521 range, 2522 direction, 2523 &cursor_options)) 2524 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2525 scoped_ptr<ObjectStoreKeyCursorImpl> cursor( 2526 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); 2527 if (!cursor->FirstSeek()) 2528 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2529 2530 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2531} 2532 2533scoped_ptr<IndexedDBBackingStore::Cursor> 2534IndexedDBBackingStore::OpenIndexKeyCursor( 2535 IndexedDBBackingStore::Transaction* transaction, 2536 int64 database_id, 2537 int64 object_store_id, 2538 int64 index_id, 2539 const IndexedDBKeyRange& range, 2540 indexed_db::CursorDirection direction) { 2541 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor"); 2542 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2543 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2544 if (!IndexCursorOptions(leveldb_transaction, 2545 database_id, 2546 object_store_id, 2547 index_id, 2548 range, 2549 direction, 2550 &cursor_options)) 2551 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2552 scoped_ptr<IndexKeyCursorImpl> cursor( 2553 new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); 2554 if (!cursor->FirstSeek()) 2555 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2556 2557 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2558} 2559 2560scoped_ptr<IndexedDBBackingStore::Cursor> 2561IndexedDBBackingStore::OpenIndexCursor( 2562 IndexedDBBackingStore::Transaction* transaction, 2563 int64 database_id, 2564 int64 object_store_id, 2565 int64 index_id, 2566 const IndexedDBKeyRange& range, 2567 indexed_db::CursorDirection direction) { 2568 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor"); 2569 LevelDBTransaction* leveldb_transaction = transaction->transaction(); 2570 IndexedDBBackingStore::Cursor::CursorOptions cursor_options; 2571 if (!IndexCursorOptions(leveldb_transaction, 2572 database_id, 2573 object_store_id, 2574 index_id, 2575 range, 2576 direction, 2577 &cursor_options)) 2578 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2579 scoped_ptr<IndexCursorImpl> cursor( 2580 new IndexCursorImpl(leveldb_transaction, cursor_options)); 2581 if (!cursor->FirstSeek()) 2582 return scoped_ptr<IndexedDBBackingStore::Cursor>(); 2583 2584 return cursor.PassAs<IndexedDBBackingStore::Cursor>(); 2585} 2586 2587IndexedDBBackingStore::Transaction::Transaction( 2588 IndexedDBBackingStore* backing_store) 2589 : backing_store_(backing_store) {} 2590 2591IndexedDBBackingStore::Transaction::~Transaction() {} 2592 2593void IndexedDBBackingStore::Transaction::Begin() { 2594 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin"); 2595 DCHECK(!transaction_.get()); 2596 transaction_ = new LevelDBTransaction(backing_store_->db_.get()); 2597} 2598 2599bool IndexedDBBackingStore::Transaction::Commit() { 2600 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit"); 2601 DCHECK(transaction_.get()); 2602 bool result = transaction_->Commit(); 2603 transaction_ = NULL; 2604 if (!result) 2605 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); 2606 return result; 2607} 2608 2609void IndexedDBBackingStore::Transaction::Rollback() { 2610 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); 2611 DCHECK(transaction_.get()); 2612 transaction_->Rollback(); 2613 transaction_ = NULL; 2614} 2615 2616} // namespace content 2617