Index: content/browser/indexed_db/indexed_db_backing_store.cc |
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc |
deleted file mode 100644 |
index 47d5011084c20271ac0d0ad541388b5f4ce8d3d7..0000000000000000000000000000000000000000 |
--- a/content/browser/indexed_db/indexed_db_backing_store.cc |
+++ /dev/null |
@@ -1,2514 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/browser/indexed_db/indexed_db_backing_store.h" |
- |
-#include <string> |
- |
-#include "base/file_util.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/utf_string_conversions.h" |
-#include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
-#include "content/browser/indexed_db/indexed_db_metadata.h" |
-#include "content/browser/indexed_db/indexed_db_tracing.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_database.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_iterator.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_slice.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_transaction.h" |
-#include "content/common/indexed_db/indexed_db_key.h" |
-#include "content/common/indexed_db/indexed_db_key_path.h" |
-#include "content/common/indexed_db/indexed_db_key_range.h" |
-#include "third_party/WebKit/Source/Platform/chromium/public/WebIDBKey.h" |
-#include "third_party/WebKit/Source/Platform/chromium/public/WebIDBKeyPath.h" |
- |
-// TODO(jsbell): Make blink push the version during the open() call. |
-static const uint32 kWireVersion = 2; |
- |
-namespace content { |
- |
-static const int64 kKeyGeneratorInitialNumber = |
- 1; // From the IndexedDB specification. |
- |
-enum IndexedDBBackingStoreErrorSource { |
- // 0 - 2 are no longer used. |
- FIND_KEY_IN_INDEX = 3, |
- GET_IDBDATABASE_METADATA, |
- GET_INDEXES, |
- GET_KEY_GENERATOR_CURRENT_NUMBER, |
- GET_OBJECT_STORES, |
- GET_RECORD, |
- KEY_EXISTS_IN_OBJECT_STORE, |
- LOAD_CURRENT_ROW, |
- SET_UP_METADATA, |
- GET_PRIMARY_KEY_VIA_INDEX, |
- KEY_EXISTS_IN_INDEX, |
- VERSION_EXISTS, |
- DELETE_OBJECT_STORE, |
- SET_MAX_OBJECT_STORE_ID, |
- SET_MAX_INDEX_ID, |
- GET_NEW_DATABASE_ID, |
- GET_NEW_VERSION_NUMBER, |
- CREATE_IDBDATABASE_METADATA, |
- DELETE_DATABASE, |
- TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro |
- INTERNAL_ERROR_MAX, |
-}; |
- |
-static void RecordInternalError(const char* type, |
- IndexedDBBackingStoreErrorSource location) { |
- string16 name = ASCIIToUTF16("WebCore.IndexedDB.BackingStore.") + |
- UTF8ToUTF16(type) + ASCIIToUTF16("Error"); |
- base::Histogram::FactoryGet(UTF16ToUTF8(name), |
- 1, |
- INTERNAL_ERROR_MAX, |
- INTERNAL_ERROR_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(location); |
-} |
- |
-// Use to signal conditions that usually indicate developer error, but |
-// could be caused by data corruption. A macro is used instead of an |
-// inline function so that the assert and log report the line number. |
-#define REPORT_ERROR(type, location) \ |
- do { \ |
- LOG(ERROR) << "IndexedDB " type " Error: " #location; \ |
- NOTREACHED(); \ |
- RecordInternalError(type, location); \ |
- } while (0) |
- |
-#define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location) |
-#define INTERNAL_CONSISTENCY_ERROR(location) \ |
- REPORT_ERROR("Consistency", location) |
-#define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location) |
- |
-static void PutBool(LevelDBTransaction* transaction, |
- const LevelDBSlice& key, |
- bool value) { |
- transaction->Put(key, EncodeBool(value)); |
-} |
- |
-template <typename DBOrTransaction> |
-static bool GetInt(DBOrTransaction* db, |
- const LevelDBSlice& key, |
- int64& found_int, |
- bool& found) { |
- std::vector<char> result; |
- bool ok = db->Get(key, result, found); |
- if (!ok) |
- return false; |
- if (!found) |
- return true; |
- |
- found_int = DecodeInt(result.begin(), result.end()); |
- return true; |
-} |
- |
-static void PutInt(LevelDBTransaction* transaction, |
- const LevelDBSlice& key, |
- int64 value) { |
- DCHECK_GE(value, 0); |
- transaction->Put(key, EncodeInt(value)); |
-} |
- |
-template <typename DBOrTransaction> |
-WARN_UNUSED_RESULT static bool GetVarInt(DBOrTransaction* db, |
- const LevelDBSlice& key, |
- int64& found_int, |
- bool& found) { |
- std::vector<char> result; |
- bool ok = db->Get(key, result, found); |
- if (!ok) |
- return false; |
- if (!found) |
- return true; |
- |
- found = DecodeVarInt(&*result.begin(), &*result.rbegin() + 1, found_int) == |
- &*result.rbegin() + 1; |
- return true; |
-} |
- |
-static void PutVarInt(LevelDBTransaction* transaction, |
- const LevelDBSlice& key, |
- int64 value) { |
- transaction->Put(key, EncodeVarInt(value)); |
-} |
- |
-template <typename DBOrTransaction> |
-WARN_UNUSED_RESULT static bool GetString(DBOrTransaction* db, |
- const LevelDBSlice& key, |
- string16& found_string, |
- bool& found) { |
- std::vector<char> result; |
- found = false; |
- bool ok = db->Get(key, result, found); |
- if (!ok) |
- return false; |
- if (!found) |
- return true; |
- |
- found_string = DecodeString(&result[0], &result[0] + result.size()); |
- return true; |
-} |
- |
-static void PutString(LevelDBTransaction* transaction, |
- const LevelDBSlice& key, |
- const string16& value) { |
- transaction->Put(key, EncodeString(value)); |
-} |
- |
-static void PutIDBKeyPath(LevelDBTransaction* transaction, |
- const LevelDBSlice& key, |
- const IndexedDBKeyPath& value) { |
- transaction->Put(key, EncodeIDBKeyPath(value)); |
-} |
- |
-static int CompareKeys(const LevelDBSlice& a, const LevelDBSlice& b) { |
- return Compare(a, b); |
-} |
- |
-static int CompareIndexKeys(const LevelDBSlice& a, const LevelDBSlice& b) { |
- return Compare(a, b, true); |
-} |
- |
-class Comparator : public LevelDBComparator { |
- public: |
- virtual int Compare(const LevelDBSlice& a, const LevelDBSlice& b) const |
- OVERRIDE { |
- return content::Compare(a, b); |
- } |
- virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } |
-}; |
- |
-// 0 - Initial version. |
-// 1 - Adds UserIntVersion to DatabaseMetaData. |
-// 2 - Adds DataVersion to to global metadata. |
-static const int64 kLatestKnownSchemaVersion = 2; |
-WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) { |
- int64 db_schema_version = 0; |
- bool found = false; |
- bool ok = GetInt( |
- db, LevelDBSlice(SchemaVersionKey::Encode()), db_schema_version, found); |
- if (!ok) |
- return false; |
- if (!found) { |
- *known = true; |
- return true; |
- } |
- if (db_schema_version > kLatestKnownSchemaVersion) { |
- *known = false; |
- return true; |
- } |
- |
- const uint32 latest_known_data_version = kWireVersion; |
- int64 db_data_version = 0; |
- ok = GetInt( |
- db, LevelDBSlice(DataVersionKey::Encode()), db_data_version, found); |
- if (!ok) |
- return false; |
- if (!found) { |
- *known = true; |
- return true; |
- } |
- |
- if (db_data_version > latest_known_data_version) { |
- *known = false; |
- return true; |
- } |
- |
- *known = true; |
- return true; |
-} |
- |
-WARN_UNUSED_RESULT static bool SetUpMetadata(LevelDBDatabase* db, |
- const string16& origin) { |
- const uint32 latest_known_data_version = kWireVersion; |
- const std::vector<char> schema_version_key = SchemaVersionKey::Encode(); |
- const std::vector<char> data_version_key = DataVersionKey::Encode(); |
- |
- scoped_refptr<LevelDBTransaction> transaction = |
- LevelDBTransaction::Create(db); |
- |
- int64 db_schema_version = 0; |
- int64 db_data_version = 0; |
- bool found = false; |
- bool ok = GetInt(transaction.get(), |
- LevelDBSlice(schema_version_key), |
- db_schema_version, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- if (!found) { |
- // Initialize new backing store. |
- db_schema_version = kLatestKnownSchemaVersion; |
- PutInt( |
- transaction.get(), LevelDBSlice(schema_version_key), db_schema_version); |
- db_data_version = latest_known_data_version; |
- PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version); |
- } else { |
- // Upgrade old backing store. |
- DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion); |
- if (db_schema_version < 1) { |
- db_schema_version = 1; |
- PutInt(transaction.get(), |
- LevelDBSlice(schema_version_key), |
- db_schema_version); |
- const std::vector<char> start_key = |
- DatabaseNameKey::EncodeMinKeyForOrigin(origin); |
- const std::vector<char> stop_key = |
- DatabaseNameKey::EncodeStopKeyForOrigin(origin); |
- scoped_ptr<LevelDBIterator> it = db->CreateIterator(); |
- for (it->Seek(LevelDBSlice(start_key)); |
- it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0; |
- it->Next()) { |
- int64 database_id = 0; |
- found = false; |
- bool ok = GetInt(transaction.get(), it->Key(), database_id, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- if (!found) { |
- INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- std::vector<char> int_version_key = DatabaseMetaDataKey::Encode( |
- database_id, DatabaseMetaDataKey::USER_INT_VERSION); |
- PutVarInt(transaction.get(), |
- LevelDBSlice(int_version_key), |
- IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); |
- } |
- } |
- if (db_schema_version < 2) { |
- db_schema_version = 2; |
- PutInt(transaction.get(), |
- LevelDBSlice(schema_version_key), |
- db_schema_version); |
- db_data_version = kWireVersion; |
- PutInt( |
- transaction.get(), LevelDBSlice(data_version_key), db_data_version); |
- } |
- } |
- |
- // All new values will be written using this serialization version. |
- found = false; |
- ok = GetInt(transaction.get(), |
- LevelDBSlice(data_version_key), |
- db_data_version, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- if (!found) { |
- INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- if (db_data_version < latest_known_data_version) { |
- db_data_version = latest_known_data_version; |
- PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version); |
- } |
- |
- DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion); |
- DCHECK_EQ(db_data_version, latest_known_data_version); |
- |
- if (!transaction->Commit()) { |
- INTERNAL_WRITE_ERROR(SET_UP_METADATA); |
- return false; |
- } |
- return true; |
-} |
- |
-template <typename DBOrTransaction> |
-WARN_UNUSED_RESULT static bool GetMaxObjectStoreId(DBOrTransaction* db, |
- int64 database_id, |
- int64& max_object_store_id) { |
- const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode( |
- database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); |
- bool ok = |
- GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id); |
- return ok; |
-} |
- |
-template <typename DBOrTransaction> |
-WARN_UNUSED_RESULT static bool GetMaxObjectStoreId( |
- DBOrTransaction* db, |
- const std::vector<char>& max_object_store_id_key, |
- int64& max_object_store_id) { |
- max_object_store_id = -1; |
- bool found = false; |
- bool ok = GetInt( |
- db, LevelDBSlice(max_object_store_id_key), max_object_store_id, found); |
- if (!ok) |
- return false; |
- if (!found) |
- max_object_store_id = 0; |
- |
- DCHECK_GE(max_object_store_id, 0); |
- return true; |
-} |
- |
-class DefaultLevelDBFactory : public LevelDBFactory { |
- public: |
- virtual scoped_ptr<LevelDBDatabase> OpenLevelDB( |
- const base::FilePath& file_name, |
- const LevelDBComparator* comparator) OVERRIDE { |
- return LevelDBDatabase::Open(file_name, comparator); |
- } |
- virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { |
- return LevelDBDatabase::Destroy(file_name); |
- } |
-}; |
- |
-IndexedDBBackingStore::IndexedDBBackingStore( |
- const string16& identifier, |
- scoped_ptr<LevelDBDatabase> db, |
- scoped_ptr<LevelDBComparator> comparator) |
- : identifier_(identifier), |
- db_(db.Pass()), |
- comparator_(comparator.Pass()), |
- weak_factory_(this) {} |
- |
-IndexedDBBackingStore::~IndexedDBBackingStore() { |
- // db_'s destructor uses comparator_. The order of destruction is important. |
- db_.reset(); |
- comparator_.reset(); |
-} |
- |
-IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( |
- const std::vector<char>& primary_key, |
- int64 version) |
- : primary_key_(primary_key), version_(version) { |
- DCHECK(!primary_key.empty()); |
-} |
-IndexedDBBackingStore::RecordIdentifier::RecordIdentifier() |
- : primary_key_(), version_(-1) {} |
-IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {} |
- |
-IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {} |
-IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {} |
- |
-enum IndexedDBLevelDBBackingStoreOpenResult { |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_SUCCESS, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
-}; |
- |
-scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
- const string16& database_identifier, |
- const string16& path_base_arg, |
- const string16& file_identifier) { |
- DefaultLevelDBFactory leveldb_factory; |
- return IndexedDBBackingStore::Open( |
- database_identifier, path_base_arg, file_identifier, &leveldb_factory); |
-} |
- |
-scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( |
- const string16& database_identifier, |
- const string16& path_base_arg, |
- const string16& file_identifier, |
- LevelDBFactory* leveldb_factory) { |
- IDB_TRACE("IndexedDBBackingStore::open"); |
- DCHECK(!path_base_arg.empty()); |
- string16 path_base = path_base_arg; |
- |
- scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
- scoped_ptr<LevelDBDatabase> db; |
- |
- if (!IsStringASCII(path_base)) { |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII); |
- } |
- base::FilePath file_path_base = |
- base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(path_base)); |
- if (!file_util::CreateDirectory(file_path_base)) { |
- LOG(ERROR) << "Unable to create IndexedDB database path " << path_base; |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY); |
- return scoped_refptr<IndexedDBBackingStore>(); |
- } |
- |
- // TODO(jsbell): Rework to use FilePath throughout. |
- base::FilePath identifier_path = |
- base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(database_identifier)); |
- base::FilePath file_path = |
- file_path_base.Append(identifier_path).AppendASCII(".indexeddb.leveldb"); |
- |
- db = leveldb_factory->OpenLevelDB(file_path, comparator.get()); |
- |
- if (db) { |
- bool known = false; |
- bool ok = IsSchemaKnown(db.get(), &known); |
- if (!ok) { |
- LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as " |
- "failure to open"; |
- base::Histogram::FactoryGet( |
- "WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA); |
- db.reset(); |
- } else if (!known) { |
- LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it " |
- "as failure to open"; |
- base::Histogram::FactoryGet( |
- "WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA); |
- db.reset(); |
- } |
- } |
- |
- if (db) { |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_SUCCESS); |
- } else { |
- LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup"; |
- bool success = leveldb_factory->DestroyLevelDB(file_path); |
- if (!success) { |
- LOG(ERROR) << "IndexedDB backing store cleanup failed"; |
- base::Histogram::FactoryGet( |
- "WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED); |
- return scoped_refptr<IndexedDBBackingStore>(); |
- } |
- |
- LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening"; |
- db = leveldb_factory->OpenLevelDB(file_path, comparator.get()); |
- if (!db) { |
- LOG(ERROR) << "IndexedDB backing store reopen after recovery failed"; |
- base::Histogram::FactoryGet( |
- "WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED); |
- return scoped_refptr<IndexedDBBackingStore>(); |
- } |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS); |
- } |
- |
- if (!db) { |
- NOTREACHED(); |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR); |
- return scoped_refptr<IndexedDBBackingStore>(); |
- } |
- |
- return Create(file_identifier, db.Pass(), comparator.Pass()); |
-} |
- |
-scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
- const string16& identifier) { |
- DefaultLevelDBFactory leveldb_factory; |
- return IndexedDBBackingStore::OpenInMemory(identifier, &leveldb_factory); |
-} |
- |
-scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( |
- const string16& identifier, |
- LevelDBFactory* leveldb_factory) { |
- IDB_TRACE("IndexedDBBackingStore::open_in_memory"); |
- |
- scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
- scoped_ptr<LevelDBDatabase> db = |
- LevelDBDatabase::OpenInMemory(comparator.get()); |
- if (!db) { |
- LOG(ERROR) << "LevelDBDatabase::open_in_memory failed."; |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED); |
- return scoped_refptr<IndexedDBBackingStore>(); |
- } |
- base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus", |
- 1, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX, |
- INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1, |
- base::HistogramBase::kUmaTargetedHistogramFlag) |
- ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS); |
- |
- return Create(identifier, db.Pass(), comparator.Pass()); |
-} |
- |
-scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( |
- const string16& identifier, |
- scoped_ptr<LevelDBDatabase> db, |
- scoped_ptr<LevelDBComparator> comparator) { |
- // TODO(jsbell): Handle comparator name changes. |
- scoped_refptr<IndexedDBBackingStore> backing_store( |
- new IndexedDBBackingStore(identifier, db.Pass(), comparator.Pass())); |
- |
- if (!SetUpMetadata(backing_store->db_.get(), identifier)) |
- return scoped_refptr<IndexedDBBackingStore>(); |
- |
- return backing_store; |
-} |
- |
-std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() { |
- std::vector<string16> found_names; |
- const std::vector<char> start_key = |
- DatabaseNameKey::EncodeMinKeyForOrigin(identifier_); |
- const std::vector<char> stop_key = |
- DatabaseNameKey::EncodeStopKeyForOrigin(identifier_); |
- |
- DCHECK(found_names.empty()); |
- |
- scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
- for (it->Seek(LevelDBSlice(start_key)); |
- it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0; |
- it->Next()) { |
- const char* p = it->Key().begin(); |
- const char* limit = it->Key().end(); |
- |
- DatabaseNameKey database_name_key; |
- p = DatabaseNameKey::Decode(p, limit, &database_name_key); |
- DCHECK(p); |
- |
- found_names.push_back(database_name_key.database_name()); |
- } |
- return found_names; |
-} |
- |
-bool IndexedDBBackingStore::GetIDBDatabaseMetaData( |
- const string16& name, |
- IndexedDBDatabaseMetadata* metadata, |
- bool& found) { |
- const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name); |
- found = false; |
- |
- bool ok = GetInt(db_.get(), LevelDBSlice(key), metadata->id, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- if (!found) |
- return true; |
- |
- ok = GetString(db_.get(), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- metadata->id, DatabaseMetaDataKey::USER_VERSION)), |
- metadata->version, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- if (!found) { |
- INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- |
- ok = GetVarInt(db_.get(), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- metadata->id, DatabaseMetaDataKey::USER_INT_VERSION)), |
- metadata->int_version, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- if (!found) { |
- INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- |
- if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) |
- metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; |
- |
- ok = GetMaxObjectStoreId( |
- db_.get(), metadata->id, metadata->max_object_store_id); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBDatabase* db, |
- int64& new_id) { |
- scoped_refptr<LevelDBTransaction> transaction = |
- LevelDBTransaction::Create(db); |
- |
- new_id = -1; |
- int64 max_database_id = -1; |
- bool found = false; |
- bool ok = GetInt(transaction.get(), |
- LevelDBSlice(MaxDatabaseIdKey::Encode()), |
- max_database_id, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_NEW_DATABASE_ID); |
- return false; |
- } |
- if (!found) |
- max_database_id = 0; |
- |
- DCHECK_GE(max_database_id, 0); |
- |
- int64 database_id = max_database_id + 1; |
- PutInt( |
- transaction.get(), LevelDBSlice(MaxDatabaseIdKey::Encode()), database_id); |
- if (!transaction->Commit()) { |
- INTERNAL_WRITE_ERROR(GET_NEW_DATABASE_ID); |
- return false; |
- } |
- new_id = database_id; |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::CreateIDBDatabaseMetaData(const string16& name, |
- const string16& version, |
- int64 int_version, |
- int64& row_id) { |
- bool ok = GetNewDatabaseId(db_.get(), row_id); |
- if (!ok) |
- return false; |
- DCHECK_GE(row_id, 0); |
- |
- if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) |
- int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; |
- |
- scoped_refptr<LevelDBTransaction> transaction = |
- LevelDBTransaction::Create(db_.get()); |
- PutInt(transaction.get(), |
- LevelDBSlice(DatabaseNameKey::Encode(identifier_, name)), |
- row_id); |
- PutString(transaction.get(), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- row_id, DatabaseMetaDataKey::USER_VERSION)), |
- version); |
- PutVarInt(transaction.get(), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- row_id, DatabaseMetaDataKey::USER_INT_VERSION)), |
- int_version); |
- if (!transaction->Commit()) { |
- INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA); |
- return false; |
- } |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 row_id, |
- int64 int_version) { |
- if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) |
- int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION; |
- DCHECK_GE(int_version, 0) << "int_version was " << int_version; |
- PutVarInt(Transaction::LevelDBTransactionFrom(transaction), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- row_id, DatabaseMetaDataKey::USER_INT_VERSION)), |
- int_version); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::UpdateIDBDatabaseMetaData( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 row_id, |
- const string16& version) { |
- PutString(Transaction::LevelDBTransactionFrom(transaction), |
- LevelDBSlice(DatabaseMetaDataKey::Encode( |
- row_id, DatabaseMetaDataKey::USER_VERSION)), |
- version); |
- return true; |
-} |
- |
-static void DeleteRange(LevelDBTransaction* transaction, |
- const std::vector<char>& begin, |
- const std::vector<char>& end) { |
- scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); |
- for (it->Seek(LevelDBSlice(begin)); |
- it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(end)) < 0; |
- it->Next()) |
- transaction->Remove(it->Key()); |
-} |
- |
-bool IndexedDBBackingStore::DeleteDatabase(const string16& name) { |
- IDB_TRACE("IndexedDBBackingStore::delete_database"); |
- scoped_ptr<LevelDBWriteOnlyTransaction> transaction = |
- LevelDBWriteOnlyTransaction::Create(db_.get()); |
- |
- IndexedDBDatabaseMetadata metadata; |
- bool success = false; |
- bool ok = GetIDBDatabaseMetaData(name, &metadata, success); |
- if (!ok) |
- return false; |
- if (!success) |
- return true; |
- |
- const std::vector<char> start_key = DatabaseMetaDataKey::Encode( |
- metadata.id, DatabaseMetaDataKey::ORIGIN_NAME); |
- const std::vector<char> stop_key = DatabaseMetaDataKey::Encode( |
- metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME); |
- scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
- for (it->Seek(LevelDBSlice(start_key)); |
- it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0; |
- it->Next()) |
- transaction->Remove(it->Key()); |
- |
- const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name); |
- transaction->Remove(LevelDBSlice(key)); |
- |
- if (!transaction->Commit()) { |
- INTERNAL_WRITE_ERROR(DELETE_DATABASE); |
- return false; |
- } |
- return true; |
-} |
- |
-static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it, |
- const std::vector<char>& stop_key, |
- int64 object_store_id, |
- int64 meta_data_type) { |
- if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0) |
- return false; |
- |
- ObjectStoreMetaDataKey meta_data_key; |
- const char* p = ObjectStoreMetaDataKey::Decode( |
- it->Key().begin(), it->Key().end(), &meta_data_key); |
- DCHECK(p); |
- if (meta_data_key.ObjectStoreId() != object_store_id) |
- return false; |
- if (meta_data_key.MetaDataType() != meta_data_type) |
- return false; |
- return true; |
-} |
- |
-// TODO(jsbell): This should do some error handling rather than |
-// plowing ahead when bad data is encountered. |
-bool IndexedDBBackingStore::GetObjectStores( |
- int64 database_id, |
- IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) { |
- IDB_TRACE("IndexedDBBackingStore::get_object_stores"); |
- if (!KeyPrefix::IsValidDatabaseId(database_id)) |
- return false; |
- const std::vector<char> start_key = |
- ObjectStoreMetaDataKey::Encode(database_id, 1, 0); |
- const std::vector<char> stop_key = |
- ObjectStoreMetaDataKey::EncodeMaxKey(database_id); |
- |
- DCHECK(object_stores->empty()); |
- |
- scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
- it->Seek(LevelDBSlice(start_key)); |
- while (it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0) { |
- const char* p = it->Key().begin(); |
- const char* limit = it->Key().end(); |
- |
- ObjectStoreMetaDataKey meta_data_key; |
- p = ObjectStoreMetaDataKey::Decode(p, limit, &meta_data_key); |
- DCHECK(p); |
- if (meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- // Possible stale metadata, but don't fail the load. |
- it->Next(); |
- continue; |
- } |
- |
- int64 object_store_id = meta_data_key.ObjectStoreId(); |
- |
- // TODO(jsbell): Do this by direct key lookup rather than iteration, to |
- // simplify. |
- string16 object_store_name = |
- DecodeString(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); |
- if (!CheckObjectStoreAndMetaDataType(it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::KEY_PATH)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- IndexedDBKeyPath key_path = |
- DecodeIDBKeyPath(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); |
- if (!CheckObjectStoreAndMetaDataType( |
- it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::AUTO_INCREMENT)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- bool auto_increment = DecodeBool(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); // Is evicatble. |
- if (!CheckObjectStoreAndMetaDataType(it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::EVICTABLE)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- |
- it->Next(); // Last version. |
- if (!CheckObjectStoreAndMetaDataType( |
- it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::LAST_VERSION)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- |
- it->Next(); // Maximum index id allocated. |
- if (!CheckObjectStoreAndMetaDataType( |
- it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::MAX_INDEX_ID)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- int64 max_index_id = DecodeInt(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); // [optional] has key path (is not null) |
- if (CheckObjectStoreAndMetaDataType(it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::HAS_KEY_PATH)) { |
- bool has_key_path = DecodeBool(it->Value().begin(), it->Value().end()); |
- // This check accounts for two layers of legacy coding: |
- // (1) Initially, has_key_path was added to distinguish null vs. string. |
- // (2) Later, null vs. string vs. array was stored in the key_path itself. |
- // So this check is only relevant for string-type key_paths. |
- if (!has_key_path && |
- (key_path.type() == WebKit::WebIDBKeyPath::StringType && |
- !key_path.string().empty())) { |
- INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES); |
- break; |
- } |
- if (!has_key_path) |
- key_path = IndexedDBKeyPath(); |
- it->Next(); |
- } |
- |
- int64 key_generator_current_number = -1; |
- if (CheckObjectStoreAndMetaDataType( |
- it.get(), |
- stop_key, |
- object_store_id, |
- ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) { |
- key_generator_current_number = |
- DecodeInt(it->Value().begin(), it->Value().end()); |
- // TODO(jsbell): Return key_generator_current_number, cache in |
- // object store, and write lazily to backing store. For now, |
- // just assert that if it was written it was valid. |
- DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber); |
- it->Next(); |
- } |
- |
- IndexedDBObjectStoreMetadata metadata(object_store_name, |
- object_store_id, |
- key_path, |
- auto_increment, |
- max_index_id); |
- if (!GetIndexes(database_id, object_store_id, &metadata.indexes)) |
- return false; |
- (*object_stores)[object_store_id] = metadata; |
- } |
- return true; |
-} |
- |
-WARN_UNUSED_RESULT static bool SetMaxObjectStoreId( |
- LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id) { |
- const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode( |
- database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID); |
- int64 max_object_store_id = -1; |
- bool ok = GetMaxObjectStoreId( |
- transaction, max_object_store_id_key, max_object_store_id); |
- if (!ok) { |
- INTERNAL_READ_ERROR(SET_MAX_OBJECT_STORE_ID); |
- return false; |
- } |
- |
- if (object_store_id <= max_object_store_id) { |
- INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID); |
- return false; |
- } |
- PutInt(transaction, LevelDBSlice(max_object_store_id_key), object_store_id); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::CreateObjectStore( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const string16& name, |
- const IndexedDBKeyPath& key_path, |
- bool auto_increment) { |
- IDB_TRACE("IndexedDBBackingStore::create_object_store"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- if (!SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id)) |
- return false; |
- |
- const std::vector<char> name_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::NAME); |
- const std::vector<char> key_path_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH); |
- const std::vector<char> auto_increment_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT); |
- const std::vector<char> evictable_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE); |
- const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); |
- const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
- const std::vector<char> has_key_path_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH); |
- const std::vector<char> key_generator_current_number_key = |
- ObjectStoreMetaDataKey::Encode( |
- database_id, |
- object_store_id, |
- ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); |
- const std::vector<char> names_key = |
- ObjectStoreNamesKey::Encode(database_id, name); |
- |
- PutString(leveldb_transaction, LevelDBSlice(name_key), name); |
- PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path); |
- PutInt(leveldb_transaction, LevelDBSlice(auto_increment_key), auto_increment); |
- PutInt(leveldb_transaction, LevelDBSlice(evictable_key), false); |
- PutInt(leveldb_transaction, LevelDBSlice(last_version_key), 1); |
- PutInt(leveldb_transaction, LevelDBSlice(max_index_id_key), kMinimumIndexId); |
- PutBool( |
- leveldb_transaction, LevelDBSlice(has_key_path_key), !key_path.IsNull()); |
- PutInt(leveldb_transaction, |
- LevelDBSlice(key_generator_current_number_key), |
- kKeyGeneratorInitialNumber); |
- PutInt(leveldb_transaction, LevelDBSlice(names_key), object_store_id); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::DeleteObjectStore( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id) { |
- IDB_TRACE("IndexedDBBackingStore::delete_object_store"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- string16 object_store_name; |
- bool found = false; |
- bool ok = GetString( |
- leveldb_transaction, |
- LevelDBSlice(ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::NAME)), |
- object_store_name, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(DELETE_OBJECT_STORE); |
- return false; |
- } |
- if (!found) { |
- INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE); |
- return false; |
- } |
- |
- DeleteRange( |
- leveldb_transaction, |
- ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0), |
- ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id)); |
- |
- leveldb_transaction->Remove(LevelDBSlice( |
- ObjectStoreNamesKey::Encode(database_id, object_store_name))); |
- |
- DeleteRange(leveldb_transaction, |
- IndexFreeListKey::Encode(database_id, object_store_id, 0), |
- IndexFreeListKey::EncodeMaxKey(database_id, object_store_id)); |
- DeleteRange(leveldb_transaction, |
- IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0), |
- IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id)); |
- |
- return ClearObjectStore(transaction, database_id, object_store_id); |
-} |
- |
-bool IndexedDBBackingStore::GetRecord( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKey& key, |
- std::vector<char>& record) { |
- IDB_TRACE("IndexedDBBackingStore::get_record"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- const std::vector<char> leveldb_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
- std::vector<char> data; |
- |
- record.clear(); |
- |
- bool found = false; |
- bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_RECORD); |
- return false; |
- } |
- if (!found) |
- return true; |
- |
- int64 version; |
- const char* p = DecodeVarInt(&*data.begin(), &*data.rbegin() + 1, version); |
- if (!p) { |
- INTERNAL_READ_ERROR(GET_RECORD); |
- return false; |
- } |
- |
- record.insert(record.end(), p, static_cast<const char*>(&*data.rbegin()) + 1); |
- return true; |
-} |
- |
-WARN_UNUSED_RESULT static bool GetNewVersionNumber( |
- LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64& new_version_number) { |
- const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION); |
- |
- new_version_number = -1; |
- int64 last_version = -1; |
- bool found = false; |
- bool ok = |
- GetInt(transaction, LevelDBSlice(last_version_key), last_version, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_NEW_VERSION_NUMBER); |
- return false; |
- } |
- if (!found) |
- last_version = 0; |
- |
- DCHECK_GE(last_version, 0); |
- |
- int64 version = last_version + 1; |
- PutInt(transaction, LevelDBSlice(last_version_key), version); |
- |
- DCHECK(version > |
- last_version); // TODO(jsbell): Think about how we want to handle |
- // the overflow scenario. |
- |
- new_version_number = version; |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::PutRecord( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKey& key, |
- const std::vector<char>& value, |
- RecordIdentifier* record_identifier) { |
- IDB_TRACE("IndexedDBBackingStore::put_record"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- DCHECK(key.IsValid()); |
- |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- int64 version = -1; |
- bool ok = GetNewVersionNumber( |
- leveldb_transaction, database_id, object_store_id, version); |
- if (!ok) |
- return false; |
- DCHECK_GE(version, 0); |
- const std::vector<char> object_storedata_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
- |
- std::vector<char> v(EncodeVarInt(version)); |
- |
- v.insert(v.end(), value.begin(), value.end()); |
- |
- leveldb_transaction->Put(LevelDBSlice(object_storedata_key), v); |
- |
- const std::vector<char> exists_entry_key = |
- ExistsEntryKey::Encode(database_id, object_store_id, key); |
- leveldb_transaction->Put(LevelDBSlice(exists_entry_key), EncodeInt(version)); |
- |
- record_identifier->Reset(EncodeIDBKey(key), version); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::ClearObjectStore( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id) { |
- IDB_TRACE("IndexedDBBackingStore::clear_object_store"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- const std::vector<char> start_key = |
- KeyPrefix(database_id, object_store_id).Encode(); |
- const std::vector<char> stop_key = |
- KeyPrefix(database_id, object_store_id + 1).Encode(); |
- |
- DeleteRange(leveldb_transaction, start_key, stop_key); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::DeleteRecord( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const RecordIdentifier& record_identifier) { |
- IDB_TRACE("IndexedDBBackingStore::delete_record"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- const std::vector<char> object_store_data_key = ObjectStoreDataKey::Encode( |
- database_id, object_store_id, record_identifier.primary_key()); |
- leveldb_transaction->Remove(LevelDBSlice(object_store_data_key)); |
- |
- const std::vector<char> exists_entry_key = ExistsEntryKey::Encode( |
- database_id, object_store_id, record_identifier.primary_key()); |
- leveldb_transaction->Remove(LevelDBSlice(exists_entry_key)); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64& key_generator_current_number) { |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- const std::vector<char> key_generator_current_number_key = |
- ObjectStoreMetaDataKey::Encode( |
- database_id, |
- object_store_id, |
- ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); |
- |
- key_generator_current_number = -1; |
- std::vector<char> data; |
- |
- bool found = false; |
- bool ok = leveldb_transaction->Get( |
- LevelDBSlice(key_generator_current_number_key), data, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER); |
- return false; |
- } |
- if (found) { |
- key_generator_current_number = DecodeInt(data.begin(), data.end()); |
- } else { |
- // Previously, the key generator state was not stored explicitly |
- // but derived from the maximum numeric key present in existing |
- // data. This violates the spec as the data may be cleared but the |
- // key generator state must be preserved. |
- // TODO(jsbell): Fix this for all stores on database open? |
- const std::vector<char> start_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); |
- const std::vector<char> stop_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); |
- |
- scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); |
- int64 max_numeric_key = 0; |
- |
- for (it->Seek(LevelDBSlice(start_key)); |
- it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0; |
- it->Next()) { |
- const char* p = it->Key().begin(); |
- const char* limit = it->Key().end(); |
- |
- ObjectStoreDataKey data_key; |
- p = ObjectStoreDataKey::Decode(p, limit, &data_key); |
- DCHECK(p); |
- |
- scoped_ptr<IndexedDBKey> user_key = data_key.user_key(); |
- if (user_key->type() == WebKit::WebIDBKey::NumberType) { |
- int64 n = static_cast<int64>(user_key->number()); |
- if (n > max_numeric_key) |
- max_numeric_key = n; |
- } |
- } |
- |
- key_generator_current_number = max_numeric_key + 1; |
- } |
- |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 new_number, |
- bool check_current) { |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- if (check_current) { |
- int64 current_number; |
- bool ok = GetKeyGeneratorCurrentNumber( |
- transaction, database_id, object_store_id, current_number); |
- if (!ok) |
- return false; |
- if (new_number <= current_number) |
- return true; |
- } |
- |
- const std::vector<char> key_generator_current_number_key = |
- ObjectStoreMetaDataKey::Encode( |
- database_id, |
- object_store_id, |
- ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER); |
- PutInt(leveldb_transaction, |
- LevelDBSlice(key_generator_current_number_key), |
- new_number); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::KeyExistsInObjectStore( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKey& key, |
- RecordIdentifier* found_record_identifier, |
- bool& found) { |
- IDB_TRACE("IndexedDBBackingStore::key_exists_in_object_store"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- found = false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- const std::vector<char> leveldb_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, key); |
- std::vector<char> data; |
- |
- bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE); |
- return false; |
- } |
- if (!found) |
- return true; |
- |
- int64 version; |
- if (DecodeVarInt(&*data.begin(), &*data.rbegin() + 1, version) == 0) |
- return false; |
- |
- found_record_identifier->Reset(EncodeIDBKey(key), version); |
- return true; |
-} |
- |
-static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, |
- const std::vector<char>& stop_key, |
- int64 index_id, |
- unsigned char meta_data_type) { |
- if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0) |
- return false; |
- |
- IndexMetaDataKey meta_data_key; |
- const char* p = IndexMetaDataKey::Decode( |
- it->Key().begin(), it->Key().end(), &meta_data_key); |
- DCHECK(p); |
- if (meta_data_key.IndexId() != index_id) |
- return false; |
- if (meta_data_key.meta_data_type() != meta_data_type) |
- return false; |
- return true; |
-} |
- |
-// TODO(jsbell): This should do some error handling rather than plowing ahead |
-// when bad |
-// data is encountered. |
-bool IndexedDBBackingStore::GetIndexes( |
- int64 database_id, |
- int64 object_store_id, |
- IndexedDBObjectStoreMetadata::IndexMap* indexes) { |
- IDB_TRACE("IndexedDBBackingStore::get_indexes"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id)) |
- return false; |
- const std::vector<char> start_key = |
- IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0); |
- const std::vector<char> stop_key = |
- IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0); |
- |
- DCHECK(indexes->empty()); |
- |
- scoped_ptr<LevelDBIterator> it = db_->CreateIterator(); |
- it->Seek(LevelDBSlice(start_key)); |
- while (it->IsValid() && |
- CompareKeys(LevelDBSlice(it->Key()), LevelDBSlice(stop_key)) < 0) { |
- const char* p = it->Key().begin(); |
- const char* limit = it->Key().end(); |
- |
- IndexMetaDataKey meta_data_key; |
- p = IndexMetaDataKey::Decode(p, limit, &meta_data_key); |
- DCHECK(p); |
- if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) { |
- INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); |
- // Possible stale metadata due to http://webkit.org/b/85557 but don't fail |
- // the load. |
- it->Next(); |
- continue; |
- } |
- |
- // TODO(jsbell): Do this by direct key lookup rather than iteration, to |
- // simplify. |
- int64 index_id = meta_data_key.IndexId(); |
- string16 index_name = DecodeString(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); // unique flag |
- if (!CheckIndexAndMetaDataKey( |
- it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); |
- break; |
- } |
- bool index_unique = DecodeBool(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); // key_path |
- if (!CheckIndexAndMetaDataKey( |
- it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) { |
- INTERNAL_CONSISTENCY_ERROR(GET_INDEXES); |
- break; |
- } |
- IndexedDBKeyPath key_path = |
- DecodeIDBKeyPath(it->Value().begin(), it->Value().end()); |
- |
- it->Next(); // [optional] multi_entry flag |
- bool index_multi_entry = false; |
- if (CheckIndexAndMetaDataKey( |
- it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) { |
- index_multi_entry = DecodeBool(it->Value().begin(), it->Value().end()); |
- it->Next(); |
- } |
- |
- (*indexes)[index_id] = IndexedDBIndexMetadata( |
- index_name, index_id, key_path, index_unique, index_multi_entry); |
- } |
- return true; |
-} |
- |
-WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- int64 max_index_id = -1; |
- const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode( |
- database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID); |
- bool found = false; |
- bool ok = |
- GetInt(transaction, LevelDBSlice(max_index_id_key), max_index_id, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(SET_MAX_INDEX_ID); |
- return false; |
- } |
- if (!found) |
- max_index_id = kMinimumIndexId; |
- |
- if (index_id <= max_index_id) { |
- INTERNAL_CONSISTENCY_ERROR(SET_MAX_INDEX_ID); |
- return false; |
- } |
- |
- PutInt(transaction, LevelDBSlice(max_index_id_key), index_id); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::CreateIndex( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const string16& name, |
- const IndexedDBKeyPath& key_path, |
- bool is_unique, |
- bool is_multi_entry) { |
- IDB_TRACE("IndexedDBBackingStore::create_index"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- if (!SetMaxIndexId( |
- leveldb_transaction, database_id, object_store_id, index_id)) |
- return false; |
- |
- const std::vector<char> name_key = IndexMetaDataKey::Encode( |
- database_id, object_store_id, index_id, IndexMetaDataKey::NAME); |
- const std::vector<char> unique_key = IndexMetaDataKey::Encode( |
- database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE); |
- const std::vector<char> key_path_key = IndexMetaDataKey::Encode( |
- database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH); |
- const std::vector<char> multi_entry_key = IndexMetaDataKey::Encode( |
- database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY); |
- |
- PutString(leveldb_transaction, LevelDBSlice(name_key), name); |
- PutBool(leveldb_transaction, LevelDBSlice(unique_key), is_unique); |
- PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path); |
- PutBool(leveldb_transaction, LevelDBSlice(multi_entry_key), is_multi_entry); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::DeleteIndex( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- IDB_TRACE("IndexedDBBackingStore::delete_index"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- |
- const std::vector<char> index_meta_data_start = |
- IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0); |
- const std::vector<char> index_meta_data_end = |
- IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
- DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end); |
- |
- const std::vector<char> index_data_start = |
- IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); |
- const std::vector<char> index_data_end = |
- IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
- DeleteRange(leveldb_transaction, index_data_start, index_data_end); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::PutIndexDataForRecord( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKey& key, |
- const RecordIdentifier& record_identifier) { |
- IDB_TRACE("IndexedDBBackingStore::put_index_data_for_record"); |
- DCHECK(key.IsValid()); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- const std::vector<char> index_data_key = |
- IndexDataKey::Encode(database_id, |
- object_store_id, |
- index_id, |
- EncodeIDBKey(key), |
- record_identifier.primary_key()); |
- |
- std::vector<char> data(EncodeVarInt(record_identifier.version())); |
- const std::vector<char>& primary_key = record_identifier.primary_key(); |
- data.insert(data.end(), primary_key.begin(), primary_key.end()); |
- |
- leveldb_transaction->Put(LevelDBSlice(index_data_key), data); |
- return true; |
-} |
- |
-static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, |
- const std::vector<char>& target, |
- std::vector<char>& found_key) { |
- scoped_ptr<LevelDBIterator> it = transaction->CreateIterator(); |
- it->Seek(LevelDBSlice(target)); |
- |
- if (!it->IsValid()) { |
- it->SeekToLast(); |
- if (!it->IsValid()) |
- return false; |
- } |
- |
- while (CompareIndexKeys(LevelDBSlice(it->Key()), LevelDBSlice(target)) > 0) { |
- it->Prev(); |
- if (!it->IsValid()) |
- return false; |
- } |
- |
- do { |
- found_key.assign(it->Key().begin(), it->Key().end()); |
- |
- // There can be several index keys that compare equal. We want the last one. |
- it->Next(); |
- } while (it->IsValid() && !CompareIndexKeys(it->Key(), LevelDBSlice(target))); |
- |
- return true; |
-} |
- |
-static bool VersionExists(LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 version, |
- const std::vector<char>& encoded_primary_key, |
- bool& exists) { |
- const std::vector<char> key = |
- ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key); |
- std::vector<char> data; |
- |
- bool ok = transaction->Get(LevelDBSlice(key), data, exists); |
- if (!ok) { |
- INTERNAL_READ_ERROR(VERSION_EXISTS); |
- return false; |
- } |
- if (!exists) |
- return true; |
- |
- exists = (DecodeInt(data.begin(), data.end()) == version); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::FindKeyInIndex( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKey& key, |
- std::vector<char>& found_encoded_primary_key, |
- bool& found) { |
- IDB_TRACE("IndexedDBBackingStore::find_key_in_index"); |
- DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id)); |
- |
- DCHECK(found_encoded_primary_key.empty()); |
- found = false; |
- |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- const std::vector<char> leveldb_key = |
- IndexDataKey::Encode(database_id, object_store_id, index_id, key); |
- scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator(); |
- it->Seek(LevelDBSlice(leveldb_key)); |
- |
- for (;;) { |
- if (!it->IsValid()) |
- return true; |
- if (CompareIndexKeys(it->Key(), LevelDBSlice(leveldb_key)) > 0) |
- return true; |
- |
- int64 version; |
- const char* p = |
- DecodeVarInt(it->Value().begin(), it->Value().end(), version); |
- if (!p) { |
- INTERNAL_READ_ERROR(FIND_KEY_IN_INDEX); |
- return false; |
- } |
- found_encoded_primary_key.insert( |
- found_encoded_primary_key.end(), p, it->Value().end()); |
- |
- bool exists = false; |
- bool ok = VersionExists(leveldb_transaction, |
- database_id, |
- object_store_id, |
- version, |
- found_encoded_primary_key, |
- exists); |
- if (!ok) |
- return false; |
- if (!exists) { |
- // Delete stale index data entry and continue. |
- leveldb_transaction->Remove(it->Key()); |
- it->Next(); |
- continue; |
- } |
- found = true; |
- return true; |
- } |
-} |
- |
-bool IndexedDBBackingStore::GetPrimaryKeyViaIndex( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKey& key, |
- scoped_ptr<IndexedDBKey>* primary_key) { |
- IDB_TRACE("IndexedDBBackingStore::get_primary_key_via_index"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- |
- bool found = false; |
- std::vector<char> found_encoded_primary_key; |
- bool ok = FindKeyInIndex(transaction, |
- database_id, |
- object_store_id, |
- index_id, |
- key, |
- found_encoded_primary_key, |
- found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX); |
- return false; |
- } |
- if (found) { |
- DecodeIDBKey(&*found_encoded_primary_key.begin(), |
- &*found_encoded_primary_key.rbegin() + 1, |
- primary_key); |
- return true; |
- } |
- |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::KeyExistsInIndex( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKey& index_key, |
- scoped_ptr<IndexedDBKey>* found_primary_key, |
- bool& exists) { |
- IDB_TRACE("IndexedDBBackingStore::key_exists_in_index"); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- |
- exists = false; |
- std::vector<char> found_encoded_primary_key; |
- bool ok = FindKeyInIndex(transaction, |
- database_id, |
- object_store_id, |
- index_id, |
- index_key, |
- found_encoded_primary_key, |
- exists); |
- if (!ok) { |
- INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX); |
- return false; |
- } |
- if (!exists) |
- return true; |
- |
- DecodeIDBKey(&*found_encoded_primary_key.begin(), |
- &*found_encoded_primary_key.rbegin() + 1, |
- found_primary_key); |
- return true; |
-} |
- |
-IndexedDBBackingStore::Cursor::Cursor( |
- const IndexedDBBackingStore::Cursor* other) |
- : transaction_(other->transaction_), |
- cursor_options_(other->cursor_options_), |
- current_key_(new IndexedDBKey(*other->current_key_)) { |
- if (other->iterator_) { |
- iterator_ = transaction_->CreateIterator(); |
- |
- if (other->iterator_->IsValid()) { |
- iterator_->Seek(other->iterator_->Key()); |
- DCHECK(iterator_->IsValid()); |
- } |
- } |
-} |
- |
-IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction, |
- const CursorOptions& cursor_options) |
- : transaction_(transaction), cursor_options_(cursor_options) {} |
-IndexedDBBackingStore::Cursor::~Cursor() {} |
- |
-bool IndexedDBBackingStore::Cursor::FirstSeek() { |
- iterator_ = transaction_->CreateIterator(); |
- if (cursor_options_.forward) |
- iterator_->Seek(LevelDBSlice(cursor_options_.low_key)); |
- else |
- iterator_->Seek(LevelDBSlice(cursor_options_.high_key)); |
- |
- return ContinueFunction(0, READY); |
-} |
- |
-bool IndexedDBBackingStore::Cursor::Advance(unsigned long count) { |
- while (count--) { |
- if (!ContinueFunction()) |
- return false; |
- } |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::Cursor::ContinueFunction(const IndexedDBKey* key, |
- IteratorState next_state) { |
- // TODO(alecflett): avoid a copy here? |
- IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey(); |
- |
- bool first_iteration = true; |
- |
- // When iterating with PrevNoDuplicate, spec requires that the |
- // value we yield for each key is the first duplicate in forwards |
- // order. |
- IndexedDBKey last_duplicate_key; |
- |
- bool forward = cursor_options_.forward; |
- |
- for (;;) { |
- if (next_state == SEEK) { |
- // TODO(jsbell): Optimize seeking for reverse cursors as well. |
- if (first_iteration && key && key->IsValid() && forward) { |
- iterator_->Seek(LevelDBSlice(EncodeKey(*key))); |
- first_iteration = false; |
- } else if (forward) { |
- iterator_->Next(); |
- } else { |
- iterator_->Prev(); |
- } |
- } else { |
- next_state = SEEK; // for subsequent iterations |
- } |
- |
- if (!iterator_->IsValid()) { |
- if (!forward && last_duplicate_key.IsValid()) { |
- // We need to walk forward because we hit the end of |
- // the data. |
- forward = true; |
- continue; |
- } |
- |
- return false; |
- } |
- |
- if (IsPastBounds()) { |
- if (!forward && last_duplicate_key.IsValid()) { |
- // We need to walk forward because now we're beyond the |
- // bounds defined by the cursor. |
- forward = true; |
- continue; |
- } |
- |
- return false; |
- } |
- |
- if (!HaveEnteredRange()) |
- continue; |
- |
- // The row may not load because there's a stale entry in the |
- // index. This is not fatal. |
- if (!LoadCurrentRow()) |
- continue; |
- |
- if (key && key->IsValid()) { |
- if (forward) { |
- if (current_key_->IsLessThan(*key)) |
- continue; |
- } else { |
- if (key->IsLessThan(*current_key_)) |
- continue; |
- } |
- } |
- |
- if (cursor_options_.unique) { |
- if (previous_key.IsValid() && current_key_->IsEqual(previous_key)) { |
- // We should never be able to walk forward all the way |
- // to the previous key. |
- DCHECK(!last_duplicate_key.IsValid()); |
- continue; |
- } |
- |
- if (!forward) { |
- if (!last_duplicate_key.IsValid()) { |
- last_duplicate_key = *current_key_; |
- continue; |
- } |
- |
- // We need to walk forward because we hit the boundary |
- // between key ranges. |
- if (!last_duplicate_key.IsEqual(*current_key_)) { |
- forward = true; |
- continue; |
- } |
- |
- continue; |
- } |
- } |
- break; |
- } |
- |
- DCHECK(!last_duplicate_key.IsValid() || |
- (forward && last_duplicate_key.IsEqual(*current_key_))); |
- return true; |
-} |
- |
-bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const { |
- if (cursor_options_.forward) { |
- int compare = CompareIndexKeys(iterator_->Key(), |
- LevelDBSlice(cursor_options_.low_key)); |
- if (cursor_options_.low_open) { |
- return compare > 0; |
- } |
- return compare >= 0; |
- } |
- int compare = CompareIndexKeys(iterator_->Key(), |
- LevelDBSlice(cursor_options_.high_key)); |
- if (cursor_options_.high_open) { |
- return compare < 0; |
- } |
- return compare <= 0; |
-} |
- |
-bool IndexedDBBackingStore::Cursor::IsPastBounds() const { |
- if (cursor_options_.forward) { |
- int compare = CompareIndexKeys(iterator_->Key(), |
- LevelDBSlice(cursor_options_.high_key)); |
- if (cursor_options_.high_open) { |
- return compare >= 0; |
- } |
- return compare > 0; |
- } |
- int compare = |
- CompareIndexKeys(iterator_->Key(), LevelDBSlice(cursor_options_.low_key)); |
- if (cursor_options_.low_open) { |
- return compare <= 0; |
- } |
- return compare < 0; |
-} |
- |
-const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const { |
- return *current_key_; |
-} |
- |
-const IndexedDBBackingStore::RecordIdentifier& |
-IndexedDBBackingStore::Cursor::record_identifier() const { |
- return record_identifier_; |
-} |
- |
-class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
- public: |
- ObjectStoreKeyCursorImpl( |
- LevelDBTransaction* transaction, |
- const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
- : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} |
- |
- virtual Cursor* Clone() OVERRIDE { |
- return new ObjectStoreKeyCursorImpl(this); |
- } |
- |
- // IndexedDBBackingStore::Cursor |
- virtual std::vector<char>* Value() OVERRIDE { |
- NOTREACHED(); |
- return NULL; |
- } |
- virtual bool LoadCurrentRow() OVERRIDE; |
- |
- protected: |
- virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE { |
- return ObjectStoreDataKey::Encode( |
- cursor_options_.database_id, cursor_options_.object_store_id, key); |
- } |
- |
- private: |
- explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other) |
- : IndexedDBBackingStore::Cursor(other) {} |
-}; |
- |
-bool ObjectStoreKeyCursorImpl::LoadCurrentRow() { |
- const char* key_position = iterator_->Key().begin(); |
- const char* key_limit = iterator_->Key().end(); |
- |
- ObjectStoreDataKey object_store_data_key; |
- key_position = ObjectStoreDataKey::Decode( |
- key_position, key_limit, &object_store_data_key); |
- if (!key_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- current_key_ = object_store_data_key.user_key(); |
- |
- int64 version; |
- const char* value_position = DecodeVarInt( |
- iterator_->Value().begin(), iterator_->Value().end(), version); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- // TODO(jsbell): This re-encodes what was just decoded; try and optimize. |
- record_identifier_.Reset(EncodeIDBKey(*current_key_), version); |
- |
- return true; |
-} |
- |
-class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor { |
- public: |
- ObjectStoreCursorImpl( |
- LevelDBTransaction* transaction, |
- const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
- : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} |
- |
- virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); } |
- |
- // IndexedDBBackingStore::Cursor |
- virtual std::vector<char>* Value() OVERRIDE { return ¤t_value_; } |
- virtual bool LoadCurrentRow() OVERRIDE; |
- |
- protected: |
- virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE { |
- return ObjectStoreDataKey::Encode( |
- cursor_options_.database_id, cursor_options_.object_store_id, key); |
- } |
- |
- private: |
- explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) |
- : IndexedDBBackingStore::Cursor(other), |
- current_value_(other->current_value_) {} |
- |
- std::vector<char> current_value_; |
-}; |
- |
-bool ObjectStoreCursorImpl::LoadCurrentRow() { |
- const char* key_position = iterator_->Key().begin(); |
- const char* key_limit = iterator_->Key().end(); |
- |
- ObjectStoreDataKey object_store_data_key; |
- key_position = ObjectStoreDataKey::Decode( |
- key_position, key_limit, &object_store_data_key); |
- if (!key_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- current_key_ = object_store_data_key.user_key(); |
- |
- int64 version; |
- const char* value_position = DecodeVarInt( |
- iterator_->Value().begin(), iterator_->Value().end(), version); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- // TODO(jsbell): This re-encodes what was just decoded; try and optimize. |
- record_identifier_.Reset(EncodeIDBKey(*current_key_), version); |
- |
- std::vector<char> value; |
- value.insert(value.end(), value_position, iterator_->Value().end()); |
- current_value_.swap(value); |
- return true; |
-} |
- |
-class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor { |
- public: |
- IndexKeyCursorImpl( |
- LevelDBTransaction* transaction, |
- const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
- : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} |
- |
- virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); } |
- |
- // IndexedDBBackingStore::Cursor |
- virtual std::vector<char>* Value() OVERRIDE { |
- NOTREACHED(); |
- return NULL; |
- } |
- virtual const IndexedDBKey& primary_key() const OVERRIDE { |
- return *primary_key_; |
- } |
- virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() |
- const { |
- NOTREACHED(); |
- return record_identifier_; |
- } |
- virtual bool LoadCurrentRow() OVERRIDE; |
- |
- protected: |
- virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE { |
- return IndexDataKey::Encode(cursor_options_.database_id, |
- cursor_options_.object_store_id, |
- cursor_options_.index_id, |
- key); |
- } |
- |
- private: |
- explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other) |
- : IndexedDBBackingStore::Cursor(other), |
- primary_key_(new IndexedDBKey(*other->primary_key_)) {} |
- |
- scoped_ptr<IndexedDBKey> primary_key_; |
-}; |
- |
-bool IndexKeyCursorImpl::LoadCurrentRow() { |
- const char* key_position = iterator_->Key().begin(); |
- const char* key_limit = iterator_->Key().end(); |
- |
- IndexDataKey index_data_key; |
- key_position = IndexDataKey::Decode(key_position, key_limit, &index_data_key); |
- |
- current_key_ = index_data_key.user_key(); |
- DCHECK(current_key_); |
- |
- int64 index_data_version; |
- const char* value_position = DecodeVarInt( |
- iterator_->Value().begin(), iterator_->Value().end(), index_data_version); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- value_position = |
- DecodeIDBKey(value_position, iterator_->Value().end(), &primary_key_); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- std::vector<char> primary_leveldb_key = |
- ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), |
- index_data_key.ObjectStoreId(), |
- *primary_key_); |
- |
- std::vector<char> result; |
- bool found = false; |
- bool ok = transaction_->Get(LevelDBSlice(primary_leveldb_key), result, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- if (!found) { |
- transaction_->Remove(iterator_->Key()); |
- return false; |
- } |
- |
- int64 object_store_data_version; |
- const char* t = DecodeVarInt( |
- &*result.begin(), &*result.rbegin() + 1, object_store_data_version); |
- if (!t) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- if (object_store_data_version != index_data_version) { |
- transaction_->Remove(iterator_->Key()); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-class IndexCursorImpl : public IndexedDBBackingStore::Cursor { |
- public: |
- IndexCursorImpl( |
- LevelDBTransaction* transaction, |
- const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) |
- : IndexedDBBackingStore::Cursor(transaction, cursor_options) {} |
- |
- virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); } |
- |
- // IndexedDBBackingStore::Cursor |
- virtual std::vector<char>* Value() OVERRIDE { return ¤t_value_; } |
- virtual const IndexedDBKey& primary_key() const OVERRIDE { |
- return *primary_key_; |
- } |
- virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier() |
- const { |
- NOTREACHED(); |
- return record_identifier_; |
- } |
- virtual bool LoadCurrentRow() OVERRIDE; |
- |
- protected: |
- virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE { |
- return IndexDataKey::Encode(cursor_options_.database_id, |
- cursor_options_.object_store_id, |
- cursor_options_.index_id, |
- key); |
- } |
- |
- private: |
- explicit IndexCursorImpl(const IndexCursorImpl* other) |
- : IndexedDBBackingStore::Cursor(other), |
- primary_key_(new IndexedDBKey(*other->primary_key_)), |
- current_value_(other->current_value_), |
- primary_leveldb_key_(other->primary_leveldb_key_) {} |
- |
- scoped_ptr<IndexedDBKey> primary_key_; |
- std::vector<char> current_value_; |
- std::vector<char> primary_leveldb_key_; |
-}; |
- |
-bool IndexCursorImpl::LoadCurrentRow() { |
- const char* key_position = iterator_->Key().begin(); |
- const char* key_limit = iterator_->Key().end(); |
- |
- IndexDataKey index_data_key; |
- key_position = IndexDataKey::Decode(key_position, key_limit, &index_data_key); |
- |
- current_key_ = index_data_key.user_key(); |
- DCHECK(current_key_); |
- |
- const char* value_position = iterator_->Value().begin(); |
- const char* value_limit = iterator_->Value().end(); |
- |
- int64 index_data_version; |
- value_position = |
- DecodeVarInt(value_position, value_limit, index_data_version); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- value_position = DecodeIDBKey(value_position, value_limit, &primary_key_); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- primary_leveldb_key_ = |
- ObjectStoreDataKey::Encode(index_data_key.DatabaseId(), |
- index_data_key.ObjectStoreId(), |
- *primary_key_); |
- |
- std::vector<char> result; |
- bool found = false; |
- bool ok = |
- transaction_->Get(LevelDBSlice(primary_leveldb_key_), result, found); |
- if (!ok) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- if (!found) { |
- transaction_->Remove(iterator_->Key()); |
- return false; |
- } |
- |
- int64 object_store_data_version; |
- value_position = DecodeVarInt( |
- &*result.begin(), &*result.rbegin() + 1, object_store_data_version); |
- if (!value_position) { |
- INTERNAL_READ_ERROR(LOAD_CURRENT_ROW); |
- return false; |
- } |
- |
- if (object_store_data_version != index_data_version) { |
- transaction_->Remove(iterator_->Key()); |
- return false; |
- } |
- |
- // TODO(jsbell): Make value_position an iterator. |
- std::vector<char> value; |
- value.insert(value.end(), |
- value_position, |
- static_cast<const char*>(&*result.rbegin()) + 1); |
- current_value_.swap(value); |
- return true; |
-} |
- |
-bool ObjectStoreCursorOptions( |
- LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction, |
- IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) { |
- cursor_options.database_id = database_id; |
- cursor_options.object_store_id = object_store_id; |
- |
- bool lower_bound = range.lower().IsValid(); |
- bool upper_bound = range.upper().IsValid(); |
- cursor_options.forward = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || |
- direction == indexed_db::CURSOR_NEXT); |
- cursor_options.unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || |
- direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); |
- |
- if (!lower_bound) { |
- cursor_options.low_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey()); |
- cursor_options.low_open = true; // Not included. |
- } else { |
- cursor_options.low_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower()); |
- cursor_options.low_open = range.lowerOpen(); |
- } |
- |
- if (!upper_bound) { |
- cursor_options.high_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey()); |
- |
- if (cursor_options.forward) { |
- cursor_options.high_open = true; // Not included. |
- } else { |
- // We need a key that exists. |
- if (!FindGreatestKeyLessThanOrEqual( |
- transaction, cursor_options.high_key, cursor_options.high_key)) |
- return false; |
- cursor_options.high_open = false; |
- } |
- } else { |
- cursor_options.high_key = |
- ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper()); |
- cursor_options.high_open = range.upperOpen(); |
- |
- if (!cursor_options.forward) { |
- // For reverse cursors, we need a key that exists. |
- std::vector<char> found_high_key; |
- if (!FindGreatestKeyLessThanOrEqual( |
- transaction, cursor_options.high_key, found_high_key)) |
- return false; |
- |
- // If the target key should not be included, but we end up with a smaller |
- // key, we should include that. |
- if (cursor_options.high_open && |
- CompareIndexKeys(LevelDBSlice(found_high_key), |
- LevelDBSlice(cursor_options.high_key)) < |
- 0) |
- cursor_options.high_open = false; |
- |
- cursor_options.high_key = found_high_key; |
- } |
- } |
- |
- return true; |
-} |
- |
-bool IndexCursorOptions( |
- LevelDBTransaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction, |
- IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) { |
- DCHECK(transaction); |
- if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) |
- return false; |
- |
- cursor_options.database_id = database_id; |
- cursor_options.object_store_id = object_store_id; |
- cursor_options.index_id = index_id; |
- |
- bool lower_bound = range.lower().IsValid(); |
- bool upper_bound = range.upper().IsValid(); |
- cursor_options.forward = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || |
- direction == indexed_db::CURSOR_NEXT); |
- cursor_options.unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE || |
- direction == indexed_db::CURSOR_PREV_NO_DUPLICATE); |
- |
- if (!lower_bound) { |
- cursor_options.low_key = |
- IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id); |
- cursor_options.low_open = false; // Included. |
- } else { |
- cursor_options.low_key = IndexDataKey::Encode( |
- database_id, object_store_id, index_id, range.lower()); |
- cursor_options.low_open = range.lowerOpen(); |
- } |
- |
- if (!upper_bound) { |
- cursor_options.high_key = |
- IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id); |
- cursor_options.high_open = false; // Included. |
- |
- if (!cursor_options.forward) { // We need a key that exists. |
- if (!FindGreatestKeyLessThanOrEqual( |
- transaction, cursor_options.high_key, cursor_options.high_key)) |
- return false; |
- cursor_options.high_open = false; |
- } |
- } else { |
- cursor_options.high_key = IndexDataKey::Encode( |
- database_id, object_store_id, index_id, range.upper()); |
- cursor_options.high_open = range.upperOpen(); |
- |
- std::vector<char> found_high_key; |
- if (!FindGreatestKeyLessThanOrEqual( |
- transaction, |
- cursor_options.high_key, |
- found_high_key)) // Seek to the *last* key in the set of non-unique |
- // keys. |
- return false; |
- |
- // If the target key should not be included, but we end up with a smaller |
- // key, we should include that. |
- if (cursor_options.high_open && |
- CompareIndexKeys(LevelDBSlice(found_high_key), |
- LevelDBSlice(cursor_options.high_key)) < |
- 0) |
- cursor_options.high_open = false; |
- |
- cursor_options.high_key = found_high_key; |
- } |
- |
- return true; |
-} |
- |
-scoped_ptr<IndexedDBBackingStore::Cursor> |
-IndexedDBBackingStore::OpenObjectStoreCursor( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction) { |
- IDB_TRACE("IndexedDBBackingStore::open_object_store_cursor"); |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
- if (!ObjectStoreCursorOptions(leveldb_transaction, |
- database_id, |
- object_store_id, |
- range, |
- direction, |
- cursor_options)) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- scoped_ptr<ObjectStoreCursorImpl> cursor( |
- new ObjectStoreCursorImpl(leveldb_transaction, cursor_options)); |
- if (!cursor->FirstSeek()) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- |
- return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
-} |
- |
-scoped_ptr<IndexedDBBackingStore::Cursor> |
-IndexedDBBackingStore::OpenObjectStoreKeyCursor( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction) { |
- IDB_TRACE("IndexedDBBackingStore::open_object_store_key_cursor"); |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
- if (!ObjectStoreCursorOptions(leveldb_transaction, |
- database_id, |
- object_store_id, |
- range, |
- direction, |
- cursor_options)) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- scoped_ptr<ObjectStoreKeyCursorImpl> cursor( |
- new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options)); |
- if (!cursor->FirstSeek()) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- |
- return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
-} |
- |
-scoped_ptr<IndexedDBBackingStore::Cursor> |
-IndexedDBBackingStore::OpenIndexKeyCursor( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction) { |
- IDB_TRACE("IndexedDBBackingStore::open_index_key_cursor"); |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
- if (!IndexCursorOptions(leveldb_transaction, |
- database_id, |
- object_store_id, |
- index_id, |
- range, |
- direction, |
- cursor_options)) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- scoped_ptr<IndexKeyCursorImpl> cursor( |
- new IndexKeyCursorImpl(leveldb_transaction, cursor_options)); |
- if (!cursor->FirstSeek()) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- |
- return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
-} |
- |
-scoped_ptr<IndexedDBBackingStore::Cursor> |
-IndexedDBBackingStore::OpenIndexCursor( |
- IndexedDBBackingStore::Transaction* transaction, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKeyRange& range, |
- indexed_db::CursorDirection direction) { |
- IDB_TRACE("IndexedDBBackingStore::open_index_cursor"); |
- LevelDBTransaction* leveldb_transaction = |
- IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction); |
- IndexedDBBackingStore::Cursor::CursorOptions cursor_options; |
- if (!IndexCursorOptions(leveldb_transaction, |
- database_id, |
- object_store_id, |
- index_id, |
- range, |
- direction, |
- cursor_options)) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- scoped_ptr<IndexCursorImpl> cursor( |
- new IndexCursorImpl(leveldb_transaction, cursor_options)); |
- if (!cursor->FirstSeek()) |
- return scoped_ptr<IndexedDBBackingStore::Cursor>(); |
- |
- return cursor.PassAs<IndexedDBBackingStore::Cursor>(); |
-} |
- |
-IndexedDBBackingStore::Transaction::Transaction( |
- IndexedDBBackingStore* backing_store) |
- : backing_store_(backing_store) {} |
- |
-IndexedDBBackingStore::Transaction::~Transaction() {} |
- |
-void IndexedDBBackingStore::Transaction::begin() { |
- IDB_TRACE("IndexedDBBackingStore::Transaction::begin"); |
- DCHECK(!transaction_); |
- transaction_ = LevelDBTransaction::Create(backing_store_->db_.get()); |
-} |
- |
-bool IndexedDBBackingStore::Transaction::Commit() { |
- IDB_TRACE("IndexedDBBackingStore::Transaction::commit"); |
- DCHECK(transaction_); |
- bool result = transaction_->Commit(); |
- transaction_ = NULL; |
- if (!result) |
- INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD); |
- return result; |
-} |
- |
-void IndexedDBBackingStore::Transaction::Rollback() { |
- IDB_TRACE("IndexedDBBackingStore::Transaction::rollback"); |
- DCHECK(transaction_); |
- transaction_->Rollback(); |
- transaction_ = NULL; |
-} |
- |
-} // namespace content |