diff options
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/leveldb')
14 files changed, 0 insertions, 5877 deletions
diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.cpp deleted file mode 100644 index b3c5f6113..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBBackingStoreCursorLevelDB.h" - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "IDBBackingStoreLevelDB.h" -#include "LevelDBTransaction.h" - -namespace WebCore { - -IDBBackingStoreCursorLevelDB::IDBBackingStoreCursorLevelDB(const IDBBackingStoreCursorLevelDB* other) - : m_transaction(other->m_transaction) - , m_cursorOptions(other->m_cursorOptions) - , m_currentKey(other->m_currentKey) - , m_recordIdentifier(IDBRecordIdentifier::create()) -{ - if (other->m_iterator) { - m_iterator = m_transaction->createIterator(); - - if (other->m_iterator->isValid()) { - m_iterator->seek(other->m_iterator->key()); - ASSERT(m_iterator->isValid()); - } - } - - m_recordIdentifier->reset(other->m_recordIdentifier->encodedPrimaryKey(), other->m_recordIdentifier->version()); -} - -bool IDBBackingStoreCursorLevelDB::firstSeek() -{ - m_iterator = m_transaction->createIterator(); - if (m_cursorOptions.forward) - m_iterator->seek(m_cursorOptions.lowKey); - else - m_iterator->seek(m_cursorOptions.highKey); - - return continueFunction(0, Ready); -} - -bool IDBBackingStoreCursorLevelDB::advance(unsigned long count) -{ - while (count--) { - if (!continueFunction()) - return false; - } - return true; -} - -bool IDBBackingStoreCursorLevelDB::continueFunction(const IDBKey* key, IteratorState nextState) -{ - RefPtr<IDBKey> previousKey = m_currentKey; - - bool firstIteration = true; - - // When iterating with PrevNoDuplicate, spec requires that the - // value we yield for each key is the first duplicate in forwards - // order. - RefPtr<IDBKey> lastDuplicateKey; - - bool forward = m_cursorOptions.forward; - - for (;;) { - if (nextState == Seek) { - // FIXME: Optimize seeking for reverse cursors as well. - if (firstIteration && key && forward) { - m_iterator->seek(encodeKey(*key)); - firstIteration = false; - } else if (forward) - m_iterator->next(); - else - m_iterator->prev(); - } else - nextState = Seek; // for subsequent iterations - - if (!m_iterator->isValid()) { - if (!forward && lastDuplicateKey.get()) { - // We need to walk forward because we hit the end of - // the data. - forward = true; - continue; - } - - return false; - } - - if (isPastBounds()) { - if (!forward && lastDuplicateKey.get()) { - // 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) { - if (forward) { - if (m_currentKey->isLessThan(key)) - continue; - } else { - if (key->isLessThan(m_currentKey.get())) - continue; - } - } - - if (m_cursorOptions.unique) { - - if (m_currentKey->isEqual(previousKey.get())) { - // We should never be able to walk forward all the way - // to the previous key. - ASSERT(!lastDuplicateKey.get()); - continue; - } - - if (!forward) { - if (!lastDuplicateKey.get()) { - lastDuplicateKey = m_currentKey; - continue; - } - - // We need to walk forward because we hit the boundary - // between key ranges. - if (!lastDuplicateKey->isEqual(m_currentKey.get())) { - forward = true; - continue; - } - - continue; - } - } - break; - } - - ASSERT(!lastDuplicateKey.get() || (forward && lastDuplicateKey->isEqual(m_currentKey.get()))); - return true; -} - -bool IDBBackingStoreCursorLevelDB::haveEnteredRange() const -{ - if (m_cursorOptions.forward) { - if (m_cursorOptions.lowOpen) - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) > 0; - - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) >= 0; - } - if (m_cursorOptions.highOpen) - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) < 0; - - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) <= 0; -} - -bool IDBBackingStoreCursorLevelDB::isPastBounds() const -{ - if (m_cursorOptions.forward) { - if (m_cursorOptions.highOpen) - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) >= 0; - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.highKey) > 0; - } - - if (m_cursorOptions.lowOpen) - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) <= 0; - return IDBBackingStoreLevelDB::compareIndexKeys(m_iterator->key(), m_cursorOptions.lowKey) < 0; -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.h deleted file mode 100644 index 972088478..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreCursorLevelDB.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBBackingStoreCursorLevelDB_h -#define IDBBackingStoreCursorLevelDB_h - -#include "IDBKey.h" -#include "IDBRecordIdentifier.h" -#include "LevelDBIterator.h" - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -namespace WebCore { - -class LevelDBTransaction; -class SharedBuffer; - -class IDBBackingStoreCursorLevelDB : public RefCounted<IDBBackingStoreCursorLevelDB> { -public: - enum IteratorState { - Ready = 0, - Seek - }; - - struct CursorOptions { - int64_t databaseId; - int64_t objectStoreId; - int64_t indexId; - Vector<char> lowKey; - bool lowOpen; - Vector<char> highKey; - bool highOpen; - bool forward; - bool unique; - }; - - virtual PassRefPtr<IDBKey> key() const { return m_currentKey; } - virtual bool continueFunction(const IDBKey* = 0, IteratorState = Seek); - virtual bool advance(unsigned long); - bool firstSeek(); - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> clone() = 0; - - virtual PassRefPtr<IDBKey> primaryKey() const { return m_currentKey; } - virtual PassRefPtr<SharedBuffer> value() const = 0; - virtual const IDBRecordIdentifier& recordIdentifier() const { return *m_recordIdentifier; } - virtual ~IDBBackingStoreCursorLevelDB() { } - virtual bool loadCurrentRow() = 0; - -protected: - IDBBackingStoreCursorLevelDB(int64_t cursorID, LevelDBTransaction* transaction, const CursorOptions& cursorOptions) - : m_cursorID(cursorID) - , m_transaction(transaction) - , m_cursorOptions(cursorOptions) - , m_recordIdentifier(IDBRecordIdentifier::create()) - { - } - explicit IDBBackingStoreCursorLevelDB(const IDBBackingStoreCursorLevelDB* other); - - virtual Vector<char> encodeKey(const IDBKey&) = 0; - - bool isPastBounds() const; - bool haveEnteredRange() const; - - int64_t m_cursorID; - LevelDBTransaction* m_transaction; - const CursorOptions m_cursorOptions; - OwnPtr<LevelDBIterator> m_iterator; - RefPtr<IDBKey> m_currentKey; - RefPtr<IDBRecordIdentifier> m_recordIdentifier; -}; - -} // namespace WebCore - -#endif // USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) -#endif // IDBBackingStoreCursorLevelDB_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp deleted file mode 100644 index 0712bdf38..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp +++ /dev/null @@ -1,1931 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBBackingStoreLevelDB.h" - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "FileSystem.h" -#include "HistogramSupport.h" -#include "IDBDatabaseMetadata.h" -#include "IDBIndexWriterLevelDB.h" -#include "IDBKey.h" -#include "IDBKeyPath.h" -#include "IDBKeyRange.h" -#include "IDBLevelDBCoding.h" -#include "IDBTransactionBackend.h" -#include "LevelDBComparator.h" -#include "LevelDBDatabase.h" -#include "LevelDBIterator.h" -#include "LevelDBSlice.h" -#include "LevelDBTransaction.h" -#include "Logging.h" -#include "SecurityOrigin.h" -#include "SharedBuffer.h" -#include <wtf/Assertions.h> - -namespace WebCore { - -using namespace IDBLevelDBCoding; - -const int64_t KeyGeneratorInitialNumber = 1; // From the IndexedDB specification. - -enum IDBBackingStoreLevelDBErrorSource { - // 0 - 2 are no longer used. - FindKeyInIndex = 3, - GetIDBDatabaseMetaData, - GetIndexes, - GetKeyGeneratorCurrentNumber, - GetObjectStores, - GetRecord, - KeyExistsInObjectStore, - LoadCurrentRow, - SetupMetadata, - GetPrimaryKeyViaIndex, - KeyExistsInIndex, - VersionExists, - DeleteObjectStore, - SetMaxObjectStoreId, - SetMaxIndexId, - GetNewDatabaseId, - GetNewVersionNumber, - CreateIDBDatabaseMetaData, - DeleteDatabase, - IDBLevelDBBackingStoreInternalErrorMax, -}; - -static void recordInternalError(const char* type, IDBBackingStoreLevelDBErrorSource location) -{ - String name = String::format("WebCore.IndexedDB.BackingStore.%sError", type); - HistogramSupport::histogramEnumeration(name.utf8().data(), location, IDBLevelDBBackingStoreInternalErrorMax); -} - -// 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 %s Error: %s", type, #location); \ - ASSERT_NOT_REACHED(); \ - 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_t& foundInt, bool& found) -{ - Vector<char> result; - bool ok = db->safeGet(key, result, found); - if (!ok) - return false; - if (!found) - return true; - - foundInt = decodeInt(result.begin(), result.end()); - return true; -} - -static void putInt(LevelDBTransaction* transaction, const LevelDBSlice& key, int64_t value) -{ - ASSERT(value >= 0); - transaction->put(key, encodeInt(value)); -} - -template <typename DBOrTransaction> -WARN_UNUSED_RETURN static bool getVarInt(DBOrTransaction* db, const LevelDBSlice& key, int64_t& foundInt, bool& found) -{ - Vector<char> result; - bool ok = db->safeGet(key, result, found); - if (!ok) - return false; - if (!found) - return true; - - found = decodeVarInt(result.begin(), result.end(), foundInt) == result.end(); - return true; -} - -static void putVarInt(LevelDBTransaction* transaction, const LevelDBSlice& key, int64_t value) -{ - transaction->put(key, encodeVarInt(value)); -} - -template <typename DBOrTransaction> -WARN_UNUSED_RETURN static bool getString(DBOrTransaction* db, const LevelDBSlice& key, String& foundString, bool& found) -{ - Vector<char> result; - found = false; - bool ok = db->safeGet(key, result, found); - if (!ok) - return false; - if (!found) - return true; - - foundString = decodeString(result.begin(), result.end()); - return true; -} - -static void putString(LevelDBTransaction* transaction, const LevelDBSlice& key, const String& value) -{ - transaction->put(key, encodeString(value)); -} - -static void putIDBKeyPath(LevelDBTransaction* transaction, const LevelDBSlice& key, const IDBKeyPath& value) -{ - transaction->put(key, encodeIDBKeyPath(value)); -} - -static int compareKeys(const LevelDBSlice& a, const LevelDBSlice& b) -{ - return compare(a, b); -} - -int IDBBackingStoreLevelDB::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 { return IDBLevelDBCoding::compare(a, b); } - virtual const char* name() const { return "idb_cmp1"; } -}; - -// 0 - Initial version. -// 1 - Adds UserIntVersion to DatabaseMetaData. -// 2 - Adds DataVersion to to global metadata. -const int64_t latestKnownSchemaVersion = 2; -WARN_UNUSED_RETURN static bool isSchemaKnown(LevelDBDatabase* db, bool& known) -{ - int64_t dbSchemaVersion = 0; - bool found = false; - bool ok = getInt(db, SchemaVersionKey::encode(), dbSchemaVersion, found); - if (!ok) - return false; - if (!found) { - known = true; - return true; - } - if (dbSchemaVersion > latestKnownSchemaVersion) { - known = false; - return true; - } - - const uint32_t latestKnownDataVersion = SerializedScriptValue::wireFormatVersion(); - int64_t dbDataVersion = 0; - ok = getInt(db, DataVersionKey::encode(), dbDataVersion, found); - if (!ok) - return false; - if (!found) { - known = true; - return true; - } - - if (dbDataVersion > latestKnownDataVersion) { - known = false; - return true; - } - - known = true; - return true; -} - -WARN_UNUSED_RETURN static bool setUpMetadata(LevelDBDatabase* db, const String& origin) -{ - const uint32_t latestKnownDataVersion = SerializedScriptValue::wireFormatVersion(); - const Vector<char> schemaVersionKey = SchemaVersionKey::encode(); - const Vector<char> dataVersionKey = DataVersionKey::encode(); - - RefPtr<LevelDBTransaction> transaction = LevelDBTransaction::create(db); - - int64_t dbSchemaVersion = 0; - int64_t dbDataVersion = 0; - bool found = false; - bool ok = getInt(transaction.get(), schemaVersionKey, dbSchemaVersion, found); - if (!ok) { - INTERNAL_READ_ERROR(SetupMetadata); - return false; - } - if (!found) { - // Initialize new backing store. - dbSchemaVersion = latestKnownSchemaVersion; - putInt(transaction.get(), schemaVersionKey, dbSchemaVersion); - dbDataVersion = latestKnownDataVersion; - putInt(transaction.get(), dataVersionKey, dbDataVersion); - } else { - // Upgrade old backing store. - ASSERT(dbSchemaVersion <= latestKnownSchemaVersion); - if (dbSchemaVersion < 1) { - dbSchemaVersion = 1; - putInt(transaction.get(), schemaVersionKey, dbSchemaVersion); - const Vector<char> startKey = DatabaseNameKey::encodeMinKeyForOrigin(origin); - const Vector<char> stopKey = DatabaseNameKey::encodeStopKeyForOrigin(origin); - OwnPtr<LevelDBIterator> it = db->createIterator(); - for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) { - int64_t databaseId = 0; - found = false; - bool ok = getInt(transaction.get(), it->key(), databaseId, found); - if (!ok) { - INTERNAL_READ_ERROR(SetupMetadata); - return false; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(SetupMetadata); - return false; - } - Vector<char> intVersionKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::UserIntVersion); - putVarInt(transaction.get(), intVersionKey, IDBDatabaseMetadata::DefaultIntVersion); - } - } - if (dbSchemaVersion < 2) { - dbSchemaVersion = 2; - putInt(transaction.get(), schemaVersionKey, dbSchemaVersion); - dbDataVersion = SerializedScriptValue::wireFormatVersion(); - putInt(transaction.get(), dataVersionKey, dbDataVersion); - } - } - - // All new values will be written using this serialization version. - found = false; - ok = getInt(transaction.get(), dataVersionKey, dbDataVersion, found); - if (!ok) { - INTERNAL_READ_ERROR(SetupMetadata); - return false; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(SetupMetadata); - return false; - } - if (dbDataVersion < latestKnownDataVersion) { - dbDataVersion = latestKnownDataVersion; - putInt(transaction.get(), dataVersionKey, dbDataVersion); - } - - ASSERT(dbSchemaVersion == latestKnownSchemaVersion); - ASSERT(dbDataVersion == latestKnownDataVersion); - - if (!transaction->commit()) { - INTERNAL_WRITE_ERROR(SetupMetadata); - return false; - } - return true; -} - -template <typename DBOrTransaction> -WARN_UNUSED_RETURN static bool getMaxObjectStoreId(DBOrTransaction* db, int64_t databaseId, int64_t& maxObjectStoreId) -{ - const Vector<char> maxObjectStoreIdKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::MaxObjectStoreId); - bool ok = getMaxObjectStoreId(db, maxObjectStoreIdKey, maxObjectStoreId); - return ok; -} - -template <typename DBOrTransaction> -WARN_UNUSED_RETURN static bool getMaxObjectStoreId(DBOrTransaction* db, const Vector<char>& maxObjectStoreIdKey, int64_t& maxObjectStoreId) -{ - maxObjectStoreId = -1; - bool found = false; - bool ok = getInt(db, maxObjectStoreIdKey, maxObjectStoreId, found); - if (!ok) - return false; - if (!found) - maxObjectStoreId = 0; - - ASSERT(maxObjectStoreId >= 0); - return true; -} - -class DefaultLevelDBFactory : public LevelDBFactory { -public: - virtual PassOwnPtr<LevelDBDatabase> openLevelDB(const String& fileName, const LevelDBComparator* comparator) - { - return LevelDBDatabase::open(fileName, comparator); - } - virtual bool destroyLevelDB(const String& fileName) - { - return LevelDBDatabase::destroy(fileName); - } -}; - -IDBBackingStoreLevelDB::IDBBackingStoreLevelDB(const String& identifier, PassOwnPtr<LevelDBDatabase> db, PassOwnPtr<LevelDBComparator> comparator) - : m_identifier(identifier) - , m_db(db) - , m_comparator(comparator) - , m_weakFactory(this) -{ -} - -IDBBackingStoreLevelDB::~IDBBackingStoreLevelDB() -{ - // m_db's destructor uses m_comparator. The order of destruction is important. - m_db.clear(); - m_comparator.clear(); -} - -enum IDBLevelDBBackingStoreOpenResult { - IDBLevelDBBackingStoreOpenMemorySuccess, - IDBLevelDBBackingStoreOpenSuccess, - IDBLevelDBBackingStoreOpenFailedDirectory, - IDBLevelDBBackingStoreOpenFailedUnknownSchema, - IDBLevelDBBackingStoreOpenCleanupDestroyFailed, - IDBLevelDBBackingStoreOpenCleanupReopenFailed, - IDBLevelDBBackingStoreOpenCleanupReopenSuccess, - IDBLevelDBBackingStoreOpenFailedIOErrCheckingSchema, - IDBLevelDBBackingStoreOpenFailedUnknownErr, - IDBLevelDBBackingStoreOpenMemoryFailed, - IDBLevelDBBackingStoreOpenAttemptNonASCII, - IDBLevelDBBackingStoreOpenMax, -}; - -PassRefPtr<IDBBackingStoreLevelDB> IDBBackingStoreLevelDB::open(const SecurityOrigin& securityOrigin, const String& pathBaseArg, const String& fileIdentifier) -{ - DefaultLevelDBFactory levelDBFactory; - return IDBBackingStoreLevelDB::open(securityOrigin, pathBaseArg, fileIdentifier, &levelDBFactory); -} - -PassRefPtr<IDBBackingStoreLevelDB> IDBBackingStoreLevelDB::open(const SecurityOrigin& securityOrigin, const String& pathBaseArg, const String& fileIdentifier, LevelDBFactory* levelDBFactory) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::open"); - ASSERT(!pathBaseArg.isEmpty()); - String pathBase = pathBaseArg; - - OwnPtr<LevelDBComparator> comparator = adoptPtr(new Comparator()); - OwnPtr<LevelDBDatabase> db; - - if (!pathBase.containsOnlyASCII()) - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenAttemptNonASCII, IDBLevelDBBackingStoreOpenMax); - if (!makeAllDirectories(pathBase)) { - LOG_ERROR("Unable to create IndexedDB database path %s", pathBase.utf8().data()); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenFailedDirectory, IDBLevelDBBackingStoreOpenMax); - return PassRefPtr<IDBBackingStoreLevelDB>(); - } - - String path = pathByAppendingComponent(pathBase, securityOrigin.databaseIdentifier() + ".indexeddb.leveldb"); - - db = levelDBFactory->openLevelDB(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"); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenFailedIOErrCheckingSchema, IDBLevelDBBackingStoreOpenMax); - db.clear(); - } else if (!known) { - LOG_ERROR("IndexedDB backing store had unknown schema, treating it as failure to open"); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenFailedUnknownSchema, IDBLevelDBBackingStoreOpenMax); - db.clear(); - } - } - - if (db) - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenSuccess, IDBLevelDBBackingStoreOpenMax); - else { - LOG_ERROR("IndexedDB backing store open failed, attempting cleanup"); - bool success = levelDBFactory->destroyLevelDB(path); - if (!success) { - LOG_ERROR("IndexedDB backing store cleanup failed"); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenCleanupDestroyFailed, IDBLevelDBBackingStoreOpenMax); - return PassRefPtr<IDBBackingStoreLevelDB>(); - } - - LOG_ERROR("IndexedDB backing store cleanup succeeded, reopening"); - db = levelDBFactory->openLevelDB(path, comparator.get()); - if (!db) { - LOG_ERROR("IndexedDB backing store reopen after recovery failed"); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenCleanupReopenFailed, IDBLevelDBBackingStoreOpenMax); - return PassRefPtr<IDBBackingStoreLevelDB>(); - } - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenCleanupReopenSuccess, IDBLevelDBBackingStoreOpenMax); - } - - if (!db) { - ASSERT_NOT_REACHED(); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenFailedUnknownErr, IDBLevelDBBackingStoreOpenMax); - return PassRefPtr<IDBBackingStoreLevelDB>(); - } - - return create(fileIdentifier, db.release(), comparator.release()); -} - -PassRefPtr<IDBBackingStoreLevelDB> IDBBackingStoreLevelDB::openInMemory(const String& identifier) -{ - DefaultLevelDBFactory levelDBFactory; - return IDBBackingStoreLevelDB::openInMemory(identifier, &levelDBFactory); -} - -PassRefPtr<IDBBackingStoreLevelDB> IDBBackingStoreLevelDB::openInMemory(const String& identifier, LevelDBFactory*) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::openInMemory"); - - OwnPtr<LevelDBComparator> comparator = adoptPtr(new Comparator()); - OwnPtr<LevelDBDatabase> db = LevelDBDatabase::openInMemory(comparator.get()); - if (!db) { - LOG_ERROR("LevelDBDatabase::openInMemory failed."); - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenMemoryFailed, IDBLevelDBBackingStoreOpenMax); - return PassRefPtr<IDBBackingStoreLevelDB>(); - } - HistogramSupport::histogramEnumeration("WebCore.IndexedDB.BackingStore.OpenStatus", IDBLevelDBBackingStoreOpenMemorySuccess, IDBLevelDBBackingStoreOpenMax); - - return create(identifier, db.release(), comparator.release()); -} - -PassRefPtr<IDBBackingStoreLevelDB> IDBBackingStoreLevelDB::create(const String& identifier, PassOwnPtr<LevelDBDatabase> db, PassOwnPtr<LevelDBComparator> comparator) -{ - // FIXME: Handle comparator name changes. - RefPtr<IDBBackingStoreLevelDB> backingStore(adoptRef(new IDBBackingStoreLevelDB(identifier, db, comparator))); - - if (!setUpMetadata(backingStore->m_db.get(), identifier)) - return PassRefPtr<IDBBackingStoreLevelDB>(); - - return backingStore.release(); -} - -Vector<String> IDBBackingStoreLevelDB::getDatabaseNames() -{ - Vector<String> foundNames; - const Vector<char> startKey = DatabaseNameKey::encodeMinKeyForOrigin(m_identifier); - const Vector<char> stopKey = DatabaseNameKey::encodeStopKeyForOrigin(m_identifier); - - ASSERT(foundNames.isEmpty()); - - OwnPtr<LevelDBIterator> it = m_db->createIterator(); - for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) { - const char* p = it->key().begin(); - const char* limit = it->key().end(); - - DatabaseNameKey databaseNameKey; - p = DatabaseNameKey::decode(p, limit, &databaseNameKey); - ASSERT(p); - - foundNames.append(databaseNameKey.databaseName()); - } - return foundNames; -} - -bool IDBBackingStoreLevelDB::getIDBDatabaseMetaData(const String& name, IDBDatabaseMetadata* metadata, bool& found) -{ - const Vector<char> key = DatabaseNameKey::encode(m_identifier, name); - found = false; - - bool ok = getInt(m_db.get(), key, metadata->id, found); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - return false; - } - if (!found) - return true; - - // FIXME: The string version is no longer supported, so the levelDB ports should consider refactoring off of it. - String stringVersion; - ok = getString(m_db.get(), DatabaseMetaDataKey::encode(metadata->id, DatabaseMetaDataKey::UserVersion), stringVersion, found); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - return false; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(GetIDBDatabaseMetaData); - return false; - } - - int64_t version; - ok = getVarInt(m_db.get(), DatabaseMetaDataKey::encode(metadata->id, DatabaseMetaDataKey::UserIntVersion), version, found); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - return false; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(GetIDBDatabaseMetaData); - return false; - } - - // FIXME: The versioning semantics have changed since this original code was written, and what was once a negative number - // stored in the database is no longer a valid version. - if (version < 0) - version = 0; - metadata->version = version; - - ok = getMaxObjectStoreId(m_db.get(), metadata->id, metadata->maxObjectStoreId); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - return false; - } - - return true; -} - -void IDBBackingStoreLevelDB::getOrEstablishIDBDatabaseMetadata(const String& name, std::function<void (const IDBDatabaseMetadata&, bool success)> metadataFunction) -{ - const Vector<char> key = DatabaseNameKey::encode(m_identifier, name); - bool found = false; - - IDBDatabaseMetadata resultMetadata; - - bool ok = getInt(m_db.get(), key, resultMetadata.id, found); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - metadataFunction(resultMetadata, false); - return; - } - - if (!found) { - resultMetadata.name = name; - resultMetadata.version = IDBDatabaseMetadata::DefaultIntVersion; - - metadataFunction(resultMetadata, createIDBDatabaseMetaData(resultMetadata)); - return; - } - - int64_t version; - ok = getVarInt(m_db.get(), DatabaseMetaDataKey::encode(resultMetadata.id, DatabaseMetaDataKey::UserIntVersion), version, found); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - metadataFunction(resultMetadata, false); - return; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(GetIDBDatabaseMetaData); - metadataFunction(resultMetadata, false); - return; - } - - // FIXME: The versioning semantics have changed since this original code was written, and what was once a negative number - // stored in the database is no longer a valid version. - if (version < 0) - version = 0; - resultMetadata.version = version; - - ok = getMaxObjectStoreId(m_db.get(), resultMetadata.id, resultMetadata.maxObjectStoreId); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - metadataFunction(resultMetadata, false); - return; - } - - ok = getObjectStores(resultMetadata.id, &resultMetadata.objectStores); - if (!ok) { - INTERNAL_READ_ERROR(GetIDBDatabaseMetaData); - metadataFunction(resultMetadata, false); - return; - } - - metadataFunction(resultMetadata, true); -} - -WARN_UNUSED_RETURN static bool getNewDatabaseId(LevelDBDatabase* db, int64_t& newId) -{ - RefPtr<LevelDBTransaction> transaction = LevelDBTransaction::create(db); - - newId = -1; - int64_t maxDatabaseId = -1; - bool found = false; - bool ok = getInt(transaction.get(), MaxDatabaseIdKey::encode(), maxDatabaseId, found); - if (!ok) { - INTERNAL_READ_ERROR(GetNewDatabaseId); - return false; - } - if (!found) - maxDatabaseId = 0; - - ASSERT(maxDatabaseId >= 0); - - int64_t databaseId = maxDatabaseId + 1; - putInt(transaction.get(), MaxDatabaseIdKey::encode(), databaseId); - if (!transaction->commit()) { - INTERNAL_WRITE_ERROR(GetNewDatabaseId); - return false; - } - newId = databaseId; - return true; -} - -// FIXME: LevelDB needs to support uint64_t as the version type. -bool IDBBackingStoreLevelDB::createIDBDatabaseMetaData(IDBDatabaseMetadata& metadata) -{ - bool ok = getNewDatabaseId(m_db.get(), metadata.id); - if (!ok) - return false; - ASSERT(metadata.id >= 0); - - RefPtr<LevelDBTransaction> transaction = LevelDBTransaction::create(m_db.get()); - putInt(transaction.get(), DatabaseNameKey::encode(m_identifier, metadata.name), metadata.id); - putVarInt(transaction.get(), DatabaseMetaDataKey::encode(metadata.id, DatabaseMetaDataKey::UserIntVersion), metadata.version); - if (!transaction->commit()) { - INTERNAL_WRITE_ERROR(CreateIDBDatabaseMetaData); - return false; - } - return true; -} - -bool IDBBackingStoreLevelDB::updateIDBDatabaseVersion(IDBBackingStoreTransactionLevelDB& transaction, int64_t rowId, uint64_t version) -{ - if (version == IDBDatabaseMetadata::NoIntVersion) - version = IDBDatabaseMetadata::DefaultIntVersion; - putVarInt(IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::UserIntVersion), version); - return true; -} - -static void deleteRange(LevelDBTransaction* transaction, const Vector<char>& begin, const Vector<char>& end) -{ - OwnPtr<LevelDBIterator> it = transaction->createIterator(); - for (it->seek(begin); it->isValid() && compareKeys(it->key(), end) < 0; it->next()) - transaction->remove(it->key()); -} - -void IDBBackingStoreLevelDB::deleteDatabase(const String& name, std::function<void (bool success)> boolCallbackFunction) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::deleteDatabase"); - OwnPtr<LevelDBWriteOnlyTransaction> transaction = LevelDBWriteOnlyTransaction::create(m_db.get()); - - IDBDatabaseMetadata metadata; - bool success = false; - bool ok = getIDBDatabaseMetaData(name, &metadata, success); - if (!ok) { - boolCallbackFunction(false); - return; - } - - if (!success) { - boolCallbackFunction(true); - return; - } - - const Vector<char> startKey = DatabaseMetaDataKey::encode(metadata.id, DatabaseMetaDataKey::OriginName); - const Vector<char> stopKey = DatabaseMetaDataKey::encode(metadata.id + 1, DatabaseMetaDataKey::OriginName); - OwnPtr<LevelDBIterator> it = m_db->createIterator(); - for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) - transaction->remove(it->key()); - - const Vector<char> key = DatabaseNameKey::encode(m_identifier, name); - transaction->remove(key); - - if (!transaction->commit()) { - INTERNAL_WRITE_ERROR(DeleteDatabase); - boolCallbackFunction(false); - return; - } - boolCallbackFunction(true); -} - -static bool checkObjectStoreAndMetaDataType(const LevelDBIterator* it, const Vector<char>& stopKey, int64_t objectStoreId, int64_t metaDataType) -{ - if (!it->isValid() || compareKeys(it->key(), stopKey) >= 0) - return false; - - ObjectStoreMetaDataKey metaDataKey; - const char* p = ObjectStoreMetaDataKey::decode(it->key().begin(), it->key().end(), &metaDataKey); - ASSERT_UNUSED(p, p); - if (metaDataKey.objectStoreId() != objectStoreId) - return false; - if (metaDataKey.metaDataType() != metaDataType) - return false; - return true; -} - -// FIXME: This should do some error handling rather than plowing ahead when bad data is encountered. -bool IDBBackingStoreLevelDB::getObjectStores(int64_t databaseId, IDBDatabaseMetadata::ObjectStoreMap* objectStores) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::getObjectStores"); - if (!KeyPrefix::isValidDatabaseId(databaseId)) - return false; - const Vector<char> startKey = ObjectStoreMetaDataKey::encode(databaseId, 1, 0); - const Vector<char> stopKey = ObjectStoreMetaDataKey::encodeMaxKey(databaseId); - - ASSERT(objectStores->isEmpty()); - - OwnPtr<LevelDBIterator> it = m_db->createIterator(); - it->seek(startKey); - while (it->isValid() && compareKeys(it->key(), stopKey) < 0) { - const char* p = it->key().begin(); - const char* limit = it->key().end(); - - ObjectStoreMetaDataKey metaDataKey; - p = ObjectStoreMetaDataKey::decode(p, limit, &metaDataKey); - ASSERT(p); - if (metaDataKey.metaDataType() != ObjectStoreMetaDataKey::Name) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - // Possible stale metadata, but don't fail the load. - it->next(); - continue; - } - - int64_t objectStoreId = metaDataKey.objectStoreId(); - - // FIXME: Do this by direct key lookup rather than iteration, to simplify. - String objectStoreName = decodeString(it->value().begin(), it->value().end()); - - it->next(); - if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::KeyPath)) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - IDBKeyPath keyPath = decodeIDBKeyPath(it->value().begin(), it->value().end()); - - it->next(); - if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::AutoIncrement)) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - bool autoIncrement = decodeBool(it->value().begin(), it->value().end()); - - it->next(); // Is evicatble. - if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::Evictable)) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - - it->next(); // Last version. - if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::LastVersion)) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - - it->next(); // Maximum index id allocated. - if (!checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::MaxIndexId)) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - int64_t maxIndexId = decodeInt(it->value().begin(), it->value().end()); - - it->next(); // [optional] has key path (is not null) - if (checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::HasKeyPath)) { - bool hasKeyPath = decodeBool(it->value().begin(), it->value().end()); - // This check accounts for two layers of legacy coding: - // (1) Initially, hasKeyPath was added to distinguish null vs. string. - // (2) Later, null vs. string vs. array was stored in the keyPath itself. - // So this check is only relevant for string-type keyPaths. - if (!hasKeyPath && (keyPath.type() == IDBKeyPath::StringType && !keyPath.string().isEmpty())) { - INTERNAL_CONSISTENCY_ERROR(GetObjectStores); - break; - } - if (!hasKeyPath) - keyPath = IDBKeyPath(); - it->next(); - } - - int64_t keyGeneratorCurrentNumber = -1; - if (checkObjectStoreAndMetaDataType(it.get(), stopKey, objectStoreId, ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber)) { - keyGeneratorCurrentNumber = decodeInt(it->value().begin(), it->value().end()); - // FIXME: Return keyGeneratorCurrentNumber, cache in object store, and write lazily to backing store. - // For now, just assert that if it was written it was valid. - ASSERT_UNUSED(keyGeneratorCurrentNumber, keyGeneratorCurrentNumber >= KeyGeneratorInitialNumber); - it->next(); - } - - IDBObjectStoreMetadata metadata(objectStoreName, objectStoreId, keyPath, autoIncrement, maxIndexId); - if (!getIndexes(databaseId, objectStoreId, &metadata.indexes)) - return false; - objectStores->set(objectStoreId, metadata); - } - return true; -} - -WARN_UNUSED_RETURN static bool setMaxObjectStoreId(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId) -{ - const Vector<char> maxObjectStoreIdKey = DatabaseMetaDataKey::encode(databaseId, DatabaseMetaDataKey::MaxObjectStoreId); - int64_t maxObjectStoreId = -1; - bool ok = getMaxObjectStoreId(transaction, maxObjectStoreIdKey, maxObjectStoreId); - if (!ok) { - INTERNAL_READ_ERROR(SetMaxObjectStoreId); - return false; - } - - if (objectStoreId <= maxObjectStoreId) { - INTERNAL_CONSISTENCY_ERROR(SetMaxObjectStoreId); - return false; - } - putInt(transaction, maxObjectStoreIdKey, objectStoreId); - return true; -} - -bool IDBBackingStoreLevelDB::createObjectStore(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, const String& name, const IDBKeyPath& keyPath, bool autoIncrement) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::createObjectStore"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - if (!setMaxObjectStoreId(levelDBTransaction, databaseId, objectStoreId)) - return false; - - const Vector<char> nameKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::Name); - const Vector<char> keyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::KeyPath); - const Vector<char> autoIncrementKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::AutoIncrement); - const Vector<char> evictableKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::Evictable); - const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::LastVersion); - const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::MaxIndexId); - const Vector<char> hasKeyPathKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::HasKeyPath); - const Vector<char> keyGeneratorCurrentNumberKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber); - const Vector<char> namesKey = ObjectStoreNamesKey::encode(databaseId, name); - - putString(levelDBTransaction, nameKey, name); - putIDBKeyPath(levelDBTransaction, keyPathKey, keyPath); - putInt(levelDBTransaction, autoIncrementKey, autoIncrement); - putInt(levelDBTransaction, evictableKey, false); - putInt(levelDBTransaction, lastVersionKey, 1); - putInt(levelDBTransaction, maxIndexIdKey, MinimumIndexId); - putBool(levelDBTransaction, hasKeyPathKey, !keyPath.isNull()); - putInt(levelDBTransaction, keyGeneratorCurrentNumberKey, KeyGeneratorInitialNumber); - putInt(levelDBTransaction, namesKey, objectStoreId); - return true; -} - -bool IDBBackingStoreLevelDB::deleteObjectStore(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::deleteObjectStore"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - String objectStoreName; - bool found = false; - bool ok = getString(levelDBTransaction, ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::Name), objectStoreName, found); - if (!ok) { - INTERNAL_READ_ERROR(DeleteObjectStore); - return false; - } - if (!found) { - INTERNAL_CONSISTENCY_ERROR(DeleteObjectStore); - return false; - } - - deleteRange(levelDBTransaction, ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, 0), ObjectStoreMetaDataKey::encodeMaxKey(databaseId, objectStoreId)); - - levelDBTransaction->remove(ObjectStoreNamesKey::encode(databaseId, objectStoreName)); - - deleteRange(levelDBTransaction, IndexFreeListKey::encode(databaseId, objectStoreId, 0), IndexFreeListKey::encodeMaxKey(databaseId, objectStoreId)); - deleteRange(levelDBTransaction, IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0), IndexMetaDataKey::encodeMaxKey(databaseId, objectStoreId)); - - return clearObjectStore(transaction, databaseId, objectStoreId); -} - -bool IDBBackingStoreLevelDB::getRecord(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey& key, Vector<char>& record) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::getRecord"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key); - Vector<char> data; - - record.clear(); - - bool found = false; - bool ok = levelDBTransaction->safeGet(leveldbKey, data, found); - if (!ok) { - INTERNAL_READ_ERROR(GetRecord); - return false; - } - if (!found) - return true; - - int64_t version; - const char* p = decodeVarInt(data.begin(), data.end(), version); - if (!p) { - INTERNAL_READ_ERROR(GetRecord); - return false; - } - - record.appendRange(p, static_cast<const char*>(data.end())); - return true; -} - -WARN_UNUSED_RETURN static bool getNewVersionNumber(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t& newVersionNumber) -{ - const Vector<char> lastVersionKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::LastVersion); - - newVersionNumber = -1; - int64_t lastVersion = -1; - bool found = false; - bool ok = getInt(transaction, lastVersionKey, lastVersion, found); - if (!ok) { - INTERNAL_READ_ERROR(GetNewVersionNumber); - return false; - } - if (!found) - lastVersion = 0; - - ASSERT(lastVersion >= 0); - - int64_t version = lastVersion + 1; - putInt(transaction, lastVersionKey, version); - - ASSERT(version > lastVersion); // FIXME: Think about how we want to handle the overflow scenario. - - newVersionNumber = version; - return true; -} - -bool IDBBackingStoreLevelDB::putRecord(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey& key, PassRefPtr<SharedBuffer> prpValue, IDBRecordIdentifier* recordIdentifier) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::putRecord"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - ASSERT(key.isValid()); - - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - int64_t version = -1; - bool ok = getNewVersionNumber(levelDBTransaction, databaseId, objectStoreId, version); - if (!ok) - return false; - ASSERT(version >= 0); - const Vector<char> objectStoredataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key); - - Vector<char> v; - v.appendVector(encodeVarInt(version)); - RefPtr<SharedBuffer> value = prpValue; - ASSERT(value); - v.append(value->data(), value->size()); - - levelDBTransaction->put(objectStoredataKey, v); - - const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, key); - levelDBTransaction->put(existsEntryKey, encodeInt(version)); - - recordIdentifier->reset(encodeIDBKey(key), version); - return true; -} - -bool IDBBackingStoreLevelDB::clearObjectStore(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::clearObjectStore"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - const Vector<char> startKey = KeyPrefix(databaseId, objectStoreId).encode(); - const Vector<char> stopKey = KeyPrefix(databaseId, objectStoreId + 1).encode(); - - deleteRange(levelDBTransaction, startKey, stopKey); - return true; -} - -bool IDBBackingStoreLevelDB::deleteRecord(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, const IDBRecordIdentifier& recordIdentifier) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::deleteRecord"); - - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - const Vector<char> objectStoreDataKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, recordIdentifier.encodedPrimaryKey()); - levelDBTransaction->remove(objectStoreDataKey); - - const Vector<char> existsEntryKey = ExistsEntryKey::encode(databaseId, objectStoreId, recordIdentifier.encodedPrimaryKey()); - levelDBTransaction->remove(existsEntryKey); - return true; -} - - -bool IDBBackingStoreLevelDB::getKeyGeneratorCurrentNumber(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t& keyGeneratorCurrentNumber) -{ - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - const Vector<char> keyGeneratorCurrentNumberKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber); - - keyGeneratorCurrentNumber = -1; - Vector<char> data; - - bool found = false; - bool ok = levelDBTransaction->safeGet(keyGeneratorCurrentNumberKey, data, found); - if (!ok) { - INTERNAL_READ_ERROR(GetKeyGeneratorCurrentNumber); - return false; - } - if (found) - keyGeneratorCurrentNumber = 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. - const Vector<char> startKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey()); - const Vector<char> stopKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey()); - - OwnPtr<LevelDBIterator> it = levelDBTransaction->createIterator(); - int64_t maxNumericKey = 0; - - for (it->seek(startKey); it->isValid() && compareKeys(it->key(), stopKey) < 0; it->next()) { - const char* p = it->key().begin(); - const char* limit = it->key().end(); - - ObjectStoreDataKey dataKey; - p = ObjectStoreDataKey::decode(p, limit, &dataKey); - ASSERT(p); - - if (dataKey.userKey()->type() == IDBKey::NumberType) { - int64_t n = static_cast<int64_t>(dataKey.userKey()->number()); - if (n > maxNumericKey) - maxNumericKey = n; - } - } - - keyGeneratorCurrentNumber = maxNumericKey + 1; - } - - return keyGeneratorCurrentNumber; -} - -bool IDBBackingStoreLevelDB::maybeUpdateKeyGeneratorCurrentNumber(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t newNumber, bool checkCurrent) -{ - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - if (checkCurrent) { - int64_t currentNumber; - bool ok = getKeyGeneratorCurrentNumber(transaction, databaseId, objectStoreId, currentNumber); - if (!ok) - return false; - if (newNumber <= currentNumber) - return true; - } - - const Vector<char> keyGeneratorCurrentNumberKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber); - putInt(levelDBTransaction, keyGeneratorCurrentNumberKey, newNumber); - return true; -} - -bool IDBBackingStoreLevelDB::keyExistsInObjectStore(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey& key, RefPtr<IDBRecordIdentifier>& foundIDBRecordIdentifier) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::keyExistsInObjectStore"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - bool found = false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - const Vector<char> leveldbKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, key); - Vector<char> data; - - bool ok = levelDBTransaction->safeGet(leveldbKey, data, found); - if (!ok) { - INTERNAL_READ_ERROR(KeyExistsInObjectStore); - return false; - } - if (!found) - return true; - - int64_t version; - if (!decodeVarInt(data.begin(), data.end(), version)) - return false; - - foundIDBRecordIdentifier = IDBRecordIdentifier::create(encodeIDBKey(key), version); - return true; -} - -static bool checkIndexAndMetaDataKey(const LevelDBIterator* it, const Vector<char>& stopKey, int64_t indexId, unsigned char metaDataType) -{ - if (!it->isValid() || compareKeys(it->key(), stopKey) >= 0) - return false; - - IndexMetaDataKey metaDataKey; - const char* p = IndexMetaDataKey::decode(it->key().begin(), it->key().end(), &metaDataKey); - ASSERT_UNUSED(p, p); - if (metaDataKey.indexId() != indexId) - return false; - if (metaDataKey.metaDataType() != metaDataType) - return false; - return true; -} - - -// FIXME: This should do some error handling rather than plowing ahead when bad data is encountered. -bool IDBBackingStoreLevelDB::getIndexes(int64_t databaseId, int64_t objectStoreId, IDBObjectStoreMetadata::IndexMap* indexes) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::getIndexes"); - if (!KeyPrefix::validIds(databaseId, objectStoreId)) - return false; - const Vector<char> startKey = IndexMetaDataKey::encode(databaseId, objectStoreId, 0, 0); - const Vector<char> stopKey = IndexMetaDataKey::encode(databaseId, objectStoreId + 1, 0, 0); - - ASSERT(indexes->isEmpty()); - - OwnPtr<LevelDBIterator> it = m_db->createIterator(); - it->seek(startKey); - while (it->isValid() && compareKeys(it->key(), stopKey) < 0) { - const char* p = it->key().begin(); - const char* limit = it->key().end(); - - IndexMetaDataKey metaDataKey; - p = IndexMetaDataKey::decode(p, limit, &metaDataKey); - ASSERT(p); - if (metaDataKey.metaDataType() != IndexMetaDataKey::Name) { - INTERNAL_CONSISTENCY_ERROR(GetIndexes); - // Possible stale metadata due to http://webkit.org/b/85557 but don't fail the load. - it->next(); - continue; - } - - // FIXME: Do this by direct key lookup rather than iteration, to simplify. - int64_t indexId = metaDataKey.indexId(); - String indexName = decodeString(it->value().begin(), it->value().end()); - - it->next(); // unique flag - if (!checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::Unique)) { - INTERNAL_CONSISTENCY_ERROR(GetIndexes); - break; - } - bool indexUnique = decodeBool(it->value().begin(), it->value().end()); - - it->next(); // keyPath - if (!checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::KeyPath)) { - INTERNAL_CONSISTENCY_ERROR(GetIndexes); - break; - } - IDBKeyPath keyPath = decodeIDBKeyPath(it->value().begin(), it->value().end()); - - it->next(); // [optional] multiEntry flag - bool indexMultiEntry = false; - if (checkIndexAndMetaDataKey(it.get(), stopKey, indexId, IndexMetaDataKey::MultiEntry)) { - indexMultiEntry = decodeBool(it->value().begin(), it->value().end()); - it->next(); - } - - indexes->set(indexId, IDBIndexMetadata(indexName, indexId, keyPath, indexUnique, indexMultiEntry)); - } - return true; -} - -WARN_UNUSED_RETURN static bool setMaxIndexId(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - int64_t maxIndexId = -1; - const Vector<char> maxIndexIdKey = ObjectStoreMetaDataKey::encode(databaseId, objectStoreId, ObjectStoreMetaDataKey::MaxIndexId); - bool found = false; - bool ok = getInt(transaction, maxIndexIdKey, maxIndexId, found); - if (!ok) { - INTERNAL_READ_ERROR(SetMaxIndexId); - return false; - } - if (!found) - maxIndexId = MinimumIndexId; - - if (indexId <= maxIndexId) { - INTERNAL_CONSISTENCY_ERROR(SetMaxIndexId); - return false; - } - - putInt(transaction, maxIndexIdKey, indexId); - return true; -} - -bool IDBBackingStoreLevelDB::createIndex(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath& keyPath, bool isUnique, bool isMultiEntry) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::createIndex"); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - if (!setMaxIndexId(levelDBTransaction, databaseId, objectStoreId, indexId)) - return false; - - const Vector<char> nameKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::Name); - const Vector<char> uniqueKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::Unique); - const Vector<char> keyPathKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::KeyPath); - const Vector<char> multiEntryKey = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, IndexMetaDataKey::MultiEntry); - - putString(levelDBTransaction, nameKey, name); - putBool(levelDBTransaction, uniqueKey, isUnique); - putIDBKeyPath(levelDBTransaction, keyPathKey, keyPath); - putBool(levelDBTransaction, multiEntryKey, isMultiEntry); - return true; -} - -bool IDBBackingStoreLevelDB::deleteIndex(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::deleteIndex"); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - - const Vector<char> indexMetaDataStart = IndexMetaDataKey::encode(databaseId, objectStoreId, indexId, 0); - const Vector<char> indexMetaDataEnd = IndexMetaDataKey::encodeMaxKey(databaseId, objectStoreId, indexId); - deleteRange(levelDBTransaction, indexMetaDataStart, indexMetaDataEnd); - - const Vector<char> indexDataStart = IndexDataKey::encodeMinKey(databaseId, objectStoreId, indexId); - const Vector<char> indexDataEnd = IndexDataKey::encodeMaxKey(databaseId, objectStoreId, indexId); - deleteRange(levelDBTransaction, indexDataStart, indexDataEnd); - return true; -} - -bool IDBBackingStoreLevelDB::putIndexDataForRecord(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, const IDBRecordIdentifier* recordIdentifier) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::putIndexDataForRecord"); - ASSERT(key.isValid()); - ASSERT(recordIdentifier); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - const Vector<char> indexDataKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, encodeIDBKey(key), recordIdentifier->encodedPrimaryKey()); - - Vector<char> data; - data.appendVector(encodeVarInt(recordIdentifier->version())); - data.appendVector(recordIdentifier->encodedPrimaryKey()); - - levelDBTransaction->put(indexDataKey, data); - return true; -} - -static bool findGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction, const Vector<char>& target, Vector<char>& foundKey) -{ - OwnPtr<LevelDBIterator> it = transaction->createIterator(); - it->seek(target); - - if (!it->isValid()) { - it->seekToLast(); - if (!it->isValid()) - return false; - } - - while (IDBBackingStoreLevelDB::compareIndexKeys(it->key(), target) > 0) { - it->prev(); - if (!it->isValid()) - return false; - } - - do { - foundKey.clear(); - foundKey.append(it->key().begin(), it->key().end() - it->key().begin()); - - // There can be several index keys that compare equal. We want the last one. - it->next(); - } while (it->isValid() && !IDBBackingStoreLevelDB::compareIndexKeys(it->key(), target)); - - return true; -} - -static bool versionExists(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t version, const Vector<char>& encodedPrimaryKey, bool& exists) -{ - const Vector<char> key = ExistsEntryKey::encode(databaseId, objectStoreId, encodedPrimaryKey); - Vector<char> data; - - bool ok = transaction->safeGet(key, data, exists); - if (!ok) { - INTERNAL_READ_ERROR(VersionExists); - return false; - } - if (!exists) - return true; - - exists = (decodeInt(data.begin(), data.end()) == version); - return true; -} - -bool IDBBackingStoreLevelDB::findKeyInIndex(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, Vector<char>& foundEncodedPrimaryKey, bool& found) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::findKeyInIndex"); - ASSERT(KeyPrefix::validIds(databaseId, objectStoreId, indexId)); - - ASSERT(foundEncodedPrimaryKey.isEmpty()); - found = false; - - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - const Vector<char> leveldbKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, key); - OwnPtr<LevelDBIterator> it = levelDBTransaction->createIterator(); - it->seek(leveldbKey); - - for (;;) { - if (!it->isValid()) - return true; - if (compareIndexKeys(it->key(), leveldbKey) > 0) - return true; - - int64_t version; - const char* p = decodeVarInt(it->value().begin(), it->value().end(), version); - if (!p) { - INTERNAL_READ_ERROR(FindKeyInIndex); - return false; - } - foundEncodedPrimaryKey.append(p, it->value().end() - p); - - bool exists = false; - bool ok = versionExists(levelDBTransaction, databaseId, objectStoreId, version, foundEncodedPrimaryKey, exists); - if (!ok) - return false; - if (!exists) { - // Delete stale index data entry and continue. - levelDBTransaction->remove(it->key()); - it->next(); - continue; - } - found = true; - return true; - } -} - -bool IDBBackingStoreLevelDB::getPrimaryKeyViaIndex(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& key, RefPtr<IDBKey>& primaryKey) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::getPrimaryKeyViaIndex"); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - - bool found = false; - Vector<char> foundEncodedPrimaryKey; - bool ok = findKeyInIndex(transaction, databaseId, objectStoreId, indexId, key, foundEncodedPrimaryKey, found); - if (!ok) { - INTERNAL_READ_ERROR(GetPrimaryKeyViaIndex); - return false; - } - if (found) { - decodeIDBKey(foundEncodedPrimaryKey.begin(), foundEncodedPrimaryKey.end(), primaryKey); - return true; - } - - return true; -} - -bool IDBBackingStoreLevelDB::keyExistsInIndex(IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& indexKey, RefPtr<IDBKey>& foundPrimaryKey, bool& exists) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::keyExistsInIndex"); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - - exists = false; - Vector<char> foundEncodedPrimaryKey; - bool ok = findKeyInIndex(transaction, databaseId, objectStoreId, indexId, indexKey, foundEncodedPrimaryKey, exists); - if (!ok) { - INTERNAL_READ_ERROR(KeyExistsInIndex); - return false; - } - if (!exists) - return true; - - decodeIDBKey(foundEncodedPrimaryKey.begin(), foundEncodedPrimaryKey.end(), foundPrimaryKey); - return true; -} - - -bool IDBBackingStoreLevelDB::makeIndexWriters(int64_t transactionID, int64_t databaseID, const IDBObjectStoreMetadata& objectStore, IDBKey& primaryKey, bool keyWasGenerated, const Vector<int64_t>& indexIDs, const Vector<Vector<RefPtr<IDBKey>>>& indexKeys, Vector<RefPtr<IDBIndexWriterLevelDB>>& indexWriters, String* errorMessage, bool& completed) -{ - ASSERT(indexIDs.size() == indexKeys.size()); - completed = false; - - HashMap<int64_t, IndexKeys> indexKeyMap; - for (size_t i = 0; i < indexIDs.size(); ++i) - indexKeyMap.add(indexIDs[i], indexKeys[i]); - - for (IDBObjectStoreMetadata::IndexMap::const_iterator it = objectStore.indexes.begin(); it != objectStore.indexes.end(); ++it) { - const IDBIndexMetadata& index = it->value; - - IndexKeys keys = indexKeyMap.get(it->key); - // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key. - if (keyWasGenerated && (index.keyPath == objectStore.keyPath)) - keys.append(&primaryKey); - - RefPtr<IDBIndexWriterLevelDB> indexWriter = IDBIndexWriterLevelDB::create(index, keys); - bool canAddKeys = false; - ASSERT(m_backingStoreTransactions.contains(transactionID)); - bool backingStoreSuccess = indexWriter->verifyIndexKeys(*this, *m_backingStoreTransactions.get(transactionID), databaseID, objectStore.id, index.id, canAddKeys, &primaryKey, errorMessage); - if (!backingStoreSuccess) - return false; - if (!canAddKeys) - return true; - - indexWriters.append(indexWriter.release()); - } - - completed = true; - return true; -} - -PassRefPtr<IDBKey> IDBBackingStoreLevelDB::generateKey(IDBTransactionBackend& transaction, int64_t databaseId, int64_t objectStoreId) -{ - const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number. - int64_t currentNumber; - ASSERT(m_backingStoreTransactions.contains(transaction.id())); - bool ok = getKeyGeneratorCurrentNumber(*m_backingStoreTransactions.get(transaction.id()), databaseId, objectStoreId, currentNumber); - if (!ok) { - LOG_ERROR("Failed to getKeyGeneratorCurrentNumber"); - return IDBKey::createInvalid(); - } - if (currentNumber < 0 || currentNumber > maxGeneratorValue) - return IDBKey::createInvalid(); - - return IDBKey::createNumber(currentNumber); -} - - -bool IDBBackingStoreLevelDB::updateKeyGenerator(IDBTransactionBackend& transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey& key, bool checkCurrent) -{ - ASSERT(key.type() == IDBKey::NumberType); - ASSERT(m_backingStoreTransactions.contains(transaction.id())); - - return maybeUpdateKeyGeneratorCurrentNumber(*m_backingStoreTransactions.get(transaction.id()), databaseId, objectStoreId, static_cast<int64_t>(floor(key.number())) + 1, checkCurrent); -} - -class ObjectStoreKeyCursorImpl : public IDBBackingStoreCursorLevelDB { -public: - static PassRefPtr<ObjectStoreKeyCursorImpl> create(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - { - return adoptRef(new ObjectStoreKeyCursorImpl(cursorID, transaction, cursorOptions)); - } - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> clone() - { - return adoptRef(new ObjectStoreKeyCursorImpl(this)); - } - - // IDBBackingStoreCursorLevelDB - virtual PassRefPtr<SharedBuffer> value() const override { ASSERT_NOT_REACHED(); return 0; } - virtual bool loadCurrentRow() override; - -protected: - virtual Vector<char> encodeKey(const IDBKey &key) - { - return ObjectStoreDataKey::encode(m_cursorOptions.databaseId, m_cursorOptions.objectStoreId, key); - } - -private: - ObjectStoreKeyCursorImpl(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - : IDBBackingStoreCursorLevelDB(cursorID, transaction, cursorOptions) - { - } - - ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other) - : IDBBackingStoreCursorLevelDB(other) - { - } -}; - -bool ObjectStoreKeyCursorImpl::loadCurrentRow() -{ - const char* keyPosition = m_iterator->key().begin(); - const char* keyLimit = m_iterator->key().end(); - - ObjectStoreDataKey objectStoreDataKey; - keyPosition = ObjectStoreDataKey::decode(keyPosition, keyLimit, &objectStoreDataKey); - if (!keyPosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - m_currentKey = objectStoreDataKey.userKey(); - - int64_t version; - const char* valuePosition = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), version); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - // FIXME: This re-encodes what was just decoded; try and optimize. - m_recordIdentifier->reset(encodeIDBKey(*m_currentKey), version); - - return true; -} - -class ObjectStoreCursorImpl : public IDBBackingStoreCursorLevelDB { -public: - static PassRefPtr<ObjectStoreCursorImpl> create(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - { - return adoptRef(new ObjectStoreCursorImpl(cursorID, transaction, cursorOptions)); - } - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> clone() - { - return adoptRef(new ObjectStoreCursorImpl(this)); - } - - // IDBBackingStoreCursorLevelDB - virtual PassRefPtr<SharedBuffer> value() const override { return m_currentValue; } - virtual bool loadCurrentRow() override; - -protected: - virtual Vector<char> encodeKey(const IDBKey &key) - { - return ObjectStoreDataKey::encode(m_cursorOptions.databaseId, m_cursorOptions.objectStoreId, key); - } - -private: - ObjectStoreCursorImpl(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - : IDBBackingStoreCursorLevelDB(cursorID, transaction, cursorOptions) - { - } - - ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other) - : IDBBackingStoreCursorLevelDB(other) - , m_currentValue(other->m_currentValue) - { - } - - RefPtr<SharedBuffer> m_currentValue; -}; - -bool ObjectStoreCursorImpl::loadCurrentRow() -{ - const char* keyPosition = m_iterator->key().begin(); - const char* keyLimit = m_iterator->key().end(); - - ObjectStoreDataKey objectStoreDataKey; - keyPosition = ObjectStoreDataKey::decode(keyPosition, keyLimit, &objectStoreDataKey); - if (!keyPosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - m_currentKey = objectStoreDataKey.userKey(); - - int64_t version; - const char* valuePosition = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), version); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - // FIXME: This re-encodes what was just decoded; try and optimize. - m_recordIdentifier->reset(encodeIDBKey(*m_currentKey), version); - - Vector<char> value; - value.append(valuePosition, m_iterator->value().end() - valuePosition); - m_currentValue = SharedBuffer::adoptVector(value); - return true; -} - -class IndexKeyCursorImpl final : public IDBBackingStoreCursorLevelDB { -public: - static PassRefPtr<IndexKeyCursorImpl> create(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - { - return adoptRef(new IndexKeyCursorImpl(cursorID, transaction, cursorOptions)); - } - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> clone() - { - return adoptRef(new IndexKeyCursorImpl(this)); - } - - // IDBBackingStoreCursorLevelDB - virtual PassRefPtr<SharedBuffer> value() const override { ASSERT_NOT_REACHED(); return 0; } - virtual PassRefPtr<IDBKey> primaryKey() const override { return m_primaryKey; } - virtual const IDBRecordIdentifier& recordIdentifier() const override { ASSERT_NOT_REACHED(); return *m_recordIdentifier; } - virtual bool loadCurrentRow() override; - -protected: - virtual Vector<char> encodeKey(const IDBKey &key) - { - return IndexDataKey::encode(m_cursorOptions.databaseId, m_cursorOptions.objectStoreId, m_cursorOptions.indexId, key); - } - -private: - IndexKeyCursorImpl(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - : IDBBackingStoreCursorLevelDB(cursorID, transaction, cursorOptions) - { - } - - IndexKeyCursorImpl(const IndexKeyCursorImpl* other) - : IDBBackingStoreCursorLevelDB(other) - , m_primaryKey(other->m_primaryKey) - { - } - - RefPtr<IDBKey> m_primaryKey; -}; - -bool IndexKeyCursorImpl::loadCurrentRow() -{ - const char* keyPosition = m_iterator->key().begin(); - const char* keyLimit = m_iterator->key().end(); - - IndexDataKey indexDataKey; - keyPosition = IndexDataKey::decode(keyPosition, keyLimit, &indexDataKey); - - m_currentKey = indexDataKey.userKey(); - - int64_t indexDataVersion; - const char* valuePosition = decodeVarInt(m_iterator->value().begin(), m_iterator->value().end(), indexDataVersion); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - valuePosition = decodeIDBKey(valuePosition, m_iterator->value().end(), m_primaryKey); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - Vector<char> primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey); - - Vector<char> result; - bool found = false; - bool ok = m_transaction->safeGet(primaryLevelDBKey, result, found); - if (!ok) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - if (!found) { - m_transaction->remove(m_iterator->key()); - return false; - } - - int64_t objectStoreDataVersion; - const char* t = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion); - if (!t) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - if (objectStoreDataVersion != indexDataVersion) { - m_transaction->remove(m_iterator->key()); - return false; - } - - return true; -} - -class IndexCursorImpl final : public IDBBackingStoreCursorLevelDB { -public: - static PassRefPtr<IndexCursorImpl> create(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - { - return adoptRef(new IndexCursorImpl(cursorID, transaction, cursorOptions)); - } - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> clone() - { - return adoptRef(new IndexCursorImpl(this)); - } - - // IDBBackingStoreCursorLevelDB - virtual PassRefPtr<SharedBuffer> value() const override { return m_currentValue; } - virtual PassRefPtr<IDBKey> primaryKey() const override { return m_primaryKey; } - virtual const IDBRecordIdentifier& recordIdentifier() const override { ASSERT_NOT_REACHED(); return *m_recordIdentifier; } - virtual bool loadCurrentRow() override; - -protected: - virtual Vector<char> encodeKey(const IDBKey &key) - { - return IndexDataKey::encode(m_cursorOptions.databaseId, m_cursorOptions.objectStoreId, m_cursorOptions.indexId, key); - } - -private: - IndexCursorImpl(int64_t cursorID, LevelDBTransaction* transaction, const IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) - : IDBBackingStoreCursorLevelDB(cursorID, transaction, cursorOptions) - { - } - - IndexCursorImpl(const IndexCursorImpl* other) - : IDBBackingStoreCursorLevelDB(other) - , m_primaryKey(other->m_primaryKey) - , m_currentValue(other->m_currentValue) - , m_primaryLevelDBKey(other->m_primaryLevelDBKey) - { - } - - RefPtr<IDBKey> m_primaryKey; - RefPtr<SharedBuffer> m_currentValue; - Vector<char> m_primaryLevelDBKey; -}; - -bool IndexCursorImpl::loadCurrentRow() -{ - const char* keyPosition = m_iterator->key().begin(); - const char* keyLimit = m_iterator->key().end(); - - IndexDataKey indexDataKey; - keyPosition = IndexDataKey::decode(keyPosition, keyLimit, &indexDataKey); - - m_currentKey = indexDataKey.userKey(); - - const char* valuePosition = m_iterator->value().begin(); - const char* valueLimit = m_iterator->value().end(); - - int64_t indexDataVersion; - valuePosition = decodeVarInt(valuePosition, valueLimit, indexDataVersion); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - valuePosition = decodeIDBKey(valuePosition, valueLimit, m_primaryKey); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - m_primaryLevelDBKey = ObjectStoreDataKey::encode(indexDataKey.databaseId(), indexDataKey.objectStoreId(), *m_primaryKey); - - Vector<char> result; - bool found = false; - bool ok = m_transaction->safeGet(m_primaryLevelDBKey, result, found); - if (!ok) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - if (!found) { - m_transaction->remove(m_iterator->key()); - return false; - } - - int64_t objectStoreDataVersion; - valuePosition = decodeVarInt(result.begin(), result.end(), objectStoreDataVersion); - if (!valuePosition) { - INTERNAL_READ_ERROR(LoadCurrentRow); - return false; - } - - if (objectStoreDataVersion != indexDataVersion) { - m_transaction->remove(m_iterator->key()); - return false; - } - - Vector<char> value; - value.append(valuePosition, result.end() - valuePosition); - m_currentValue = SharedBuffer::adoptVector(value); - return true; -} - -static bool objectStoreCursorOptions(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, const IDBKeyRange* range, IndexedDB::CursorDirection direction, IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) -{ - cursorOptions.databaseId = databaseId; - cursorOptions.objectStoreId = objectStoreId; - - bool lowerBound = range && range->lower(); - bool upperBound = range && range->upper(); - cursorOptions.forward = (direction == IndexedDB::CursorDirection::NextNoDuplicate || direction == IndexedDB::CursorDirection::Next); - cursorOptions.unique = (direction == IndexedDB::CursorDirection::NextNoDuplicate || direction == IndexedDB::CursorDirection::PrevNoDuplicate); - - if (!lowerBound) { - cursorOptions.lowKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, minIDBKey()); - cursorOptions.lowOpen = true; // Not included. - } else { - cursorOptions.lowKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->lower()); - cursorOptions.lowOpen = range->lowerOpen(); - } - - if (!upperBound) { - cursorOptions.highKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, maxIDBKey()); - - if (cursorOptions.forward) - cursorOptions.highOpen = true; // Not included. - else { - // We need a key that exists. - if (!findGreatestKeyLessThanOrEqual(transaction, cursorOptions.highKey, cursorOptions.highKey)) - return false; - cursorOptions.highOpen = false; - } - } else { - cursorOptions.highKey = ObjectStoreDataKey::encode(databaseId, objectStoreId, *range->upper()); - cursorOptions.highOpen = range->upperOpen(); - - if (!cursorOptions.forward) { - // For reverse cursors, we need a key that exists. - Vector<char> foundHighKey; - if (!findGreatestKeyLessThanOrEqual(transaction, cursorOptions.highKey, foundHighKey)) - return false; - - // If the target key should not be included, but we end up with a smaller key, we should include that. - if (cursorOptions.highOpen && IDBBackingStoreLevelDB::compareIndexKeys(foundHighKey, cursorOptions.highKey) < 0) - cursorOptions.highOpen = false; - - cursorOptions.highKey = foundHighKey; - } - } - - return true; -} - -static bool indexCursorOptions(LevelDBTransaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IndexedDB::CursorDirection direction, IDBBackingStoreCursorLevelDB::CursorOptions& cursorOptions) -{ - ASSERT(transaction); - if (!KeyPrefix::validIds(databaseId, objectStoreId, indexId)) - return false; - - cursorOptions.databaseId = databaseId; - cursorOptions.objectStoreId = objectStoreId; - cursorOptions.indexId = indexId; - - bool lowerBound = range && range->lower(); - bool upperBound = range && range->upper(); - cursorOptions.forward = (direction == IndexedDB::CursorDirection::NextNoDuplicate || direction == IndexedDB::CursorDirection::Next); - cursorOptions.unique = (direction == IndexedDB::CursorDirection::NextNoDuplicate || direction == IndexedDB::CursorDirection::PrevNoDuplicate); - - if (!lowerBound) { - cursorOptions.lowKey = IndexDataKey::encodeMinKey(databaseId, objectStoreId, indexId); - cursorOptions.lowOpen = false; // Included. - } else { - cursorOptions.lowKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->lower()); - cursorOptions.lowOpen = range->lowerOpen(); - } - - if (!upperBound) { - cursorOptions.highKey = IndexDataKey::encodeMaxKey(databaseId, objectStoreId, indexId); - cursorOptions.highOpen = false; // Included. - - if (!cursorOptions.forward) { // We need a key that exists. - if (!findGreatestKeyLessThanOrEqual(transaction, cursorOptions.highKey, cursorOptions.highKey)) - return false; - cursorOptions.highOpen = false; - } - } else { - cursorOptions.highKey = IndexDataKey::encode(databaseId, objectStoreId, indexId, *range->upper()); - cursorOptions.highOpen = range->upperOpen(); - - Vector<char> foundHighKey; - if (!findGreatestKeyLessThanOrEqual(transaction, cursorOptions.highKey, foundHighKey)) // 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 (cursorOptions.highOpen && IDBBackingStoreLevelDB::compareIndexKeys(foundHighKey, cursorOptions.highKey) < 0) - cursorOptions.highOpen = false; - - cursorOptions.highKey = foundHighKey; - } - - return true; -} -PassRefPtr<IDBBackingStoreCursorLevelDB> IDBBackingStoreLevelDB::openObjectStoreCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseID, int64_t objectStoreId, const IDBKeyRange* range, IndexedDB::CursorDirection direction) - -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::openObjectStoreCursor"); - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - IDBBackingStoreCursorLevelDB::CursorOptions cursorOptions; - if (!objectStoreCursorOptions(levelDBTransaction, databaseID, objectStoreId, range, direction, cursorOptions)) - return 0; - RefPtr<ObjectStoreCursorImpl> cursor = ObjectStoreCursorImpl::create(cursorID, levelDBTransaction, cursorOptions); - if (!cursor->firstSeek()) - return 0; - - return cursor.release(); -} - -PassRefPtr<IDBBackingStoreCursorLevelDB> IDBBackingStoreLevelDB::openObjectStoreKeyCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseID, int64_t objectStoreId, const IDBKeyRange* range, IndexedDB::CursorDirection direction) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::openObjectStoreKeyCursor"); - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - IDBBackingStoreCursorLevelDB::CursorOptions cursorOptions; - if (!objectStoreCursorOptions(levelDBTransaction, databaseID, objectStoreId, range, direction, cursorOptions)) - return 0; - RefPtr<ObjectStoreKeyCursorImpl> cursor = ObjectStoreKeyCursorImpl::create(cursorID, levelDBTransaction, cursorOptions); - if (!cursor->firstSeek()) - return 0; - - return cursor.release(); -} - -PassRefPtr<IDBBackingStoreCursorLevelDB> IDBBackingStoreLevelDB::openIndexKeyCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseID, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IndexedDB::CursorDirection direction) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::openIndexKeyCursor"); - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - IDBBackingStoreCursorLevelDB::CursorOptions cursorOptions; - if (!indexCursorOptions(levelDBTransaction, databaseID, objectStoreId, indexId, range, direction, cursorOptions)) - return 0; - RefPtr<IndexKeyCursorImpl> cursor = IndexKeyCursorImpl::create(cursorID, levelDBTransaction, cursorOptions); - if (!cursor->firstSeek()) - return 0; - - return cursor.release(); -} - -PassRefPtr<IDBBackingStoreCursorLevelDB> IDBBackingStoreLevelDB::openIndexCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseID, int64_t objectStoreId, int64_t indexId, const IDBKeyRange* range, IndexedDB::CursorDirection direction) -{ - LOG(StorageAPI, "IDBBackingStoreLevelDB::openIndexCursor"); - LevelDBTransaction* levelDBTransaction = IDBBackingStoreTransactionLevelDB::levelDBTransactionFrom(transaction); - IDBBackingStoreCursorLevelDB::CursorOptions cursorOptions; - if (!indexCursorOptions(levelDBTransaction, databaseID, objectStoreId, indexId, range, direction, cursorOptions)) - return 0; - RefPtr<IndexCursorImpl> cursor = IndexCursorImpl::create(cursorID, levelDBTransaction, cursorOptions); - if (!cursor->firstSeek()) - return 0; - - return cursor.release(); -} - -void IDBBackingStoreLevelDB::establishBackingStoreTransaction(int64_t transactionID) -{ - ASSERT(!m_backingStoreTransactions.contains(transactionID)); - m_backingStoreTransactions.set(transactionID, IDBBackingStoreTransactionLevelDB::create(transactionID, this)); -} - -void IDBBackingStoreLevelDB::removeBackingStoreTransaction(IDBBackingStoreTransactionLevelDB* transaction) -{ - ASSERT(m_backingStoreTransactions.contains(transaction->transactionID())); - m_backingStoreTransactions.remove(transaction->transactionID()); -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h deleted file mode 100644 index 9ef75e45c..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBBackingStoreLevelDB_h -#define IDBBackingStoreLevelDB_h - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "IDBBackingStoreCursorLevelDB.h" -#include "IDBBackingStoreTransactionLevelDB.h" -#include "IDBDatabaseMetadata.h" -#include "IDBKey.h" -#include "IDBRecordIdentifier.h" -#include "IndexedDB.h" -#include "LevelDBIterator.h" -#include "LevelDBTransaction.h" -#include <functional> -#include <wtf/OwnPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/WeakPtr.h> - -namespace WebCore { - -class LevelDBComparator; -class LevelDBDatabase; -class LevelDBTransaction; -class IDBIndexWriterLevelDB; -class IDBKey; -class IDBKeyRange; -class IDBTransactionBackend; -class SecurityOrigin; -class SharedBuffer; - -class LevelDBFactory { -public: - virtual ~LevelDBFactory() { } - virtual PassOwnPtr<LevelDBDatabase> openLevelDB(const String& fileName, const LevelDBComparator*) = 0; - virtual bool destroyLevelDB(const String& fileName) = 0; -}; - -class IDBBackingStoreLevelDB : public RefCounted<IDBBackingStoreLevelDB> { -public: - class Transaction; - - virtual ~IDBBackingStoreLevelDB(); - static PassRefPtr<IDBBackingStoreLevelDB> open(const SecurityOrigin&, const String& pathBase, const String& fileIdentifier); - static PassRefPtr<IDBBackingStoreLevelDB> open(const SecurityOrigin&, const String& pathBase, const String& fileIdentifier, LevelDBFactory*); - static PassRefPtr<IDBBackingStoreLevelDB> openInMemory(const String& identifier); - static PassRefPtr<IDBBackingStoreLevelDB> openInMemory(const String& identifier, LevelDBFactory*); - WeakPtr<IDBBackingStoreLevelDB> createWeakPtr() { return m_weakFactory.createWeakPtr(); } - - void establishBackingStoreTransaction(int64_t transactionID); - - Vector<String> getDatabaseNames(); - - // New-style asynchronous callbacks - void getOrEstablishIDBDatabaseMetadata(const String& name, std::function<void (const IDBDatabaseMetadata&, bool success)> callbackFunction); - void deleteDatabase(const String& name, std::function<void (bool success)> successCallback); - - // Old-style synchronous callbacks - bool updateIDBDatabaseVersion(IDBBackingStoreTransactionLevelDB&, int64_t rowId, uint64_t version); - - bool createObjectStore(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, const String& name, const IDBKeyPath&, bool autoIncrement); - bool deleteObjectStore(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId) WARN_UNUSED_RETURN; - - bool getRecord(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, const IDBKey&, Vector<char>& record) WARN_UNUSED_RETURN; - bool putRecord(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, const IDBKey&, PassRefPtr<SharedBuffer> value, IDBRecordIdentifier*) WARN_UNUSED_RETURN; - bool clearObjectStore(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId) WARN_UNUSED_RETURN; - bool deleteRecord(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, const IDBRecordIdentifier&) WARN_UNUSED_RETURN; - bool getKeyGeneratorCurrentNumber(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t& currentNumber) WARN_UNUSED_RETURN; - bool maybeUpdateKeyGeneratorCurrentNumber(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t newState, bool checkCurrent) WARN_UNUSED_RETURN; - bool keyExistsInObjectStore(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, const IDBKey&, RefPtr<IDBRecordIdentifier>& foundIDBRecordIdentifier) WARN_UNUSED_RETURN; - - bool createIndex(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath&, bool isUnique, bool isMultiEntry) WARN_UNUSED_RETURN; - bool deleteIndex(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId) WARN_UNUSED_RETURN; - bool putIndexDataForRecord(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&, const IDBRecordIdentifier*) WARN_UNUSED_RETURN; - bool getPrimaryKeyViaIndex(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&, RefPtr<IDBKey>& primaryKey) WARN_UNUSED_RETURN; - bool keyExistsInIndex(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& indexKey, RefPtr<IDBKey>& foundPrimaryKey, bool& exists) WARN_UNUSED_RETURN; - - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> openObjectStoreKeyCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB&, int64_t databaseID, int64_t objectStoreId, const IDBKeyRange*, IndexedDB::CursorDirection); - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> openObjectStoreCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB&, int64_t databaseID, int64_t objectStoreId, const IDBKeyRange*, IndexedDB::CursorDirection); - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> openIndexKeyCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB&, int64_t databaseID, int64_t objectStoreId, int64_t indexId, const IDBKeyRange*, IndexedDB::CursorDirection); - virtual PassRefPtr<IDBBackingStoreCursorLevelDB> openIndexCursor(int64_t cursorID, IDBBackingStoreTransactionLevelDB&, int64_t databaseID, int64_t objectStoreId, int64_t indexId, const IDBKeyRange*, IndexedDB::CursorDirection); - - bool makeIndexWriters(int64_t transactionID, int64_t databaseId, const IDBObjectStoreMetadata&, IDBKey& primaryKey, bool keyWasGenerated, const Vector<int64_t>& indexIds, const Vector<Vector<RefPtr<IDBKey>>>&, Vector<RefPtr<IDBIndexWriterLevelDB>>& indexWriters, String* errorMessage, bool& completed) WARN_UNUSED_RETURN; - - virtual PassRefPtr<IDBKey> generateKey(IDBTransactionBackend&, int64_t databaseId, int64_t objectStoreId); - bool updateKeyGenerator(IDBTransactionBackend&, int64_t databaseId, int64_t objectStoreId, const IDBKey&, bool checkCurrent); - - LevelDBDatabase* levelDBDatabase() { return m_db.get(); } - - static int compareIndexKeys(const LevelDBSlice&, const LevelDBSlice&); - - void removeBackingStoreTransaction(IDBBackingStoreTransactionLevelDB*); - -private: - IDBBackingStoreLevelDB(const String& identifier, PassOwnPtr<LevelDBDatabase>, PassOwnPtr<LevelDBComparator>); - static PassRefPtr<IDBBackingStoreLevelDB> create(const String& identifier, PassOwnPtr<LevelDBDatabase>, PassOwnPtr<LevelDBComparator>); - - // FIXME: LevelDB needs to support uint64_t as the version type. - bool createIDBDatabaseMetaData(IDBDatabaseMetadata&); - bool getIDBDatabaseMetaData(const String& name, IDBDatabaseMetadata*, bool& success) WARN_UNUSED_RETURN; - bool getObjectStores(int64_t databaseId, IDBDatabaseMetadata::ObjectStoreMap* objectStores) WARN_UNUSED_RETURN; - - bool findKeyInIndex(IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&, Vector<char>& foundEncodedPrimaryKey, bool& found); - bool getIndexes(int64_t databaseId, int64_t objectStoreId, IDBObjectStoreMetadata::IndexMap*) WARN_UNUSED_RETURN; - - String m_identifier; - - OwnPtr<LevelDBDatabase> m_db; - OwnPtr<LevelDBComparator> m_comparator; - WeakPtrFactory<IDBBackingStoreLevelDB> m_weakFactory; - - HashMap<int64_t, RefPtr<IDBBackingStoreTransactionLevelDB>> m_backingStoreTransactions; -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#endif // IDBBackingStoreLevelDB_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.cpp deleted file mode 100644 index a7a5f66fa..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBBackingStoreTransactionLevelDB.h" - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "HistogramSupport.h" -#include "IDBBackingStoreLevelDB.h" -#include "Logging.h" -#include <wtf/text/CString.h> - -namespace WebCore { - -IDBBackingStoreTransactionLevelDB::IDBBackingStoreTransactionLevelDB(int64_t transactionID, IDBBackingStoreLevelDB* backingStore) - : m_transactionID(transactionID) - , m_backingStore(backingStore) -{ -} - -IDBBackingStoreTransactionLevelDB::~IDBBackingStoreTransactionLevelDB() -{ - if (m_backingStore) - m_backingStore->removeBackingStoreTransaction(this); -} - -void IDBBackingStoreTransactionLevelDB::begin() -{ - LOG(StorageAPI, "IDBBackingStoreTransactionLevelDB::begin"); - ASSERT(!m_transaction); - m_transaction = LevelDBTransaction::create(reinterpret_cast<IDBBackingStoreLevelDB*>(m_backingStore)->levelDBDatabase()); -} - -bool IDBBackingStoreTransactionLevelDB::commit() -{ - LOG(StorageAPI, "IDBBackingStoreTransactionLevelDB::commit"); - ASSERT(m_transaction); - bool result = m_transaction->commit(); - m_transaction.clear(); - if (!result) - LOG_ERROR("IndexedDB TransactionCommit Error"); - return result; -} - -void IDBBackingStoreTransactionLevelDB::rollback() -{ - LOG(StorageAPI, "IDBBackingStoreTransactionLevelDB::rollback"); - ASSERT(m_transaction); - m_transaction->rollback(); - m_transaction.clear(); -} - -void IDBBackingStoreTransactionLevelDB::resetTransaction() -{ - ASSERT(m_backingStore); - m_backingStore->removeBackingStoreTransaction(this); - m_backingStore = 0; - m_transaction = 0; -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.h deleted file mode 100644 index c7f7bc494..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreTransactionLevelDB.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBBackingStoreTransactionLevelDB_h -#define IDBBackingStoreTransactionLevelDB_h - -#include "LevelDBTransaction.h" - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -namespace WebCore { - -class IDBBackingStoreLevelDB; - -class IDBBackingStoreTransactionLevelDB : public RefCounted<IDBBackingStoreTransactionLevelDB> { -public: - static PassRefPtr<IDBBackingStoreTransactionLevelDB> create(int64_t transactionID, IDBBackingStoreLevelDB* backingStore) - { - return adoptRef(new IDBBackingStoreTransactionLevelDB(transactionID, backingStore)); - } - - ~IDBBackingStoreTransactionLevelDB(); - - void begin(); - bool commit(); - void rollback(); - void resetTransaction(); - - static LevelDBTransaction* levelDBTransactionFrom(IDBBackingStoreTransactionLevelDB& transaction) - { - return static_cast<IDBBackingStoreTransactionLevelDB&>(transaction).m_transaction.get(); - } - - int64_t transactionID() { return m_transactionID; } - -private: - IDBBackingStoreTransactionLevelDB(int64_t transactionID, IDBBackingStoreLevelDB*); - - int64_t m_transactionID; - IDBBackingStoreLevelDB* m_backingStore; - RefPtr<LevelDBTransaction> m_transaction; -}; - -} // namespace WebCore - -#endif // USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) -#endif // IDBBackingStoreTransactionLevelDB_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.cpp deleted file mode 100644 index 3541fa88c..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBFactoryBackendLevelDB.h" - -#include "DOMStringList.h" -#include "IDBBackingStoreLevelDB.h" -#include "IDBCursorBackend.h" -#include "IDBDatabaseBackend.h" -#include "IDBDatabaseException.h" -#include "IDBServerConnectionLevelDB.h" -#include "IDBTransactionBackend.h" -#include "IDBTransactionCoordinator.h" -#include "Logging.h" -#include "SecurityOrigin.h" - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -namespace WebCore { - -template<typename K, typename M> -static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map) -{ - HashMap<K, WeakPtr<M> > other; - other.swap(map); - - typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin(); - while (iter != other.end()) { - if (iter->value.get()) - map.set(iter->key, iter->value); - ++iter; - } -} - -static String computeFileIdentifier(const SecurityOrigin& securityOrigin) -{ - static const char levelDBFileSuffix[] = "@1"; - return securityOrigin.databaseIdentifier() + levelDBFileSuffix; -} - -static String computeUniqueIdentifier(const String& name, const SecurityOrigin& securityOrigin) -{ - return computeFileIdentifier(securityOrigin) + name; -} - -IDBFactoryBackendLevelDB::IDBFactoryBackendLevelDB(const String& databaseDirectory) - : m_databaseDirectory(databaseDirectory) -{ -} - -IDBFactoryBackendLevelDB::~IDBFactoryBackendLevelDB() -{ -} - -void IDBFactoryBackendLevelDB::removeIDBDatabaseBackend(const String& uniqueIdentifier) -{ - ASSERT(m_databaseBackendMap.contains(uniqueIdentifier)); - m_databaseBackendMap.remove(uniqueIdentifier); -} - -void IDBFactoryBackendLevelDB::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory) -{ - ASSERT(securityOrigin); - LOG(StorageAPI, "IDBFactoryBackendLevelDB::getDatabaseNames"); - RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory); - if (!backingStore) { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.webkitGetDatabaseNames.")); - return; - } - - RefPtr<DOMStringList> databaseNames = DOMStringList::create(); - - Vector<String> foundNames = backingStore->getDatabaseNames(); - for (Vector<String>::const_iterator it = foundNames.begin(); it != foundNames.end(); ++it) - databaseNames->append(*it); - - callbacks->onSuccess(databaseNames.release()); -} - -void IDBFactoryBackendLevelDB::deleteDatabase(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory) -{ - LOG(StorageAPI, "IDBFactoryBackendLevelDB::deleteDatabase"); - const String uniqueIdentifier = computeUniqueIdentifier(name, *securityOrigin); - - IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier); - if (it != m_databaseBackendMap.end()) { - // If there are any connections to the database, directly delete the - // database. - it->value->deleteDatabase(callbacks); - return; - } - - // FIXME: Everything from now on should be done on another thread. - RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(*securityOrigin, dataDirectory); - if (!backingStore) { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.deleteDatabase.")); - return; - } - - RefPtr<IDBServerConnection> serverConnection = IDBServerConnectionLevelDB::create(name, backingStore.get()); - RefPtr<IDBDatabaseBackend> databaseBackend = IDBDatabaseBackend::create(name, uniqueIdentifier, this, *serverConnection); - if (databaseBackend) { - m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); - databaseBackend->deleteDatabase(callbacks); - m_databaseBackendMap.remove(uniqueIdentifier); - } else - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexedDB.deleteDatabase.")); -} - -PassRefPtr<IDBBackingStoreLevelDB> IDBFactoryBackendLevelDB::openBackingStore(const SecurityOrigin& securityOrigin, const String& dataDirectory) -{ - const String fileIdentifier = computeFileIdentifier(securityOrigin); - const bool openInMemory = dataDirectory.isEmpty(); - - IDBBackingStoreLevelDBMap::iterator it2 = m_backingStoreMap.find(fileIdentifier); - if (it2 != m_backingStoreMap.end() && it2->value.get()) - return it2->value.get(); - - RefPtr<IDBBackingStoreLevelDB> backingStore; - if (openInMemory) - backingStore = IDBBackingStoreLevelDB::openInMemory(fileIdentifier); - else - backingStore = IDBBackingStoreLevelDB::open(securityOrigin, dataDirectory, fileIdentifier); - - if (backingStore) { - cleanWeakMap(m_backingStoreMap); - m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr()); - // If an in-memory database, bind lifetime to this factory instance. - if (openInMemory) - m_sessionOnlyBackingStores.add(backingStore); - - // All backing stores associated with this factory should be of the same type. - ASSERT(m_sessionOnlyBackingStores.isEmpty() || openInMemory); - - return backingStore.release(); - } - - return 0; -} - -void IDBFactoryBackendLevelDB::open(const String& name, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, const SecurityOrigin& openingOrigin, const SecurityOrigin&) -{ - LOG(StorageAPI, "IDBFactoryBackendLevelDB::open"); - const String uniqueIdentifier = computeUniqueIdentifier(name, openingOrigin); - - RefPtr<IDBDatabaseBackend> databaseBackend; - IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier); - if (it == m_databaseBackendMap.end()) { - RefPtr<IDBBackingStoreLevelDB> backingStore = openBackingStore(openingOrigin, m_databaseDirectory); - if (!backingStore) { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error opening backing store for indexedDB.open.")); - return; - } - - RefPtr<IDBServerConnection> serverConnection = IDBServerConnectionLevelDB::create(name, backingStore.get()); - databaseBackend = IDBDatabaseBackend::create(name, uniqueIdentifier, this, *serverConnection); - if (databaseBackend) - m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); - else { - callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error creating database backend for indexeddb.open.")); - return; - } - } else - databaseBackend = it->value; - - databaseBackend->openConnection(callbacks, databaseCallbacks, transactionId, version); -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.h deleted file mode 100644 index 004046062..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBFactoryBackendLevelDB.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef IDBFactoryBackendLevelDB_h -#define IDBFactoryBackendLevelDB_h - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "IDBCallbacks.h" -#include "IDBDatabaseCallbacks.h" -#include "IDBFactoryBackendInterface.h" -#include "SecurityOrigin.h" -#include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/RefCounted.h> -#include <wtf/WeakPtr.h> -#include <wtf/text/StringHash.h> - -namespace WebCore { - -class DOMStringList; - -class IDBBackingStoreLevelDB; -class IDBDatabaseBackend; - -class IDBFactoryBackendLevelDB : public IDBFactoryBackendInterface { -public: - static PassRefPtr<IDBFactoryBackendLevelDB> create(const String& databaseDirectory) - { - return adoptRef(new IDBFactoryBackendLevelDB(databaseDirectory)); - } - virtual ~IDBFactoryBackendLevelDB(); - - // Notifications from weak pointers. - virtual void removeIDBDatabaseBackend(const String& uniqueIdentifier) override final; - - virtual void getDatabaseNames(PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, ScriptExecutionContext*, const String& dataDir) override final; - virtual void open(const String& name, uint64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBDatabaseCallbacks>, const SecurityOrigin& openingOrigin, const SecurityOrigin& mainFrameOrigin) override final; - - virtual void deleteDatabase(const String& name, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, ScriptExecutionContext*, const String& dataDir) override final; - -protected: - virtual PassRefPtr<IDBBackingStoreLevelDB> openBackingStore(const SecurityOrigin&, const String& dataDir); - -private: - explicit IDBFactoryBackendLevelDB(const String& databaseDirectory); - - typedef HashMap<String, RefPtr<IDBDatabaseBackend> > IDBDatabaseBackendMap; - IDBDatabaseBackendMap m_databaseBackendMap; - - typedef HashMap<String, WeakPtr<IDBBackingStoreLevelDB> > IDBBackingStoreLevelDBMap; - IDBBackingStoreLevelDBMap m_backingStoreMap; - - HashSet<RefPtr<IDBBackingStoreLevelDB> > m_sessionOnlyBackingStores; - - String m_databaseDirectory; -}; - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#endif // IDBFactoryBackendLevelDB_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.cpp deleted file mode 100644 index 75b824501..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBIndexWriterLevelDB.h" - -#include "IDBKey.h" -#include <wtf/text/CString.h> - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -namespace WebCore { - -IDBIndexWriterLevelDB::IDBIndexWriterLevelDB(const IDBIndexMetadata& metadata, const IndexKeys& keys) - : m_indexMetadata(metadata) - , m_indexKeys(keys) -{ -} - -void IDBIndexWriterLevelDB::writeIndexKeys(const IDBRecordIdentifier* recordIdentifier, IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId) const -{ - ASSERT(recordIdentifier); - int64_t indexId = m_indexMetadata.id; - for (size_t i = 0; i < m_indexKeys.size(); ++i) { - bool ok = backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier); - // This should have already been verified as a valid write during verifyIndexKeys. - ASSERT_UNUSED(ok, ok); - } -} - -bool IDBIndexWriterLevelDB::verifyIndexKeys(IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, bool& canAddKeys, const IDBKey* primaryKey, String* errorMessage) const -{ - canAddKeys = false; - for (size_t i = 0; i < m_indexKeys.size(); ++i) { - bool ok = addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId, (m_indexKeys)[i].get(), primaryKey, canAddKeys); - if (!ok) - return false; - if (!canAddKeys) { - if (errorMessage) - *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.", m_indexMetadata.name.utf8().data()); - return true; - } - } - canAddKeys = true; - return true; -} - -bool IDBIndexWriterLevelDB::addingKeyAllowed(IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey* indexKey, const IDBKey* primaryKey, bool& allowed) const -{ - allowed = false; - if (!m_indexMetadata.unique) { - allowed = true; - return true; - } - - RefPtr<IDBKey> foundPrimaryKey; - bool found = false; - bool ok = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey, found); - if (!ok) - return false; - if (!found || (primaryKey && foundPrimaryKey->isEqual(primaryKey))) - allowed = true; - return true; -} - - -} // namespace WebCore - -#endif // USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.h deleted file mode 100644 index 07e55538e..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBIndexWriterLevelDB.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBIndexWriterLevelDB_h -#define IDBIndexWriterLevelDB_h - -#include "IDBBackingStoreLevelDB.h" -#include "IDBDatabaseBackend.h" -#include "IDBDatabaseMetadata.h" -#include <wtf/RefCounted.h> - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -namespace WebCore { - -typedef Vector<RefPtr<IDBKey>> IndexKeys; - -class IDBIndexWriterLevelDB : public RefCounted<IDBIndexWriterLevelDB> { -public: - static PassRefPtr<IDBIndexWriterLevelDB> create(const IDBIndexMetadata& indexMetadata, const IndexKeys& indexKeys) - { - return adoptRef(new IDBIndexWriterLevelDB(indexMetadata, indexKeys)); - } - - bool verifyIndexKeys(IDBBackingStoreLevelDB&, IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, bool& canAddKeys, const IDBKey* primaryKey = 0, String* errorMessage = 0) const WARN_UNUSED_RETURN; - - void writeIndexKeys(const IDBRecordIdentifier*, IDBBackingStoreLevelDB&, IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId) const; - -private: - IDBIndexWriterLevelDB(const IDBIndexMetadata&, const IndexKeys&); - - bool addingKeyAllowed(IDBBackingStoreLevelDB&, IDBBackingStoreTransactionLevelDB&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey* indexKey, const IDBKey* primaryKey, bool& allowed) const WARN_UNUSED_RETURN; - - const IDBIndexMetadata m_indexMetadata; - IndexKeys m_indexKeys; -}; - -} // namespace WebCore - -#endif // #if USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) -#endif // IDBIndexWriterLevelDB_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.cpp deleted file mode 100644 index a4dcb1ede..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.cpp +++ /dev/null @@ -1,1807 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBLevelDBCoding.h" - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include "IDBKey.h" -#include "IDBKeyPath.h" -#include "LevelDBSlice.h" -#include <wtf/ByteOrder.h> -#include <wtf/text/StringBuilder.h> - -// LevelDB stores key/value pairs. Keys and values are strings of bytes, normally of type Vector<char>. -// -// The keys in the backing store are variable-length tuples with different types -// of fields. Each key in the backing store starts with a ternary prefix: (database id, object store id, index id). For each, 0 is reserved for meta-data. -// The prefix makes sure that data for a specific database, object store, and index are grouped together. The locality is important for performance: common -// operations should only need a minimal number of seek operations. For example, all the meta-data for a database is grouped together so that reading that -// meta-data only requires one seek. -// -// Each key type has a class (in square brackets below) which knows how to encode, decode, and compare that key type. -// -// Global meta-data have keys with prefix (0,0,0), followed by a type byte: -// -// <0, 0, 0, 0> => IndexedDB/LevelDB schema version [SchemaVersionKey] -// <0, 0, 0, 1> => The maximum database id ever allocated [MaxDatabaseIdKey] -// <0, 0, 0, 2> => SerializedScriptValue version [DataVersionKey] -// <0, 0, 0, 100, database id> => Existence implies the database id is in the free list [DatabaseFreeListKey] -// <0, 0, 0, 201, utf16 origin name, utf16 database name> => Database id [DatabaseNameKey] -// -// -// Database meta-data: -// -// Again, the prefix is followed by a type byte. -// -// <database id, 0, 0, 0> => utf16 origin name [DatabaseMetaDataKey] -// <database id, 0, 0, 1> => utf16 database name [DatabaseMetaDataKey] -// <database id, 0, 0, 2> => utf16 user version data [DatabaseMetaDataKey] -// <database id, 0, 0, 3> => maximum object store id ever allocated [DatabaseMetaDataKey] -// <database id, 0, 0, 4> => user integer version (var int) [DatabaseMetaDataKey] -// -// -// Object store meta-data: -// -// The prefix is followed by a type byte, then a variable-length integer, and then another type byte. -// -// <database id, 0, 0, 50, object store id, 0> => utf16 object store name [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 1> => utf16 key path [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 2> => has auto increment [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 3> => is evictable [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 4> => last "version" number [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 5> => maximum index id ever allocated [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 6> => has key path (vs. null) [ObjectStoreMetaDataKey] -// <database id, 0, 0, 50, object store id, 7> => key generator current number [ObjectStoreMetaDataKey] -// -// -// Index meta-data: -// -// The prefix is followed by a type byte, then two variable-length integers, and then another type byte. -// -// <database id, 0, 0, 100, object store id, index id, 0> => utf16 index name [IndexMetaDataKey] -// <database id, 0, 0, 100, object store id, index id, 1> => are index keys unique [IndexMetaDataKey] -// <database id, 0, 0, 100, object store id, index id, 2> => utf16 key path [IndexMetaDataKey] -// <database id, 0, 0, 100, object store id, index id, 3> => is index multi-entry [IndexMetaDataKey] -// -// -// Other object store and index meta-data: -// -// The prefix is followed by a type byte. The object store and index id are variable length integers, the utf16 strings are variable length strings. -// -// <database id, 0, 0, 150, object store id> => existence implies the object store id is in the free list [ObjectStoreFreeListKey] -// <database id, 0, 0, 151, object store id, index id> => existence implies the index id is in the free list [IndexFreeListKey] -// <database id, 0, 0, 200, utf16 object store name> => object store id [ObjectStoreNamesKey] -// <database id, 0, 0, 201, object store id, utf16 index name> => index id [IndexNamesKey] -// -// -// Object store data: -// -// The prefix is followed by a type byte. The user key is an encoded IDBKey. -// -// <database id, object store id, 1, user key> => "version", serialized script value [ObjectStoreDataKey] -// -// -// "Exists" entry: -// -// The prefix is followed by a type byte. The user key is an encoded IDBKey. -// -// <database id, object store id, 2, user key> => "version" [ExistsEntryKey] -// -// -// Index data: -// -// The prefix is followed by a type byte. The index key is an encoded IDBKey. The sequence number is a variable length integer. -// The primary key is an encoded IDBKey. -// -// <database id, object store id, index id, index key, sequence number, primary key> => "version", primary key [IndexDataKey] -// -// (The sequence number is obsolete; it was used to allow two entries with -// the same user (index) key in non-unique indexes prior to the inclusion of -// the primary key in the data. The "version" field is used to weed out stale -// index data. Whenever new object store data is inserted, it gets a new -// "version" number, and new index data is written with this number. When -// the index is used for look-ups, entries are validated against the -// "exists" entries, and records with old "version" numbers are deleted -// when they are encountered in getPrimaryKeyViaIndex, -// IndexCursorImpl::loadCurrentRow, and IndexKeyCursorImpl::loadCurrentRow). - -namespace WebCore { -namespace IDBLevelDBCoding { - -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffLL -#endif -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffffL -#endif - -static const unsigned char IDBKeyNullTypeByte = 0; -static const unsigned char IDBKeyStringTypeByte = 1; -static const unsigned char IDBKeyDateTypeByte = 2; -static const unsigned char IDBKeyNumberTypeByte = 3; -static const unsigned char IDBKeyArrayTypeByte = 4; -static const unsigned char IDBKeyMinKeyTypeByte = 5; - -static const unsigned char IDBKeyPathTypeCodedByte1 = 0; -static const unsigned char IDBKeyPathTypeCodedByte2 = 0; - -static const unsigned char ObjectStoreDataIndexId = 1; -static const unsigned char ExistsEntryIndexId = 2; - -static const unsigned char SchemaVersionTypeByte = 0; -static const unsigned char MaxDatabaseIdTypeByte = 1; -static const unsigned char DataVersionTypeByte = 2; -static const unsigned char MaxSimpleGlobalMetaDataTypeByte = 3; // Insert before this and increment. -static const unsigned char DatabaseFreeListTypeByte = 100; -static const unsigned char DatabaseNameTypeByte = 201; - -static const unsigned char ObjectStoreMetaDataTypeByte = 50; -static const unsigned char IndexMetaDataTypeByte = 100; -static const unsigned char ObjectStoreFreeListTypeByte = 150; -static const unsigned char IndexFreeListTypeByte = 151; -static const unsigned char ObjectStoreNamesTypeByte = 200; -static const unsigned char IndexNamesKeyTypeByte = 201; - -static const unsigned char ObjectMetaDataTypeMaximum = 255; -static const unsigned char IndexMetaDataTypeMaximum = 255; - -Vector<char> encodeByte(unsigned char c) -{ - Vector<char, DefaultInlineBufferSize> v; - v.append(c); - - ASSERT(v.size() <= DefaultInlineBufferSize); - return v; -} - -const char* decodeByte(const char* p, const char* limit, unsigned char& foundChar) -{ - if (p >= limit) - return 0; - - foundChar = *p++; - return p; -} - -Vector<char> maxIDBKey() -{ - return encodeByte(IDBKeyNullTypeByte); -} - -Vector<char> minIDBKey() -{ - return encodeByte(IDBKeyMinKeyTypeByte); -} - -Vector<char> encodeBool(bool b) -{ - Vector<char, DefaultInlineBufferSize> ret; - ret.append(b ? 1 : 0); - - ASSERT(ret.size() <= DefaultInlineBufferSize); - return ret; -} - -bool decodeBool(const char* begin, const char* end) -{ - ASSERT_UNUSED(end, begin < end); - return *begin; -} - -Vector<char> encodeInt(int64_t nParam) -{ - ASSERT(nParam >= 0); - uint64_t n = static_cast<uint64_t>(nParam); - Vector<char, DefaultInlineBufferSize> ret; - - do { - unsigned char c = n; - ret.append(c); - n >>= 8; - } while (n); - - ASSERT(ret.size() <= DefaultInlineBufferSize); - return ret; -} - -int64_t decodeInt(const char* begin, const char* end) -{ - ASSERT(begin <= end); - int64_t ret = 0; - - int shift = 0; - while (begin < end) { - unsigned char c = *begin++; - ret |= static_cast<int64_t>(c) << shift; - shift += 8; - } - - return ret; -} - -static int compareInts(int64_t a, int64_t b) -{ - ASSERT(a >= 0); - ASSERT(b >= 0); - - int64_t diff = a - b; - if (diff < 0) - return -1; - if (diff > 0) - return 1; - return 0; -} - -Vector<char> encodeVarInt(int64_t nParam) -{ - ASSERT(nParam >= 0); - uint64_t n = static_cast<uint64_t>(nParam); - Vector<char, DefaultInlineBufferSize> ret; - - do { - unsigned char c = n & 0x7f; - n >>= 7; - if (n) - c |= 0x80; - ret.append(c); - } while (n); - - ASSERT(ret.size() <= DefaultInlineBufferSize); - return ret; -} - -const char* decodeVarInt(const char* p, const char* limit, int64_t& foundInt) -{ - ASSERT(limit >= p); - foundInt = 0; - int shift = 0; - - do { - if (p >= limit) - return 0; - - unsigned char c = *p; - foundInt |= static_cast<int64_t>(c & 0x7f) << shift; - shift += 7; - } while (*p++ & 0x80); - return p; -} - -Vector<char> encodeString(const String& s) -{ - // Backing store is UTF-16BE, convert from host endianness. - size_t length = s.length(); - Vector<char> ret(length * sizeof(UChar)); - - const UChar* src = s.characters(); - UChar* dst = reinterpret_cast<UChar*>(ret.data()); - for (unsigned i = 0; i < length; ++i) - *dst++ = htons(*src++); - - return ret; -} - -String decodeString(const char* start, const char* end) -{ - // Backing store is UTF-16BE, convert to host endianness. - ASSERT(end >= start); - ASSERT(!((end - start) % sizeof(UChar))); - - size_t length = (end - start) / sizeof(UChar); - Vector<UChar> buffer(length); - - const UChar* src = reinterpret_cast<const UChar*>(start); - UChar* dst = buffer.data(); - for (unsigned i = 0; i < length; ++i) - *dst++ = ntohs(*src++); - - return String::adopt(buffer); -} - -Vector<char> encodeStringWithLength(const String& s) -{ - Vector<char> ret = encodeVarInt(s.length()); - ret.appendVector(encodeString(s)); - return ret; -} - -const char* decodeStringWithLength(const char* p, const char* limit, String& foundString) -{ - ASSERT(limit >= p); - int64_t len; - p = decodeVarInt(p, limit, len); - if (!p || len < 0 || p + len * 2 > limit) - return 0; - - foundString = decodeString(p, p + len * 2); - p += len * 2; - return p; -} - -int compareEncodedStringsWithLength(const char*& p, const char* limitP, const char*& q, const char* limitQ, bool& ok) -{ - ASSERT(&p != &q); - ASSERT(limitP >= p); - ASSERT(limitQ >= q); - int64_t lenP, lenQ; - p = decodeVarInt(p, limitP, lenP); - q = decodeVarInt(q, limitQ, lenQ); - if (!p || !q || lenP < 0 || lenQ < 0) { - ok = false; - return 0; - } - ASSERT(p && q); - ASSERT(lenP >= 0); - ASSERT(lenQ >= 0); - ASSERT(p + lenP * 2 <= limitP); - ASSERT(q + lenQ * 2 <= limitQ); - - const char* startP = p; - const char* startQ = q; - p += lenP * 2; - q += lenQ * 2; - - if (p > limitP || q > limitQ) { - ok = false; - return 0; - } - - ok = true; - const size_t lmin = static_cast<size_t>(lenP < lenQ ? lenP : lenQ); - if (int x = memcmp(startP, startQ, lmin * 2)) - return x; - - if (lenP == lenQ) - return 0; - - return (lenP > lenQ) ? 1 : -1; -} - -Vector<char> encodeDouble(double x) -{ - // FIXME: It would be nice if we could be byte order independent. - const char* p = reinterpret_cast<char*>(&x); - Vector<char, DefaultInlineBufferSize> v; - v.append(p, sizeof(x)); - - ASSERT(v.size() <= DefaultInlineBufferSize); - return v; -} - -const char* decodeDouble(const char* p, const char* limit, double* d) -{ - if (p + sizeof(*d) > limit) - return 0; - - char* x = reinterpret_cast<char*>(d); - for (size_t i = 0; i < sizeof(*d); ++i) - *x++ = *p++; - return p; -} - -Vector<char> encodeIDBKey(const IDBKey& key) -{ - Vector<char, DefaultInlineBufferSize> ret; - encodeIDBKey(key, ret); - return ret; -} - -void encodeIDBKey(const IDBKey& key, Vector<char, DefaultInlineBufferSize>& into) -{ - size_t previousSize = into.size(); - ASSERT(key.isValid()); - switch (key.type()) { - case IDBKey::InvalidType: - case IDBKey::MinType: - ASSERT_NOT_REACHED(); - into.appendVector(encodeByte(IDBKeyNullTypeByte)); - return; - case IDBKey::ArrayType: { - into.appendVector(encodeByte(IDBKeyArrayTypeByte)); - size_t length = key.array().size(); - into.appendVector(encodeVarInt(length)); - for (size_t i = 0; i < length; ++i) - encodeIDBKey(*key.array()[i], into); - ASSERT_UNUSED(previousSize, into.size() > previousSize); - return; - } - case IDBKey::StringType: - into.appendVector(encodeByte(IDBKeyStringTypeByte)); - into.appendVector(encodeStringWithLength(key.string())); - ASSERT_UNUSED(previousSize, into.size() > previousSize); - return; - case IDBKey::DateType: - into.appendVector(encodeByte(IDBKeyDateTypeByte)); - into.appendVector(encodeDouble(key.date())); - ASSERT_UNUSED(previousSize, into.size() - previousSize == 9); - return; - case IDBKey::NumberType: - into.appendVector(encodeByte(IDBKeyNumberTypeByte)); - into.appendVector(encodeDouble(key.number())); - ASSERT_UNUSED(previousSize, into.size() - previousSize == 9); - return; - } - - ASSERT_NOT_REACHED(); -} - - -const char* decodeIDBKey(const char* p, const char* limit, RefPtr<IDBKey>& foundKey) -{ - ASSERT(limit >= p); - if (p >= limit) - return 0; - - unsigned char type = *p++; - - switch (type) { - case IDBKeyNullTypeByte: - foundKey = IDBKey::createInvalid(); - return p; - - case IDBKeyArrayTypeByte: { - int64_t length; - p = decodeVarInt(p, limit, length); - if (!p || length < 0) - return 0; - IDBKey::KeyArray array; - while (length--) { - RefPtr<IDBKey> key; - p = decodeIDBKey(p, limit, key); - if (!p) - return 0; - array.append(key); - } - foundKey = IDBKey::createArray(array); - return p; - } - case IDBKeyStringTypeByte: { - String s; - p = decodeStringWithLength(p, limit, s); - if (!p) - return 0; - foundKey = IDBKey::createString(s); - return p; - } - case IDBKeyDateTypeByte: { - double d; - p = decodeDouble(p, limit, &d); - if (!p) - return 0; - foundKey = IDBKey::createDate(d); - return p; - } - case IDBKeyNumberTypeByte: { - double d; - p = decodeDouble(p, limit, &d); - if (!p) - return 0; - foundKey = IDBKey::createNumber(d); - return p; - } - } - - ASSERT_NOT_REACHED(); - return 0; -} - -const char* extractEncodedIDBKey(const char* start, const char* limit, Vector<char>* result = 0) -{ - const char* p = start; - if (p >= limit) - return 0; - - unsigned char type = *p++; - - switch (type) { - case IDBKeyNullTypeByte: - case IDBKeyMinKeyTypeByte: - break; - case IDBKeyArrayTypeByte: { - int64_t length; - p = decodeVarInt(p, limit, length); - if (!p || length < 0) - return 0; - while (length--) { - p = extractEncodedIDBKey(p, limit); - if (!p) - return 0; - } - break; - } - case IDBKeyStringTypeByte: { - int64_t length; - p = decodeVarInt(p, limit, length); - if (!p || length < 0 || p + length * 2 > limit) - return 0; - p += length * 2; - break; - } - case IDBKeyDateTypeByte: - case IDBKeyNumberTypeByte: - if (p + sizeof(double) > limit) - return 0; - p += sizeof(double); - break; - } - - if (result) { - ASSERT(p); - ASSERT(p <= limit); - result->clear(); - result->append(start, p - start); - } - - return p; -} - -static IDBKey::Type keyTypeByteToKeyType(unsigned char type) -{ - switch (type) { - case IDBKeyNullTypeByte: - return IDBKey::InvalidType; - case IDBKeyArrayTypeByte: - return IDBKey::ArrayType; - case IDBKeyStringTypeByte: - return IDBKey::StringType; - case IDBKeyDateTypeByte: - return IDBKey::DateType; - case IDBKeyNumberTypeByte: - return IDBKey::NumberType; - case IDBKeyMinKeyTypeByte: - return IDBKey::MinType; - } - - ASSERT_NOT_REACHED(); - return IDBKey::InvalidType; -} - -static int compareEncodedIDBKeys(const char*& ptrA, const char* limitA, const char*& ptrB, const char* limitB, bool& ok) -{ - ok = true; - ASSERT(&ptrA != &ptrB); - ASSERT_WITH_SECURITY_IMPLICATION(ptrA < limitA); - ASSERT_WITH_SECURITY_IMPLICATION(ptrB < limitB); - unsigned char typeA = *ptrA++; - unsigned char typeB = *ptrB++; - - if (int x = IDBKey::compareTypes(keyTypeByteToKeyType(typeA), keyTypeByteToKeyType(typeB))) - return x; - - switch (typeA) { - case IDBKeyNullTypeByte: - case IDBKeyMinKeyTypeByte: - // Null type or max type; no payload to compare. - return 0; - case IDBKeyArrayTypeByte: { - int64_t lengthA, lengthB; - ptrA = decodeVarInt(ptrA, limitA, lengthA); - ptrB = decodeVarInt(ptrB, limitB, lengthB); - if (!ptrA || !ptrB || lengthA < 0 || lengthB < 0) { - ok = false; - return 0; - } - for (int64_t i = 0; i < lengthA && i < lengthB; ++i) { - int result = compareEncodedIDBKeys(ptrA, limitA, ptrB, limitB, ok); - if (!ok || result) - return result; - } - if (lengthA < lengthB) - return -1; - if (lengthA > lengthB) - return 1; - return 0; - } - case IDBKeyStringTypeByte: - return compareEncodedStringsWithLength(ptrA, limitA, ptrB, limitB, ok); - case IDBKeyDateTypeByte: - case IDBKeyNumberTypeByte: { - double d, e; - ptrA = decodeDouble(ptrA, limitA, &d); - ptrB = decodeDouble(ptrB, limitB, &e); - ASSERT(ptrA); - ASSERT(ptrB); - if (!ptrA || !ptrB) { - ok = false; - return 0; - } - if (d < e) - return -1; - if (d > e) - return 1; - return 0; - } - } - - ASSERT_NOT_REACHED(); - return 0; -} - -int compareEncodedIDBKeys(const Vector<char>& keyA, const Vector<char>& keyB, bool& ok) -{ - ASSERT(keyA.size() >= 1); - ASSERT(keyB.size() >= 1); - - const char* ptrA = keyA.data(); - const char* limitA = ptrA + keyA.size(); - const char* ptrB = keyB.data(); - const char* limitB = ptrB + keyB.size(); - - return compareEncodedIDBKeys(ptrA, limitA, ptrB, limitB, ok); -} - -Vector<char> encodeIDBKeyPath(const IDBKeyPath& keyPath) -{ - // May be typed, or may be a raw string. An invalid leading - // byte is used to identify typed coding. New records are - // always written as typed. - Vector<char, DefaultInlineBufferSize> ret; - ret.append(IDBKeyPathTypeCodedByte1); - ret.append(IDBKeyPathTypeCodedByte2); - ret.append(static_cast<char>(keyPath.type())); - switch (keyPath.type()) { - case IDBKeyPath::NullType: - break; - case IDBKeyPath::StringType: - ret.appendVector(encodeStringWithLength(keyPath.string())); - break; - case IDBKeyPath::ArrayType: { - const Vector<String>& array = keyPath.array(); - size_t count = array.size(); - ret.appendVector(encodeVarInt(count)); - for (size_t i = 0; i < count; ++i) - ret.appendVector(encodeStringWithLength(array[i])); - break; - } - } - return ret; -} - -IDBKeyPath decodeIDBKeyPath(const char* p, const char* limit) -{ - // May be typed, or may be a raw string. An invalid leading - // byte sequence is used to identify typed coding. New records are - // always written as typed. - if (p == limit || (limit - p >= 2 && (*p != IDBKeyPathTypeCodedByte1 || *(p + 1) != IDBKeyPathTypeCodedByte2))) - return IDBKeyPath(decodeString(p, limit)); - p += 2; - - ASSERT(p != limit); - IDBKeyPath::Type type = static_cast<IDBKeyPath::Type>(*p++); - switch (type) { - case IDBKeyPath::NullType: - ASSERT(p == limit); - return IDBKeyPath(); - case IDBKeyPath::StringType: { - String string; - p = decodeStringWithLength(p, limit, string); - ASSERT(p == limit); - return IDBKeyPath(string); - } - case IDBKeyPath::ArrayType: { - Vector<String> array; - int64_t count; - p = decodeVarInt(p, limit, count); - ASSERT(p); - ASSERT(count >= 0); - while (count--) { - String string; - p = decodeStringWithLength(p, limit, string); - ASSERT(p); - array.append(string); - } - ASSERT(p == limit); - return IDBKeyPath(array); - } - } - ASSERT_NOT_REACHED(); - return IDBKeyPath(); -} - -namespace { - -template<typename KeyType> -int compare(const LevelDBSlice& a, const LevelDBSlice& b, bool, bool& ok) -{ - KeyType keyA; - KeyType keyB; - - const char* ptrA = KeyType::decode(a.begin(), a.end(), &keyA); - ASSERT(ptrA); - if (!ptrA) { - ok = false; - return 0; - } - const char* ptrB = KeyType::decode(b.begin(), b.end(), &keyB); - ASSERT(ptrB); - if (!ptrB) { - ok = false; - return 0; - } - - ok = true; - return keyA.compare(keyB); -} - -template<> -int compare<ExistsEntryKey>(const LevelDBSlice& a, const LevelDBSlice& b, bool, bool& ok) -{ - KeyPrefix prefixA; - KeyPrefix prefixB; - const char* ptrA = KeyPrefix::decode(a.begin(), a.end(), &prefixA); - const char* ptrB = KeyPrefix::decode(b.begin(), b.end(), &prefixB); - ASSERT(ptrA); - ASSERT(ptrB); - ASSERT(prefixA.m_databaseId); - ASSERT(prefixA.m_objectStoreId); - ASSERT(prefixA.m_indexId == ExistsEntryKey::SpecialIndexNumber); - ASSERT(prefixB.m_databaseId); - ASSERT(prefixB.m_objectStoreId); - ASSERT(prefixB.m_indexId == ExistsEntryKey::SpecialIndexNumber); - ASSERT(ptrA != a.end()); - ASSERT(ptrB != b.end()); - // Prefixes are not compared - it is assumed this was already done. - ASSERT(!prefixA.compare(prefixB)); - - return compareEncodedIDBKeys(ptrA, a.end(), ptrB, b.end(), ok); -} - -template<> -int compare<ObjectStoreDataKey>(const LevelDBSlice& a, const LevelDBSlice& b, bool, bool& ok) -{ - KeyPrefix prefixA; - KeyPrefix prefixB; - const char* ptrA = KeyPrefix::decode(a.begin(), a.end(), &prefixA); - const char* ptrB = KeyPrefix::decode(b.begin(), b.end(), &prefixB); - ASSERT(ptrA); - ASSERT(ptrB); - ASSERT(prefixA.m_databaseId); - ASSERT(prefixA.m_objectStoreId); - ASSERT(prefixA.m_indexId == ObjectStoreDataKey::SpecialIndexNumber); - ASSERT(prefixB.m_databaseId); - ASSERT(prefixB.m_objectStoreId); - ASSERT(prefixB.m_indexId == ObjectStoreDataKey::SpecialIndexNumber); - ASSERT(ptrA != a.end()); - ASSERT(ptrB != b.end()); - // Prefixes are not compared - it is assumed this was already done. - ASSERT(!prefixA.compare(prefixB)); - - return compareEncodedIDBKeys(ptrA, a.end(), ptrB, b.end(), ok); -} - -template<> -int compare<IndexDataKey>(const LevelDBSlice& a, const LevelDBSlice& b, bool ignoreDuplicates, bool& ok) -{ - KeyPrefix prefixA; - KeyPrefix prefixB; - const char* ptrA = KeyPrefix::decode(a.begin(), a.end(), &prefixA); - const char* ptrB = KeyPrefix::decode(b.begin(), b.end(), &prefixB); - ASSERT(ptrA); - ASSERT(ptrB); - ASSERT(prefixA.m_databaseId); - ASSERT(prefixA.m_objectStoreId); - ASSERT(prefixA.m_indexId >= MinimumIndexId); - ASSERT(prefixB.m_databaseId); - ASSERT(prefixB.m_objectStoreId); - ASSERT(prefixB.m_indexId >= MinimumIndexId); - ASSERT(ptrA != a.end()); - ASSERT(ptrB != b.end()); - // Prefixes are not compared - it is assumed this was already done. - ASSERT(!prefixA.compare(prefixB)); - - // index key - int result = compareEncodedIDBKeys(ptrA, a.end(), ptrB, b.end(), ok); - if (!ok || result) - return result; - if (ignoreDuplicates) - return 0; - - // sequence number [optional] - int64_t sequenceNumberA = -1; - int64_t sequenceNumberB = -1; - if (ptrA != a.end()) - ptrA = decodeVarInt(ptrA, a.end(), sequenceNumberA); - if (ptrB != b.end()) - ptrB = decodeVarInt(ptrB, b.end(), sequenceNumberB); - - // primary key [optional] - if (!ptrA || !ptrB) - return 0; - if (ptrA == a.end() && ptrB == b.end()) - return 0; - if (ptrA == a.end()) - return -1; - if (ptrB == b.end()) - return 1; - - result = compareEncodedIDBKeys(ptrA, a.end(), ptrB, b.end(), ok); - if (!ok || result) - return result; - - return compareInts(sequenceNumberA, sequenceNumberB); -} - -int compare(const LevelDBSlice& a, const LevelDBSlice& b, bool indexKeys, bool& ok) -{ - const char* ptrA = a.begin(); - const char* ptrB = b.begin(); - const char* endA = a.end(); - const char* endB = b.end(); - - KeyPrefix prefixA; - KeyPrefix prefixB; - - ptrA = KeyPrefix::decode(ptrA, endA, &prefixA); - ptrB = KeyPrefix::decode(ptrB, endB, &prefixB); - ASSERT(ptrA); - ASSERT(ptrB); - if (!ptrA || !ptrB) { - ok = false; - return 0; - } - - ok = true; - if (int x = prefixA.compare(prefixB)) - return x; - - if (prefixA.type() == KeyPrefix::GlobalMetaData) { - ASSERT(ptrA != endA); - ASSERT(ptrB != endB); - - unsigned char typeByteA = *ptrA++; - unsigned char typeByteB = *ptrB++; - - if (int x = typeByteA - typeByteB) - return x; - if (typeByteA < MaxSimpleGlobalMetaDataTypeByte) - return 0; - - const bool ignoreDuplicates = false; - if (typeByteA == DatabaseFreeListTypeByte) - return compare<DatabaseFreeListKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == DatabaseNameTypeByte) - return compare<DatabaseNameKey>(a, b, ignoreDuplicates, ok); - } - - if (prefixA.type() == KeyPrefix::DatabaseMetaData) { - ASSERT(ptrA != endA); - ASSERT(ptrB != endB); - - unsigned char typeByteA = *ptrA++; - unsigned char typeByteB = *ptrB++; - - if (int x = typeByteA - typeByteB) - return x; - if (typeByteA < DatabaseMetaDataKey::MaxSimpleMetaDataType) - return 0; - - const bool ignoreDuplicates = false; - if (typeByteA == ObjectStoreMetaDataTypeByte) - return compare<ObjectStoreMetaDataKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == IndexMetaDataTypeByte) - return compare<IndexMetaDataKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == ObjectStoreFreeListTypeByte) - return compare<ObjectStoreFreeListKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == IndexFreeListTypeByte) - return compare<IndexFreeListKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == ObjectStoreNamesTypeByte) - return compare<ObjectStoreNamesKey>(a, b, ignoreDuplicates, ok); - if (typeByteA == IndexNamesKeyTypeByte) - return compare<IndexNamesKey>(a, b, ignoreDuplicates, ok); - } - - if (prefixA.type() == KeyPrefix::ObjectStoreData) { - if (ptrA == endA && ptrB == endB) - return 0; - if (ptrA == endA) - return -1; - if (ptrB == endB) - return 1; // FIXME: This case of non-existing user keys should not have to be handled this way. - - const bool ignoreDuplicates = false; - return compare<ObjectStoreDataKey>(a, b, ignoreDuplicates, ok); - } - if (prefixA.type() == KeyPrefix::ExistsEntry) { - if (ptrA == endA && ptrB == endB) - return 0; - if (ptrA == endA) - return -1; - if (ptrB == endB) - return 1; // FIXME: This case of non-existing user keys should not have to be handled this way. - - const bool ignoreDuplicates = false; - return compare<ExistsEntryKey>(a, b, ignoreDuplicates, ok); - } - if (prefixA.type() == KeyPrefix::IndexData) { - if (ptrA == endA && ptrB == endB) - return 0; - if (ptrA == endA) - return -1; - if (ptrB == endB) - return 1; // FIXME: This case of non-existing user keys should not have to be handled this way. - - bool ignoreDuplicates = indexKeys; - return compare<IndexDataKey>(a, b, ignoreDuplicates, ok); - } - - ASSERT_NOT_REACHED(); - ok = false; - return 0; -} - -} - -int compare(const LevelDBSlice& a, const LevelDBSlice& b, bool indexKeys) -{ - bool ok; - int result = compare(a, b, indexKeys, ok); - ASSERT(ok); - if (!ok) - return 0; - return result; -} - -KeyPrefix::KeyPrefix() - : m_databaseId(InvalidType) - , m_objectStoreId(InvalidType) - , m_indexId(InvalidType) -{ -} - -KeyPrefix::KeyPrefix(int64_t databaseId) - : m_databaseId(databaseId) - , m_objectStoreId(0) - , m_indexId(0) -{ - ASSERT(KeyPrefix::isValidDatabaseId(databaseId)); -} - -KeyPrefix::KeyPrefix(int64_t databaseId, int64_t objectStoreId) - : m_databaseId(databaseId) - , m_objectStoreId(objectStoreId) - , m_indexId(0) -{ - ASSERT(KeyPrefix::isValidDatabaseId(databaseId)); - ASSERT(KeyPrefix::isValidObjectStoreId(objectStoreId)); -} - -KeyPrefix::KeyPrefix(int64_t databaseId, int64_t objectStoreId, int64_t indexId) - : m_databaseId(databaseId) - , m_objectStoreId(objectStoreId) - , m_indexId(indexId) -{ - ASSERT(KeyPrefix::isValidDatabaseId(databaseId)); - ASSERT(KeyPrefix::isValidObjectStoreId(objectStoreId)); - ASSERT(KeyPrefix::isValidIndexId(indexId)); -} - -KeyPrefix::KeyPrefix(Type type, int64_t databaseId, int64_t objectStoreId, int64_t indexId) - : m_databaseId(databaseId) - , m_objectStoreId(objectStoreId) - , m_indexId(indexId) -{ - ASSERT_UNUSED(type, type == InvalidType); - ASSERT(KeyPrefix::isValidDatabaseId(databaseId)); - ASSERT(KeyPrefix::isValidObjectStoreId(objectStoreId)); -} - - -KeyPrefix KeyPrefix::createWithSpecialIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - ASSERT(KeyPrefix::isValidDatabaseId(databaseId)); - ASSERT(KeyPrefix::isValidObjectStoreId(objectStoreId)); - ASSERT(indexId); - return KeyPrefix(InvalidType, databaseId, objectStoreId, indexId); -} - - -bool KeyPrefix::isValidDatabaseId(int64_t databaseId) -{ - return (databaseId > 0) && (databaseId < KeyPrefix::kMaxDatabaseId); -} - -bool KeyPrefix::isValidObjectStoreId(int64_t objectStoreId) -{ - return (objectStoreId > 0) && (objectStoreId < KeyPrefix::kMaxObjectStoreId); -} - -bool KeyPrefix::isValidIndexId(int64_t indexId) -{ - return (indexId >= MinimumIndexId) && (indexId < KeyPrefix::kMaxIndexId); -} - -const char* KeyPrefix::decode(const char* start, const char* limit, KeyPrefix* result) -{ - if (start == limit) - return 0; - - unsigned char firstByte = *start++; - - int databaseIdBytes = ((firstByte >> 5) & 0x7) + 1; - int objectStoreIdBytes = ((firstByte >> 2) & 0x7) + 1; - int indexIdBytes = (firstByte & 0x3) + 1; - - if (start + databaseIdBytes + objectStoreIdBytes + indexIdBytes > limit) - return 0; - - result->m_databaseId = decodeInt(start, start + databaseIdBytes); - start += databaseIdBytes; - result->m_objectStoreId = decodeInt(start, start + objectStoreIdBytes); - start += objectStoreIdBytes; - result->m_indexId = decodeInt(start, start + indexIdBytes); - start += indexIdBytes; - - return start; -} - -Vector<char> KeyPrefix::encodeEmpty() -{ - const Vector<char, 4> result(4, 0); - ASSERT(encodeInternal(0, 0, 0) == Vector<char>(4, 0)); - return result; -} - -Vector<char> KeyPrefix::encode() const -{ - ASSERT(m_databaseId != InvalidId); - ASSERT(m_objectStoreId != InvalidId); - ASSERT(m_indexId != InvalidId); - return encodeInternal(m_databaseId, m_objectStoreId, m_indexId); -} - -Vector<char> KeyPrefix::encodeInternal(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - Vector<char> databaseIdString = encodeIntSafely(databaseId, kMaxDatabaseId); - Vector<char> objectStoreIdString = encodeIntSafely(objectStoreId, kMaxObjectStoreId); - Vector<char> indexIdString = encodeIntSafely(indexId, kMaxIndexId); - - ASSERT(databaseIdString.size() <= kMaxDatabaseIdSizeBytes); - ASSERT(objectStoreIdString.size() <= kMaxObjectStoreIdSizeBytes); - ASSERT(indexIdString.size() <= kMaxIndexIdSizeBytes); - - unsigned char firstByte = (databaseIdString.size() - 1) << (kMaxObjectStoreIdSizeBits + kMaxIndexIdSizeBits) | (objectStoreIdString.size() - 1) << kMaxIndexIdSizeBits | (indexIdString.size() - 1); - COMPILE_ASSERT(kMaxDatabaseIdSizeBits + kMaxObjectStoreIdSizeBits + kMaxIndexIdSizeBits == sizeof(firstByte) * 8, CANT_ENCODE_IDS); - Vector<char, DefaultInlineBufferSize> ret; - ret.append(firstByte); - ret.appendVector(databaseIdString); - ret.appendVector(objectStoreIdString); - ret.appendVector(indexIdString); - - ASSERT(ret.size() <= DefaultInlineBufferSize); - return ret; -} - -int KeyPrefix::compare(const KeyPrefix& other) const -{ - ASSERT(m_databaseId != InvalidId); - ASSERT(m_objectStoreId != InvalidId); - ASSERT(m_indexId != InvalidId); - - if (m_databaseId != other.m_databaseId) - return compareInts(m_databaseId, other.m_databaseId); - if (m_objectStoreId != other.m_objectStoreId) - return compareInts(m_objectStoreId, other.m_objectStoreId); - if (m_indexId != other.m_indexId) - return compareInts(m_indexId, other.m_indexId); - return 0; -} - -KeyPrefix::Type KeyPrefix::type() const -{ - ASSERT(m_databaseId != InvalidId); - ASSERT(m_objectStoreId != InvalidId); - ASSERT(m_indexId != InvalidId); - - if (!m_databaseId) - return GlobalMetaData; - if (!m_objectStoreId) - return DatabaseMetaData; - if (m_indexId == ObjectStoreDataIndexId) - return ObjectStoreData; - if (m_indexId == ExistsEntryIndexId) - return ExistsEntry; - if (m_indexId >= MinimumIndexId) - return IndexData; - - ASSERT_NOT_REACHED(); - return InvalidType; -} - -Vector<char> SchemaVersionKey::encode() -{ - Vector<char> ret = KeyPrefix::encodeEmpty(); - ret.appendVector(encodeByte(SchemaVersionTypeByte)); - return ret; -} - -Vector<char> MaxDatabaseIdKey::encode() -{ - Vector<char> ret = KeyPrefix::encodeEmpty(); - ret.appendVector(encodeByte(MaxDatabaseIdTypeByte)); - return ret; -} - -Vector<char> DataVersionKey::encode() -{ - Vector<char> ret = KeyPrefix::encodeEmpty(); - ret.appendVector(encodeByte(DataVersionTypeByte)); - return ret; -} - -DatabaseFreeListKey::DatabaseFreeListKey() - : m_databaseId(-1) -{ -} - -const char* DatabaseFreeListKey::decode(const char* start, const char* limit, DatabaseFreeListKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(!prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == DatabaseFreeListTypeByte); - if (p == limit) - return 0; - return decodeVarInt(p, limit, result->m_databaseId); -} - -Vector<char> DatabaseFreeListKey::encode(int64_t databaseId) -{ - Vector<char> ret = KeyPrefix::encodeEmpty(); - ret.appendVector(encodeByte(DatabaseFreeListTypeByte)); - ret.appendVector(encodeVarInt(databaseId)); - return ret; -} - -Vector<char> DatabaseFreeListKey::encodeMaxKey() -{ - return encode(INT64_MAX); -} - -int64_t DatabaseFreeListKey::databaseId() const -{ - ASSERT(m_databaseId >= 0); - return m_databaseId; -} - -int DatabaseFreeListKey::compare(const DatabaseFreeListKey& other) const -{ - ASSERT(m_databaseId >= 0); - return compareInts(m_databaseId, other.m_databaseId); -} - -const char* DatabaseNameKey::decode(const char* start, const char* limit, DatabaseNameKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return p; - ASSERT(!prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == DatabaseNameTypeByte); - if (p == limit) - return 0; - p = decodeStringWithLength(p, limit, result->m_origin); - if (!p) - return 0; - return decodeStringWithLength(p, limit, result->m_databaseName); -} - -Vector<char> DatabaseNameKey::encode(const String& origin, const String& databaseName) -{ - Vector<char> ret = KeyPrefix::encodeEmpty(); - ret.appendVector(encodeByte(DatabaseNameTypeByte)); - ret.appendVector(encodeStringWithLength(origin)); - ret.appendVector(encodeStringWithLength(databaseName)); - return ret; -} - -Vector<char> DatabaseNameKey::encodeMinKeyForOrigin(const String& origin) -{ - return encode(origin, ""); -} - -Vector<char> DatabaseNameKey::encodeStopKeyForOrigin(const String& origin) -{ - // just after origin in collation order - return encodeMinKeyForOrigin(origin + "\x01"); -} - -int DatabaseNameKey::compare(const DatabaseNameKey& other) -{ - if (int x = codePointCompare(m_origin, other.m_origin)) - return x; - return codePointCompare(m_databaseName, other.m_databaseName); -} - -Vector<char> DatabaseMetaDataKey::encode(int64_t databaseId, MetaDataType metaDataType) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(metaDataType)); - return ret; -} - -ObjectStoreMetaDataKey::ObjectStoreMetaDataKey() - : m_objectStoreId(-1) - , m_metaDataType(-1) -{ -} - -const char* ObjectStoreMetaDataKey::decode(const char* start, const char* limit, ObjectStoreMetaDataKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == ObjectStoreMetaDataTypeByte); - if (p == limit) - return 0; - p = decodeVarInt(p, limit, result->m_objectStoreId); - if (!p) - return 0; - ASSERT(result->m_objectStoreId); - if (p == limit) - return 0; - return decodeByte(p, limit, result->m_metaDataType); -} - -Vector<char> ObjectStoreMetaDataKey::encode(int64_t databaseId, int64_t objectStoreId, unsigned char metaDataType) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(ObjectStoreMetaDataTypeByte)); - ret.appendVector(encodeVarInt(objectStoreId)); - ret.appendVector(encodeByte(metaDataType)); - return ret; -} - -Vector<char> ObjectStoreMetaDataKey::encodeMaxKey(int64_t databaseId) -{ - return encode(databaseId, INT64_MAX, ObjectMetaDataTypeMaximum); -} - -Vector<char> ObjectStoreMetaDataKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId) -{ - return encode(databaseId, objectStoreId, ObjectMetaDataTypeMaximum); -} - -int64_t ObjectStoreMetaDataKey::objectStoreId() const -{ - ASSERT(m_objectStoreId >= 0); - return m_objectStoreId; -} -unsigned char ObjectStoreMetaDataKey::metaDataType() const -{ - return m_metaDataType; -} - -int ObjectStoreMetaDataKey::compare(const ObjectStoreMetaDataKey& other) -{ - ASSERT(m_objectStoreId >= 0); - if (int x = compareInts(m_objectStoreId, other.m_objectStoreId)) - return x; - int64_t result = m_metaDataType - other.m_metaDataType; - if (result < 0) - return -1; - return (result > 0) ? 1 : result; -} - -IndexMetaDataKey::IndexMetaDataKey() - : m_objectStoreId(-1) - , m_indexId(-1) - , m_metaDataType(0) -{ -} - -const char* IndexMetaDataKey::decode(const char* start, const char* limit, IndexMetaDataKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == IndexMetaDataTypeByte); - if (p == limit) - return 0; - p = decodeVarInt(p, limit, result->m_objectStoreId); - if (!p) - return 0; - p = decodeVarInt(p, limit, result->m_indexId); - if (!p) - return 0; - if (p == limit) - return 0; - return decodeByte(p, limit, result->m_metaDataType); -} - -Vector<char> IndexMetaDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, unsigned char metaDataType) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(IndexMetaDataTypeByte)); - ret.appendVector(encodeVarInt(objectStoreId)); - ret.appendVector(encodeVarInt(indexId)); - ret.appendVector(encodeByte(metaDataType)); - return ret; -} - -Vector<char> IndexMetaDataKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId) -{ - return encode(databaseId, objectStoreId, INT64_MAX, IndexMetaDataTypeMaximum); -} - -Vector<char> IndexMetaDataKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - return encode(databaseId, objectStoreId, indexId, IndexMetaDataTypeMaximum); -} - -int IndexMetaDataKey::compare(const IndexMetaDataKey& other) -{ - ASSERT(m_objectStoreId >= 0); - ASSERT(m_indexId >= 0); - - if (int x = compareInts(m_objectStoreId, other.m_objectStoreId)) - return x; - if (int x = compareInts(m_indexId, other.m_indexId)) - return x; - return m_metaDataType - other.m_metaDataType; -} - -int64_t IndexMetaDataKey::indexId() const -{ - ASSERT(m_indexId >= 0); - return m_indexId; -} - -ObjectStoreFreeListKey::ObjectStoreFreeListKey() - : m_objectStoreId(-1) -{ -} - -const char* ObjectStoreFreeListKey::decode(const char* start, const char* limit, ObjectStoreFreeListKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == ObjectStoreFreeListTypeByte); - if (p == limit) - return 0; - return decodeVarInt(p, limit, result->m_objectStoreId); -} - -Vector<char> ObjectStoreFreeListKey::encode(int64_t databaseId, int64_t objectStoreId) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(ObjectStoreFreeListTypeByte)); - ret.appendVector(encodeVarInt(objectStoreId)); - return ret; -} - -Vector<char> ObjectStoreFreeListKey::encodeMaxKey(int64_t databaseId) -{ - return encode(databaseId, INT64_MAX); -} - -int64_t ObjectStoreFreeListKey::objectStoreId() const -{ - ASSERT(m_objectStoreId >= 0); - return m_objectStoreId; -} - -int ObjectStoreFreeListKey::compare(const ObjectStoreFreeListKey& other) -{ - // FIXME: It may seem strange that we're not comparing database id's, - // but that comparison will have been made earlier. - // We should probably make this more clear, though... - ASSERT(m_objectStoreId >= 0); - return compareInts(m_objectStoreId, other.m_objectStoreId); -} - -IndexFreeListKey::IndexFreeListKey() - : m_objectStoreId(-1) - , m_indexId(-1) -{ -} - -const char* IndexFreeListKey::decode(const char* start, const char* limit, IndexFreeListKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == IndexFreeListTypeByte); - if (p == limit) - return 0; - p = decodeVarInt(p, limit, result->m_objectStoreId); - if (!p) - return 0; - return decodeVarInt(p, limit, result->m_indexId); -} - -Vector<char> IndexFreeListKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(IndexFreeListTypeByte)); - ret.appendVector(encodeVarInt(objectStoreId)); - ret.appendVector(encodeVarInt(indexId)); - return ret; -} - -Vector<char> IndexFreeListKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId) -{ - return encode(databaseId, objectStoreId, INT64_MAX); -} - -int IndexFreeListKey::compare(const IndexFreeListKey& other) -{ - ASSERT(m_objectStoreId >= 0); - ASSERT(m_indexId >= 0); - if (int x = compareInts(m_objectStoreId, other.m_objectStoreId)) - return x; - return compareInts(m_indexId, other.m_indexId); -} - -int64_t IndexFreeListKey::objectStoreId() const -{ - ASSERT(m_objectStoreId >= 0); - return m_objectStoreId; -} - -int64_t IndexFreeListKey::indexId() const -{ - ASSERT(m_indexId >= 0); - return m_indexId; -} - -// FIXME: We never use this to look up object store ids, because a mapping -// is kept in the IDBDatabaseBackend. Can the mapping become unreliable? -// Can we remove this? -const char* ObjectStoreNamesKey::decode(const char* start, const char* limit, ObjectStoreNamesKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == ObjectStoreNamesTypeByte); - return decodeStringWithLength(p, limit, result->m_objectStoreName); -} - -Vector<char> ObjectStoreNamesKey::encode(int64_t databaseId, const String& objectStoreName) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(ObjectStoreNamesTypeByte)); - ret.appendVector(encodeStringWithLength(objectStoreName)); - return ret; -} - -int ObjectStoreNamesKey::compare(const ObjectStoreNamesKey& other) -{ - return codePointCompare(m_objectStoreName, other.m_objectStoreName); -} - -IndexNamesKey::IndexNamesKey() - : m_objectStoreId(-1) -{ -} - -// FIXME: We never use this to look up index ids, because a mapping -// is kept at a higher level. -const char* IndexNamesKey::decode(const char* start, const char* limit, IndexNamesKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(!prefix.m_objectStoreId); - ASSERT(!prefix.m_indexId); - if (p == limit) - return 0; - unsigned char typeByte = 0; - p = decodeByte(p, limit, typeByte); - ASSERT_UNUSED(typeByte, typeByte == IndexNamesKeyTypeByte); - if (p == limit) - return 0; - p = decodeVarInt(p, limit, result->m_objectStoreId); - if (!p) - return 0; - return decodeStringWithLength(p, limit, result->m_indexName); -} - -Vector<char> IndexNamesKey::encode(int64_t databaseId, int64_t objectStoreId, const String& indexName) -{ - KeyPrefix prefix(databaseId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodeByte(IndexNamesKeyTypeByte)); - ret.appendVector(encodeVarInt(objectStoreId)); - ret.appendVector(encodeStringWithLength(indexName)); - return ret; -} - -int IndexNamesKey::compare(const IndexNamesKey& other) -{ - ASSERT(m_objectStoreId >= 0); - if (int x = compareInts(m_objectStoreId, other.m_objectStoreId)) - return x; - return codePointCompare(m_indexName, other.m_indexName); -} - -const char* ObjectStoreDataKey::decode(const char* start, const char* end, ObjectStoreDataKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, end, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(prefix.m_objectStoreId); - ASSERT(prefix.m_indexId == SpecialIndexNumber); - if (p == end) - return 0; - return extractEncodedIDBKey(p, end, &result->m_encodedUserKey); -} - -Vector<char> ObjectStoreDataKey::encode(int64_t databaseId, int64_t objectStoreId, const Vector<char> encodedUserKey) -{ - KeyPrefix prefix(KeyPrefix::createWithSpecialIndex(databaseId, objectStoreId, SpecialIndexNumber)); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodedUserKey); - - return ret; -} - -Vector<char> ObjectStoreDataKey::encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey) -{ - return encode(databaseId, objectStoreId, encodeIDBKey(userKey)); -} - -int ObjectStoreDataKey::compare(const ObjectStoreDataKey& other, bool& ok) -{ - return compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey, ok); -} - -PassRefPtr<IDBKey> ObjectStoreDataKey::userKey() const -{ - RefPtr<IDBKey> key; - decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key); - return key; -} - -const int64_t ObjectStoreDataKey::SpecialIndexNumber = ObjectStoreDataIndexId; - -const char* ExistsEntryKey::decode(const char* start, const char* end, ExistsEntryKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, end, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(prefix.m_objectStoreId); - ASSERT(prefix.m_indexId == SpecialIndexNumber); - if (p == end) - return 0; - return extractEncodedIDBKey(p, end, &result->m_encodedUserKey); -} - -Vector<char> ExistsEntryKey::encode(int64_t databaseId, int64_t objectStoreId, const Vector<char>& encodedKey) -{ - KeyPrefix prefix(KeyPrefix::createWithSpecialIndex(databaseId, objectStoreId, SpecialIndexNumber)); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodedKey); - return ret; -} - -Vector<char> ExistsEntryKey::encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey) -{ - return encode(databaseId, objectStoreId, encodeIDBKey(userKey)); -} - -int ExistsEntryKey::compare(const ExistsEntryKey& other, bool& ok) -{ - return compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey, ok); -} - -PassRefPtr<IDBKey> ExistsEntryKey::userKey() const -{ - RefPtr<IDBKey> key; - decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key); - return key; -} - -const int64_t ExistsEntryKey::SpecialIndexNumber = ExistsEntryIndexId; - -IndexDataKey::IndexDataKey() - : m_databaseId(-1) - , m_objectStoreId(-1) - , m_indexId(-1) - , m_sequenceNumber(-1) -{ -} - -const char* IndexDataKey::decode(const char* start, const char* limit, IndexDataKey* result) -{ - KeyPrefix prefix; - const char* p = KeyPrefix::decode(start, limit, &prefix); - if (!p) - return 0; - ASSERT(prefix.m_databaseId); - ASSERT(prefix.m_objectStoreId); - ASSERT(prefix.m_indexId >= MinimumIndexId); - result->m_databaseId = prefix.m_databaseId; - result->m_objectStoreId = prefix.m_objectStoreId; - result->m_indexId = prefix.m_indexId; - result->m_sequenceNumber = -1; - result->m_encodedPrimaryKey = minIDBKey(); - - p = extractEncodedIDBKey(p, limit, &result->m_encodedUserKey); - if (!p) - return 0; - - // [optional] sequence number - if (p == limit) - return p; - p = decodeVarInt(p, limit, result->m_sequenceNumber); - if (!p) - return 0; - - // [optional] primary key - if (p == limit) - return p; - p = extractEncodedIDBKey(p, limit, &result->m_encodedPrimaryKey); - if (!p) - return 0; - - return p; -} - -Vector<char> IndexDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const Vector<char>& encodedUserKey, const Vector<char>& encodedPrimaryKey, int64_t sequenceNumber) -{ - KeyPrefix prefix(databaseId, objectStoreId, indexId); - Vector<char> ret = prefix.encode(); - ret.appendVector(encodedUserKey); - ret.appendVector(encodeVarInt(sequenceNumber)); - ret.appendVector(encodedPrimaryKey); - return ret; -} - -Vector<char> IndexDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& userKey) -{ - return encode(databaseId, objectStoreId, indexId, encodeIDBKey(userKey), minIDBKey()); -} - -Vector<char> IndexDataKey::encodeMinKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - return encode(databaseId, objectStoreId, indexId, minIDBKey(), minIDBKey()); -} - -Vector<char> IndexDataKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId) -{ - return encode(databaseId, objectStoreId, indexId, maxIDBKey(), maxIDBKey(), INT64_MAX); -} - -int IndexDataKey::compare(const IndexDataKey& other, bool ignoreDuplicates, bool& ok) -{ - ASSERT(m_databaseId >= 0); - ASSERT(m_objectStoreId >= 0); - ASSERT(m_indexId >= 0); - int result = compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey, ok); - if (!ok || result) - return result; - if (ignoreDuplicates) - return 0; - result = compareEncodedIDBKeys(m_encodedPrimaryKey, other.m_encodedPrimaryKey, ok); - if (!ok || result) - return result; - return compareInts(m_sequenceNumber, other.m_sequenceNumber); -} - -int64_t IndexDataKey::databaseId() const -{ - ASSERT(m_databaseId >= 0); - return m_databaseId; -} - -int64_t IndexDataKey::objectStoreId() const -{ - ASSERT(m_objectStoreId >= 0); - return m_objectStoreId; -} - -int64_t IndexDataKey::indexId() const -{ - ASSERT(m_indexId >= 0); - return m_indexId; -} - -PassRefPtr<IDBKey> IndexDataKey::userKey() const -{ - RefPtr<IDBKey> key; - decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key); - return key; -} - -PassRefPtr<IDBKey> IndexDataKey::primaryKey() const -{ - RefPtr<IDBKey> key; - decodeIDBKey(m_encodedPrimaryKey.begin(), m_encodedPrimaryKey.end(), key); - return key; -} - -} // namespace IDBLevelDBCoding -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.h deleted file mode 100644 index 9ac39bfd3..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBLevelDBCoding.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBLevelDBCoding_h -#define IDBLevelDBCoding_h - -#if ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -class IDBKey; -class IDBKeyPath; -class LevelDBSlice; - -namespace IDBLevelDBCoding { - -const unsigned char MinimumIndexId = 30; - -// As most of the IDBKeys and encoded values are short, we initialize some Vectors with a default inline buffer size -// to reduce the memory re-allocations when the Vectors are appended. -static const size_t DefaultInlineBufferSize = 32; - -Vector<char> encodeByte(unsigned char); -const char* decodeByte(const char* p, const char* limit, unsigned char& foundChar); -Vector<char> maxIDBKey(); -Vector<char> minIDBKey(); -Vector<char> encodeBool(bool); -bool decodeBool(const char* begin, const char* end); -Vector<char> encodeInt(int64_t); -inline Vector<char> encodeIntSafely(int64_t nParam, int64_t max) -{ - ASSERT_UNUSED(max, nParam <= max); - return encodeInt(nParam); -} -int64_t decodeInt(const char* begin, const char* end); -Vector<char> encodeVarInt(int64_t); -const char* decodeVarInt(const char* p, const char* limit, int64_t& foundInt); -Vector<char> encodeString(const String&); -String decodeString(const char* p, const char* end); -Vector<char> encodeStringWithLength(const String&); -const char* decodeStringWithLength(const char* p, const char* limit, String& foundString); -int compareEncodedStringsWithLength(const char*& p, const char* limitP, const char*& q, const char* limitQ, bool& ok); -Vector<char> encodeDouble(double); -const char* decodeDouble(const char* p, const char* limit, double*); -void encodeIDBKey(const IDBKey&, Vector<char, DefaultInlineBufferSize>& into); -Vector<char> encodeIDBKey(const IDBKey&); -const char* decodeIDBKey(const char* p, const char* limit, RefPtr<IDBKey>& foundKey); -const char* extractEncodedIDBKey(const char* start, const char* limit, Vector<char>* result); -int compareEncodedIDBKeys(const Vector<char>&, const Vector<char>&, bool& ok); -Vector<char> encodeIDBKeyPath(const IDBKeyPath&); -IDBKeyPath decodeIDBKeyPath(const char*, const char*); - -int compare(const LevelDBSlice&, const LevelDBSlice&, bool indexKeys = false); - -class KeyPrefix { -public: - KeyPrefix(); - explicit KeyPrefix(int64_t databaseId); - KeyPrefix(int64_t databaseId, int64_t objectStoreId); - KeyPrefix(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - static KeyPrefix createWithSpecialIndex(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - - static const char* decode(const char* start, const char* limit, KeyPrefix* result); - Vector<char> encode() const; - static Vector<char> encodeEmpty(); - int compare(const KeyPrefix& other) const; - - enum Type { - GlobalMetaData, - DatabaseMetaData, - ObjectStoreData, - ExistsEntry, - IndexData, - InvalidType - }; - - static const size_t kMaxDatabaseIdSizeBits = 3; - static const size_t kMaxObjectStoreIdSizeBits = 3; - static const size_t kMaxIndexIdSizeBits = 2; - - static const size_t kMaxDatabaseIdSizeBytes = 1ULL << kMaxDatabaseIdSizeBits; // 8 - static const size_t kMaxObjectStoreIdSizeBytes = 1ULL << kMaxObjectStoreIdSizeBits; // 8 - static const size_t kMaxIndexIdSizeBytes = 1ULL << kMaxIndexIdSizeBits; // 4 - - static const size_t kMaxDatabaseIdBits = kMaxDatabaseIdSizeBytes * 8 - 1; // 63 - static const size_t kMaxObjectStoreIdBits = kMaxObjectStoreIdSizeBytes * 8 - 1; // 63 - static const size_t kMaxIndexIdBits = kMaxIndexIdSizeBytes * 8 - 1; // 31 - - static const int64_t kMaxDatabaseId = (1ULL << kMaxDatabaseIdBits) - 1; // max signed int64_t - static const int64_t kMaxObjectStoreId = (1ULL << kMaxObjectStoreIdBits) - 1; // max signed int64_t - static const int64_t kMaxIndexId = (1ULL << kMaxIndexIdBits) - 1; // max signed int32_t - - static bool isValidDatabaseId(int64_t databaseId); - static bool isValidObjectStoreId(int64_t indexId); - static bool isValidIndexId(int64_t indexId); - static bool validIds(int64_t databaseId, int64_t objectStoreId, int64_t indexId) - { - return isValidDatabaseId(databaseId) && isValidObjectStoreId(objectStoreId) && isValidIndexId(indexId); - } - static bool validIds(int64_t databaseId, int64_t objectStoreId) - { - return isValidDatabaseId(databaseId) && isValidObjectStoreId(objectStoreId); - } - - Type type() const; - - int64_t m_databaseId; - int64_t m_objectStoreId; - int64_t m_indexId; - - static const int64_t InvalidId = -1; - -private: - static Vector<char> encodeInternal(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - // Special constructor for createWithSpecialIndex() - KeyPrefix(Type, int64_t databaseId, int64_t objectStoreId, int64_t indexId); -}; - -class SchemaVersionKey { -public: - static Vector<char> encode(); -}; - -class MaxDatabaseIdKey { -public: - static Vector<char> encode(); -}; - -class DataVersionKey { -public: - static Vector<char> encode(); -}; - -class DatabaseFreeListKey { -public: - DatabaseFreeListKey(); - static const char* decode(const char* start, const char* limit, DatabaseFreeListKey* result); - static Vector<char> encode(int64_t databaseId); - static Vector<char> encodeMaxKey(); - int64_t databaseId() const; - int compare(const DatabaseFreeListKey& other) const; - -private: - int64_t m_databaseId; -}; - -class DatabaseNameKey { -public: - static const char* decode(const char* start, const char* limit, DatabaseNameKey* result); - static Vector<char> encode(const String& origin, const String& databaseName); - static Vector<char> encodeMinKeyForOrigin(const String& origin); - static Vector<char> encodeStopKeyForOrigin(const String& origin); - String origin() const { return m_origin; } - String databaseName() const { return m_databaseName; } - int compare(const DatabaseNameKey& other); - -private: - String m_origin; // FIXME: Store encoded strings, or just pointers. - String m_databaseName; -}; - -class DatabaseMetaDataKey { -public: - enum MetaDataType { - OriginName = 0, - DatabaseName = 1, - UserVersion = 2, - MaxObjectStoreId = 3, - UserIntVersion = 4, - MaxSimpleMetaDataType = 5 - }; - - static Vector<char> encode(int64_t databaseId, MetaDataType); -}; - -class ObjectStoreMetaDataKey { -public: - enum MetaDataType { - Name = 0, - KeyPath = 1, - AutoIncrement = 2, - Evictable = 3, - LastVersion = 4, - MaxIndexId = 5, - HasKeyPath = 6, - KeyGeneratorCurrentNumber = 7 - }; - - ObjectStoreMetaDataKey(); - static const char* decode(const char* start, const char* limit, ObjectStoreMetaDataKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, unsigned char metaDataType); - static Vector<char> encodeMaxKey(int64_t databaseId); - static Vector<char> encodeMaxKey(int64_t databaseId, int64_t objectStoreId); - int64_t objectStoreId() const; - unsigned char metaDataType() const; - int compare(const ObjectStoreMetaDataKey& other); - -private: - int64_t m_objectStoreId; - unsigned char m_metaDataType; -}; - -class IndexMetaDataKey { -public: - enum MetaDataType { - Name = 0, - Unique = 1, - KeyPath = 2, - MultiEntry = 3 - }; - - IndexMetaDataKey(); - static const char* decode(const char* start, const char* limit, IndexMetaDataKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, unsigned char metaDataType); - static Vector<char> encodeMaxKey(int64_t databaseId, int64_t objectStoreId); - static Vector<char> encodeMaxKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - int compare(const IndexMetaDataKey& other); - int64_t indexId() const; - unsigned char metaDataType() const { return m_metaDataType; } - -private: - int64_t m_objectStoreId; - int64_t m_indexId; - unsigned char m_metaDataType; -}; - -class ObjectStoreFreeListKey { -public: - ObjectStoreFreeListKey(); - static const char* decode(const char* start, const char* limit, ObjectStoreFreeListKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId); - static Vector<char> encodeMaxKey(int64_t databaseId); - int64_t objectStoreId() const; - int compare(const ObjectStoreFreeListKey& other); - -private: - int64_t m_objectStoreId; -}; - -class IndexFreeListKey { -public: - IndexFreeListKey(); - static const char* decode(const char* start, const char* limit, IndexFreeListKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - static Vector<char> encodeMaxKey(int64_t databaseId, int64_t objectStoreId); - int compare(const IndexFreeListKey& other); - int64_t objectStoreId() const; - int64_t indexId() const; - -private: - int64_t m_objectStoreId; - int64_t m_indexId; -}; - -class ObjectStoreNamesKey { -public: - // FIXME: We never use this to look up object store ids, because a mapping - // is kept in the IDBDatabaseBackend. Can the mapping become unreliable? - // Can we remove this? - static const char* decode(const char* start, const char* limit, ObjectStoreNamesKey* result); - static Vector<char> encode(int64_t databaseId, const String& objectStoreName); - int compare(const ObjectStoreNamesKey& other); - String objectStoreName() const { return m_objectStoreName; } - -private: - String m_objectStoreName; // FIXME: Store the encoded string, or just pointers to it. -}; - -class IndexNamesKey { -public: - IndexNamesKey(); - // FIXME: We never use this to look up index ids, because a mapping - // is kept at a higher level. - static const char* decode(const char* start, const char* limit, IndexNamesKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, const String& indexName); - int compare(const IndexNamesKey& other); - String indexName() const { return m_indexName; } - -private: - int64_t m_objectStoreId; - String m_indexName; -}; - -class ObjectStoreDataKey { -public: - static const char* decode(const char* start, const char* end, ObjectStoreDataKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, const Vector<char> encodedUserKey); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey); - int compare(const ObjectStoreDataKey& other, bool& ok); - PassRefPtr<IDBKey> userKey() const; - static const int64_t SpecialIndexNumber; - -private: - Vector<char> m_encodedUserKey; -}; - -class ExistsEntryKey { -public: - static const char* decode(const char* start, const char* end, ExistsEntryKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, const Vector<char>& encodedKey); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey); - int compare(const ExistsEntryKey& other, bool& ok); - PassRefPtr<IDBKey> userKey() const; - - static const int64_t SpecialIndexNumber; - -private: - Vector<char> m_encodedUserKey; -}; - -class IndexDataKey { -public: - IndexDataKey(); - static const char* decode(const char* start, const char* limit, IndexDataKey* result); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const Vector<char>& encodedUserKey, const Vector<char>& encodedPrimaryKey, int64_t sequenceNumber = 0); - static Vector<char> encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& userKey); - static Vector<char> encodeMinKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - static Vector<char> encodeMaxKey(int64_t databaseId, int64_t objectStoreId, int64_t indexId); - int compare(const IndexDataKey& other, bool ignoreDuplicates, bool& ok); - int64_t databaseId() const; - int64_t objectStoreId() const; - int64_t indexId() const; - PassRefPtr<IDBKey> userKey() const; - PassRefPtr<IDBKey> primaryKey() const; - -private: - int64_t m_databaseId; - int64_t m_objectStoreId; - int64_t m_indexId; - Vector<char> m_encodedUserKey; - Vector<char> m_encodedPrimaryKey; - int64_t m_sequenceNumber; -}; - -} // namespace IDBLevelDBCoding - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) && USE(LEVELDB) - -#endif // IDBLevelDBCoding_h diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.cpp b/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.cpp deleted file mode 100644 index b7333f965..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "IDBServerConnectionLevelDB.h" - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -#include "IDBBackingStoreCursorLevelDB.h" -#include "IDBBackingStoreLevelDB.h" -#include "IDBBackingStoreTransactionLevelDB.h" -#include "IDBCursorBackend.h" -#include "IDBFactoryBackendLevelDB.h" -#include "IDBIndexWriterLevelDB.h" -#include <wtf/MainThread.h> - -#define ASYNC_COMPLETION_CALLBACK_WITH_ARG(callback, arg) \ - callOnMainThread([callback, arg]() { \ - callback(arg); \ - }); - -#define ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(callback, arg1, arg2) \ - callOnMainThread([callback]() { \ - callback(arg1, arg2); \ - }); - -#define ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(callback) \ - callOnMainThread([callback]() { \ - callback(0); \ - }); - -#define EMPTY_ASYNC_COMPLETION_CALLBACK(callback) \ - callOnMainThread([callback]() { \ - callback(); \ - }); - - -namespace WebCore { - -IDBServerConnectionLevelDB::IDBServerConnectionLevelDB(const String& databaseName, IDBBackingStoreLevelDB* backingStore) - : m_backingStore(backingStore) - , m_nextCursorID(1) - , m_closed(false) - , m_databaseName(databaseName) -{ -} - -IDBServerConnectionLevelDB::~IDBServerConnectionLevelDB() -{ -} - -bool IDBServerConnectionLevelDB::isClosed() -{ - return m_closed; -} - -void IDBServerConnectionLevelDB::getOrEstablishIDBDatabaseMetadata(GetIDBDatabaseMetadataFunction callback) -{ - RefPtr<IDBServerConnection> self(this); - m_backingStore->getOrEstablishIDBDatabaseMetadata(m_databaseName, [self, this, callback](const IDBDatabaseMetadata& metadata, bool success) { - callback(metadata, success); - }); -} - -void IDBServerConnectionLevelDB::deleteDatabase(const String& name, BoolCallbackFunction successCallback) -{ - RefPtr<IDBServerConnection> self(this); - m_backingStore->deleteDatabase(name, [self, this, successCallback](bool success) { - successCallback(success); - }); -} - -void IDBServerConnectionLevelDB::close() -{ - m_backingStore.clear(); - m_closed = true; -} - -void IDBServerConnectionLevelDB::openTransaction(int64_t transactionID, const HashSet<int64_t>&, IndexedDB::TransactionMode, BoolCallbackFunction successCallback) -{ - if (!m_backingStore) { - callOnMainThread([successCallback]() { - successCallback(false); - }); - return; - } - - m_backingStore->establishBackingStoreTransaction(transactionID); - callOnMainThread([successCallback]() { - successCallback(true); - }); -} - -void IDBServerConnectionLevelDB::beginTransaction(int64_t transactionID, std::function<void()> completionCallback) -{ - RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID); - ASSERT(transaction); - - transaction->begin(); - callOnMainThread(completionCallback); -} - -void IDBServerConnectionLevelDB::commitTransaction(int64_t transactionID, BoolCallbackFunction successCallback) -{ - RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID); - ASSERT(transaction); - - bool result = transaction->commit(); - callOnMainThread([successCallback, result]() { - successCallback(result); - }); -} - -void IDBServerConnectionLevelDB::resetTransaction(int64_t transactionID, std::function<void()> completionCallback) -{ - RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID); - ASSERT(transaction); - - transaction->resetTransaction(); - callOnMainThread(completionCallback); -} - -void IDBServerConnectionLevelDB::rollbackTransaction(int64_t transactionID, std::function<void()> completionCallback) -{ - RefPtr<IDBBackingStoreTransactionLevelDB> transaction = m_backingStoreTransactions.get(transactionID); - ASSERT(transaction); - - transaction->rollback(); - callOnMainThread(completionCallback); -} - -void IDBServerConnectionLevelDB::setIndexKeys(int64_t transactionID, int64_t databaseID, int64_t objectStoreID, const IDBObjectStoreMetadata& objectStoreMetadata, IDBKey& primaryKey, const Vector<int64_t>& indexIDs, const Vector<Vector<RefPtr<IDBKey>>>& indexKeys, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - RefPtr<IDBBackingStoreTransactionLevelDB> backingStoreTransaction = m_backingStoreTransactions.get(transactionID); - ASSERT(backingStoreTransaction); - - RefPtr<IDBRecordIdentifier> recordIdentifier; - bool ok = m_backingStore->keyExistsInObjectStore(*backingStoreTransaction, databaseID, objectStoreID, primaryKey, recordIdentifier); - if (!ok) { - callOnMainThread([completionCallback]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: setting index keys.")); - }); - return; - } - if (!recordIdentifier) { - callOnMainThread([completionCallback]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: setting index keys for object store.")); - }); - return; - } - - Vector<RefPtr<IDBIndexWriterLevelDB>> indexWriters; - String errorMessage; - bool obeysConstraints = false; - - bool backingStoreSuccess = m_backingStore->makeIndexWriters(transactionID, databaseID, objectStoreMetadata, primaryKey, false, indexIDs, indexKeys, indexWriters, &errorMessage, obeysConstraints); - if (!backingStoreSuccess) { - callOnMainThread([completionCallback]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys.")); - }); - return; - } - if (!obeysConstraints) { - callOnMainThread([completionCallback, errorMessage]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage)); - }); - return; - } - - for (size_t i = 0; i < indexWriters.size(); ++i) { - IDBIndexWriterLevelDB* indexWriter = indexWriters[i].get(); - indexWriter->writeIndexKeys(recordIdentifier.get(), *m_backingStore, *backingStoreTransaction, databaseID, objectStoreID); - } - - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::createObjectStore(IDBTransactionBackend& transaction, const CreateObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - String objectStoreName = operation.objectStoreMetadata().name; - - if (!m_backingStore->createObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStoreMetadata().id, objectStoreName, operation.objectStoreMetadata().keyPath, operation.objectStoreMetadata().autoIncrement)) { - callOnMainThread([completionCallback, objectStoreName]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", objectStoreName.utf8().data()))); - }); - return; - } - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::createIndex(IDBTransactionBackend& transaction, const CreateIndexOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - const IDBIndexMetadata& indexMetadata = operation.idbIndexMetadata(); - if (!m_backingStore->createIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), indexMetadata.id, indexMetadata.name, indexMetadata.keyPath, indexMetadata.unique, indexMetadata.multiEntry)) { - callOnMainThread([completionCallback, indexMetadata]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", indexMetadata.name.utf8().data()))); - }); - return; - } - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::deleteIndex(IDBTransactionBackend& transaction, const DeleteIndexOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - const IDBIndexMetadata& indexMetadata = operation.idbIndexMetadata(); - if (!m_backingStore->deleteIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), indexMetadata.id)) { - callOnMainThread([completionCallback, indexMetadata]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting index '%s'.", indexMetadata.name.utf8().data()))); - }); - return; - } - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::get(IDBTransactionBackend& transaction, const GetOperation& operation, std::function<void(const IDBGetResult&, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - RefPtr<IDBKey> key; - - if (operation.keyRange()->isOnlyKey()) - key = operation.keyRange()->lower(); - else { - RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor; - int64_t cursorID = m_nextCursorID++; - - if (operation.indexID() == IDBIndexMetadata::InvalidId) { - ASSERT(operation.cursorType() != IndexedDB::CursorType::KeyOnly); - // ObjectStore Retrieval Operation - backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - } else { - if (operation.cursorType() == IndexedDB::CursorType::KeyOnly) { - // Index Value Retrieval Operation - backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - } else { - // Index Referenced Value Retrieval Operation - backingStoreCursor = m_backingStore->openIndexCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - } - } - - if (!backingStoreCursor) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr); - return; - } - - key = backingStoreCursor->key(); - } - - RefPtr<IDBKey> primaryKey; - bool ok; - if (operation.indexID() == IDBIndexMetadata::InvalidId) { - // Object Store Retrieval Operation - Vector<char> value; - ok = m_backingStore->getRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), *key, value); - if (!ok) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord.")); - return; - } - - if (value.isEmpty()) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr); - return; - } - - IDBGetResult result; - - if (operation.autoIncrement() && !operation.keyPath().isNull()) - result = IDBGetResult(SharedBuffer::adoptVector(value), key, operation.keyPath()); - else - result = IDBGetResult(SharedBuffer::adoptVector(value)); - - callOnMainThread([completionCallback, result]() { - completionCallback(result, nullptr); - }); - return; - } - - // From here we are dealing only with indexes. - ok = m_backingStore->getPrimaryKeyViaIndex(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), *key, primaryKey); - if (!ok) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex.")); - return; - } - if (!primaryKey) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr); - return; - } - if (operation.cursorType() == IndexedDB::CursorType::KeyOnly) { - // Index Value Retrieval Operation - IDBGetResult result(primaryKey.release()); - callOnMainThread([completionCallback, result]() { - completionCallback(result, nullptr); - }); - return; - } - - // Index Referenced Value Retrieval Operation - Vector<char> value; - ok = m_backingStore->getRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), *primaryKey, value); - if (!ok) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord.")); - return; - } - - if (value.isEmpty()) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, IDBGetResult(), nullptr); - return; - } - if (operation.autoIncrement() && !operation.keyPath().isNull()) { - IDBGetResult result(SharedBuffer::adoptVector(value), key, operation.keyPath()); - callOnMainThread([completionCallback, result]() { - completionCallback(result, nullptr); - }); - - return; - } - - IDBGetResult result(SharedBuffer::adoptVector(value)); - callOnMainThread([completionCallback, result]() { - completionCallback(result, nullptr); - }); -} - -void IDBServerConnectionLevelDB::put(IDBTransactionBackend& transaction, const PutOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - bool keyWasGenerated = false; - - RefPtr<IDBKey> key; - if (operation.putMode() != IDBDatabaseBackend::CursorUpdate && operation.objectStore().autoIncrement && !operation.key()) { - RefPtr<IDBKey> autoIncKey = m_backingStore->generateKey(transaction, transaction.database().id(), operation.objectStore().id); - keyWasGenerated = true; - if (!autoIncKey->isValid()) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached.")); - return; - } - key = autoIncKey; - } else - key = operation.key(); - - ASSERT(key); - ASSERT(key->isValid()); - - RefPtr<IDBRecordIdentifier> recordIdentifier; - if (operation.putMode() == IDBDatabaseBackend::AddOnly) { - bool ok = m_backingStore->keyExistsInObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStore().id, *key, recordIdentifier); - if (!ok) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence.")); - return; - } - if (recordIdentifier) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store.")); - return; - } - } - - Vector<RefPtr<IDBIndexWriterLevelDB>> indexWriters; - String errorMessage; - bool obeysConstraints = false; - bool backingStoreSuccess = m_backingStore->makeIndexWriters(transaction.id(), transaction.database().id(), operation.objectStore(), *key, keyWasGenerated, operation.indexIDs(), operation.indexKeys(), indexWriters, &errorMessage, obeysConstraints); - if (!backingStoreSuccess) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys.")); - return; - } - if (!obeysConstraints) { - callOnMainThread([completionCallback, errorMessage]() { \ - completionCallback(nullptr, IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage)); \ - }); - return; - } - - // Before this point, don't do any mutation. After this point, rollback the transaction in case of error. - backingStoreSuccess = m_backingStore->putRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStore().id, *key, operation.value(), recordIdentifier.get()); - if (!backingStoreSuccess) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add.")); - return; - } - - for (size_t i = 0; i < indexWriters.size(); ++i) { - IDBIndexWriterLevelDB* indexWriter = indexWriters[i].get(); - indexWriter->writeIndexKeys(recordIdentifier.get(), *m_backingStore, *backingStoreTransaction, transaction.database().id(), operation.objectStore().id); - } - - if (operation.objectStore().autoIncrement && operation.putMode() != IDBDatabaseBackend::CursorUpdate && key->type() == IDBKey::NumberType) { - bool ok = m_backingStore->updateKeyGenerator(transaction, transaction.database().id(), operation.objectStore().id, *key, !keyWasGenerated); - if (!ok) { - ASYNC_COMPLETION_CALLBACK_WITH_TWO_ARGS(completionCallback, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator.")); - return; - } - } - - callOnMainThread([completionCallback, key]() { \ - completionCallback(key.get(), nullptr); \ - }); -} - -void IDBServerConnectionLevelDB::openCursor(IDBTransactionBackend& transaction, const OpenCursorOperation& operation, std::function<void(int64_t, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - // The frontend has begun indexing, so this pauses the transaction - // until the indexing is complete. This can't happen any earlier - // because we don't want to switch to early mode in case multiple - // indexes are being created in a row, with put()'s in between. - if (operation.taskType() == IDBDatabaseBackend::PreemptiveTask) - transaction.addPreemptiveEvent(); - - int64_t cursorID = m_nextCursorID++; - - RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor; - if (operation.indexID() == IDBIndexMetadata::InvalidId) { - ASSERT(operation.cursorType() != IndexedDB::CursorType::KeyOnly); - backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), operation.direction()); - } else { - ASSERT(operation.taskType() == IDBDatabaseBackend::NormalTask); - if (operation.cursorType() == IndexedDB::CursorType::KeyOnly) - backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), operation.direction()); - else - backingStoreCursor = m_backingStore->openIndexCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), operation.direction()); - } - - if (!backingStoreCursor) { - // FIXME: Should it be an error to not have a backing store cursor? - cursorID = 0; - } - - callOnMainThread([completionCallback, cursorID]() { - completionCallback(cursorID, nullptr); - }); -} - -void IDBServerConnectionLevelDB::count(IDBTransactionBackend& transaction, const CountOperation& operation, std::function<void(int64_t, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - uint32_t count = 0; - RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor; - - int64_t cursorID = m_nextCursorID++; - - if (operation.indexID() == IDBIndexMetadata::InvalidId) - backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - else - backingStoreCursor = m_backingStore->openIndexKeyCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.indexID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - if (!backingStoreCursor) { - // FIXME: Is this an error case? - callOnMainThread([completionCallback, count]() { - completionCallback(count, nullptr); - }); - return; - } - - do { - ++count; - } while (backingStoreCursor->continueFunction(0)); - - callOnMainThread([completionCallback, count]() { - completionCallback(count, nullptr); - }); -} - -void IDBServerConnectionLevelDB::deleteRange(IDBTransactionBackend& transaction, const DeleteRangeOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - int64_t cursorID = m_nextCursorID++; - - RefPtr<IDBBackingStoreCursorLevelDB> backingStoreCursor = m_backingStore->openObjectStoreCursor(cursorID, *backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), operation.keyRange(), IndexedDB::CursorDirection::Next); - if (backingStoreCursor) { - do { - if (!m_backingStore->deleteRecord(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID(), backingStoreCursor->recordIdentifier())) { - callOnMainThread([completionCallback]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error deleting data in range")); - }); - return; - } - } while (backingStoreCursor->continueFunction(0)); - } - - callOnMainThread([completionCallback]() { - completionCallback(nullptr); - }); -} - -void IDBServerConnectionLevelDB::clearObjectStore(IDBTransactionBackend& transaction, const ClearObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - if (!m_backingStore->clearObjectStore(*backingStoreTransaction, transaction.database().id(), operation.objectStoreID())) { - callOnMainThread([completionCallback]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error clearing object store")); - }); - return; - } - - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::deleteObjectStore(IDBTransactionBackend& transaction, const DeleteObjectStoreOperation& operation, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - const IDBObjectStoreMetadata& objectStoreMetadata = operation.objectStoreMetadata(); - - if (!m_backingStore->deleteObjectStore(*backingStoreTransaction, transaction.database().id(), objectStoreMetadata.id)) { - callOnMainThread([completionCallback, objectStoreMetadata]() { - completionCallback(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", objectStoreMetadata.name.utf8().data()))); - }); - return; - } - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::changeDatabaseVersion(IDBTransactionBackend& transaction, const IDBDatabaseBackend::VersionChangeOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreTransactionLevelDB* backingStoreTransaction = m_backingStoreTransactions.get(transaction.id()); - ASSERT(backingStoreTransaction); - - IDBDatabaseBackend& database = transaction.database(); - int64_t databaseId = database.id(); - - if (!m_backingStore->updateIDBDatabaseVersion(*backingStoreTransaction, databaseId, database.metadata().version)) { - RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version."); - ASYNC_COMPLETION_CALLBACK_WITH_ARG(completionCallback, error); - return; - } - - ASYNC_COMPLETION_CALLBACK_WITH_NULL_ARG(completionCallback); -} - -void IDBServerConnectionLevelDB::cursorAdvance(IDBCursorBackend& cursor, const CursorAdvanceOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreCursorLevelDB* backingStoreCursor = cursor.id() ? m_backingStoreCursors.get(cursor.id()) : 0; -#ifndef NDEBUG - if (cursor.id()) - ASSERT(backingStoreCursor); -#endif - - if (!backingStoreCursor || !backingStoreCursor->advance(operation.count())) { - m_backingStoreCursors.remove(cursor.id()); - - callOnMainThread([completionCallback]() { - completionCallback(nullptr, nullptr, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor")); - }); - - return; - } - - RefPtr<IDBKey> key = backingStoreCursor->key(), primaryKey = backingStoreCursor->primaryKey(); - RefPtr<SharedBuffer> value = backingStoreCursor->value(); - - callOnMainThread([completionCallback, key, primaryKey, value]() { - completionCallback(key, primaryKey, value, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor")); - }); -} - -void IDBServerConnectionLevelDB::cursorIterate(IDBCursorBackend& cursor, const CursorIterationOperation& operation, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback) -{ - IDBBackingStoreCursorLevelDB* backingStoreCursor = cursor.id() ? m_backingStoreCursors.get(cursor.id()) : 0; -#ifndef NDEBUG - if (cursor.id()) - ASSERT(backingStoreCursor); -#endif - - if (!backingStoreCursor || !backingStoreCursor->continueFunction(operation.key())) { - m_backingStoreCursors.remove(cursor.id()); - - callOnMainThread([completionCallback]() { - completionCallback(nullptr, nullptr, nullptr, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor")); - }); - - return; - } - - RefPtr<IDBKey> key = backingStoreCursor->key(), primaryKey = backingStoreCursor->primaryKey(); - RefPtr<SharedBuffer> value = backingStoreCursor->value(); - - callOnMainThread([completionCallback, key, primaryKey, value]() { - completionCallback(key, primaryKey, value, IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Unknown error advancing cursor")); - }); -} - -} // namespace WebCore - -#endif // USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.h b/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.h deleted file mode 100644 index e574f389f..000000000 --- a/Source/WebCore/Modules/indexeddb/leveldb/IDBServerConnectionLevelDB.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef IDBServerConnectionLevelDB_h -#define IDBServerConnectionLevelDB_h - -#include "IDBServerConnection.h" - -#if ENABLE(INDEXED_DATABASE) -#if USE(LEVELDB) - -namespace WebCore { - -class IDBBackingStoreCursorLevelDB; -class IDBBackingStoreLevelDB; -class IDBBackingStoreTransactionLevelDB; - -class IDBServerConnectionLevelDB final : public IDBServerConnection { -public: - static PassRefPtr<IDBServerConnection> create(const String& databaseName, IDBBackingStoreLevelDB* backingStore) - { - return adoptRef(new IDBServerConnectionLevelDB(databaseName, backingStore)); - } - - virtual ~IDBServerConnectionLevelDB(); - - virtual bool isClosed() override; - - // Factory-level operations - virtual void deleteDatabase(const String& name, BoolCallbackFunction successCallback) override; - - // Database-level operations - virtual void getOrEstablishIDBDatabaseMetadata(GetIDBDatabaseMetadataFunction) override; - virtual void close() override; - - // Transaction-level operations - virtual void openTransaction(int64_t transactionID, const HashSet<int64_t>& objectStoreIds, IndexedDB::TransactionMode, BoolCallbackFunction successCallback) override; - virtual void beginTransaction(int64_t transactionID, std::function<void()> completionCallback) override; - virtual void commitTransaction(int64_t transactionID, BoolCallbackFunction successCallback) override; - virtual void resetTransaction(int64_t transactionID, std::function<void()> completionCallback) override; - virtual void rollbackTransaction(int64_t transactionID, std::function<void()> completionCallback) override; - virtual void setIndexKeys(int64_t transactionID, int64_t databaseID, int64_t objectStoreID, const IDBObjectStoreMetadata&, IDBKey& primaryKey, const Vector<int64_t>& indexIDs, const Vector<Vector<RefPtr<IDBKey>>>& indexKeys, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback); - - virtual void createObjectStore(IDBTransactionBackend&, const CreateObjectStoreOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void createIndex(IDBTransactionBackend&, const CreateIndexOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void deleteIndex(IDBTransactionBackend&, const DeleteIndexOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void get(IDBTransactionBackend&, const GetOperation&, std::function<void(const IDBGetResult&, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void put(IDBTransactionBackend&, const PutOperation&, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void openCursor(IDBTransactionBackend&, const OpenCursorOperation&, std::function<void(int64_t, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void count(IDBTransactionBackend&, const CountOperation&, std::function<void(int64_t, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void deleteRange(IDBTransactionBackend&, const DeleteRangeOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void clearObjectStore(IDBTransactionBackend&, const ClearObjectStoreOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void deleteObjectStore(IDBTransactionBackend&, const DeleteObjectStoreOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void changeDatabaseVersion(IDBTransactionBackend&, const IDBDatabaseBackend::VersionChangeOperation&, std::function<void(PassRefPtr<IDBDatabaseError>)> completionCallback) override; - - // Cursor-level operations - virtual void cursorAdvance(IDBCursorBackend&, const CursorAdvanceOperation&, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - virtual void cursorIterate(IDBCursorBackend&, const CursorIterationOperation&, std::function<void(PassRefPtr<IDBKey>, PassRefPtr<IDBKey>, PassRefPtr<SharedBuffer>, PassRefPtr<IDBDatabaseError>)> completionCallback) override; - -private: - IDBServerConnectionLevelDB(const String& databaseName, IDBBackingStoreLevelDB*); - - RefPtr<IDBBackingStoreLevelDB> m_backingStore; - HashMap<int64_t, RefPtr<IDBBackingStoreTransactionLevelDB>> m_backingStoreTransactions; - HashMap<int64_t, RefPtr<IDBBackingStoreCursorLevelDB>> m_backingStoreCursors; - - int64_t m_nextCursorID; - - bool m_closed; - - String m_databaseName; -}; - -} // namespace WebCore - -#endif // USE(LEVELDB) -#endif // ENABLE(INDEXED_DATABASE) -#endif // IDBServerConnectionLevelDB_h |