Diff
Modified: trunk/LayoutTests/ChangeLog (89947 => 89948)
--- trunk/LayoutTests/ChangeLog 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/LayoutTests/ChangeLog 2011-06-28 19:19:33 UTC (rev 89948)
@@ -1,3 +1,13 @@
+2011-06-28 Greg Simon <[email protected]>
+
+ Reviewed by Dimitri Glazkov.
+
+ Update migration LayoutTest to include indexes and successful migration.
+ https://bugs.webkit.org/show_bug.cgi?id=62780
+
+ * storage/indexeddb/migrate-basics-expected.txt:
+ * storage/indexeddb/migrate-basics.html:
+
2011-06-28 Gavin Barraclough <[email protected]>
Reviewed by Oliver Hunt.
Modified: trunk/LayoutTests/storage/indexeddb/migrate-basics-expected.txt (89947 => 89948)
--- trunk/LayoutTests/storage/indexeddb/migrate-basics-expected.txt 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/LayoutTests/storage/indexeddb/migrate-basics-expected.txt 2011-06-28 19:19:33 UTC (rev 89948)
@@ -27,9 +27,24 @@
trans = db.transaction([], webkitIDBTransaction.READ_WRITE, 0)
leveldbCheckPlainOldStore():
store = trans.objectStore('MigrationPlainOldStore')
-FAIL store = trans.objectStore('MigrationPlainOldStore') threw exception Error: NOT_FOUND_ERR: DOM IDBDatabase Exception 3
request = store.openCursor(keyRange)
-FAIL request = store.openCursor(keyRange) threw exception TypeError: Cannot call method 'openCursor' of undefined
+leveldbCheckPlainOldStoreCursorNext():
+PASS cursor.value.name == 'George' is true
+leveldbCheckPlainOldStoreCursorNext():
+leveldbCheckStoreWithKeyPath():
+store = trans.objectStore('MigrationStoreWithKeyPath')
+leveldbCheckStoreWithKeyPathCursorNext():
+PASS ((window.index = window.store.index('ExampleIndex')) != undefined) is true
+PASS (window.keyIndexCursor.key == 3) is true
+PASS cursor.value.name == 'Thomas' is true
+PASS cursor.value.id == '3' is true
+leveldbCheckStoreWithKeyPathCursorNext():
+leveldbCheckStoreWithAutoIncrement():
+store = trans.objectStore('MigrationStoreWithAutoIncrement')
+leveldbCheckStoreWithAutoIncrementCursorNext():
+PASS cursor.value.name == 'Lincoln' is true
+PASS cursor.value.number == '7012' is true
+leveldbCheckStoreWithAutoIncrementCursorNext():
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/storage/indexeddb/migrate-basics.html (89947 => 89948)
--- trunk/LayoutTests/storage/indexeddb/migrate-basics.html 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/LayoutTests/storage/indexeddb/migrate-basics.html 2011-06-28 19:19:33 UTC (rev 89948)
@@ -45,7 +45,6 @@
window.trans = evalAndLog("trans = db.transaction([], webkitIDBTransaction.READ_WRITE)");
window.index = evalAndLog("index = store.createIndex('ExampleIndex','id', false)");
-
sqliteTestAddRecords1();
}
@@ -151,6 +150,16 @@
return;
}
+ shouldBeTrue("((window.index = window.store.index('ExampleIndex')) != undefined)");
+ openKeyCursor = window.index.openKeyCursor();
+ openKeyCursor._onsuccess_ = leveldbCheckStoreWithKeyPathCursorNext2;
+ openKeyCursor._onerror_ = unexpectedErrorCallback;
+}
+
+function leveldbCheckStoreWithKeyPathCursorNext2()
+{
+ window.keyIndexCursor = event.target.result;
+ shouldBeTrue("(window.keyIndexCursor.key == 3)");
shouldBeTrue("cursor.value.name == 'Thomas'");
shouldBeTrue("cursor.value.id == '3'");
cursor.continue();
Modified: trunk/Source/WebCore/ChangeLog (89947 => 89948)
--- trunk/Source/WebCore/ChangeLog 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/ChangeLog 2011-06-28 19:19:33 UTC (rev 89948)
@@ -1,3 +1,26 @@
+2011-06-28 Greg Simon <[email protected]>
+
+ Reviewed by Dimitri Glazkov.
+
+ Migrate SQLite backing store to LevelDB backing store for Indexeddb.
+ https://bugs.webkit.org/show_bug.cgi?id=62780
+
+ * storage/IDBFactoryBackendImpl.cpp:
+ (WebCore::computeFileIdentifier):
+ (WebCore::computeUniqueIdentifier):
+ (WebCore::IDBFactoryBackendImpl::open):
+ (WebCore::migrateObjectStores):
+ (WebCore::IDBFactoryBackendImpl::migrateFromSQLiteToLevelDB):
+ * storage/IDBLevelDBBackingStore.cpp:
+ (WebCore::IDBLevelDBBackingStore::backingStoreExists):
+ * storage/IDBLevelDBBackingStore.h:
+ * storage/IDBObjectStoreBackendImpl.cpp:
+ (WebCore::IDBObjectStoreBackendImpl::populateIndex):
+ * storage/IDBObjectStoreBackendImpl.h:
+ * storage/IDBSQLiteBackingStore.cpp:
+ (WebCore::IDBSQLiteBackingStore::backingStoreExists):
+ * storage/IDBSQLiteBackingStore.h:
+
2011-06-28 Levi Weintraub <[email protected]>
Reviewed by Darin Adler.
Modified: trunk/Source/WebCore/storage/IDBFactoryBackendImpl.cpp (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBFactoryBackendImpl.cpp 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBFactoryBackendImpl.cpp 2011-06-28 19:19:33 UTC (rev 89948)
@@ -33,6 +33,7 @@
#include "IDBDatabaseBackendImpl.h"
#include "IDBDatabaseException.h"
#include "IDBLevelDBBackingStore.h"
+#include "IDBObjectStoreBackendImpl.h"
#include "IDBSQLiteBackingStore.h"
#include "IDBTransactionCoordinator.h"
#include "SecurityOrigin.h"
@@ -43,6 +44,16 @@
namespace WebCore {
+static String computeFileIdentifier(SecurityOrigin* securityOrigin, IDBFactoryBackendInterface::BackingStoreType type)
+{
+ return securityOrigin->databaseIdentifier() + String::format("@%d", type);
+}
+
+static String computeUniqueIdentifier(const String& name, SecurityOrigin* securityOrigin, IDBFactoryBackendInterface::BackingStoreType type)
+{
+ return computeFileIdentifier(securityOrigin, type) + name;
+}
+
IDBFactoryBackendImpl::IDBFactoryBackendImpl()
: m_transactionCoordinator(IDBTransactionCoordinator::create())
{
@@ -75,8 +86,8 @@
if (backingStoreType == DefaultBackingStore)
backingStoreType = SQLiteBackingStore; // FIXME: DefaultBackingStore is confusing; get rid of it.
- const String fileIdentifier = securityOrigin->databaseIdentifier() + String::format("@%d", static_cast<int>(backingStoreType));
- const String uniqueIdentifier = fileIdentifier + "@" + name;
+ const String fileIdentifier = computeFileIdentifier(securityOrigin.get(), backingStoreType);
+ const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get(), backingStoreType);
IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
if (it != m_databaseBackendMap.end()) {
@@ -94,8 +105,13 @@
#if ENABLE(LEVELDB)
if (backingStoreType == LevelDBBackingStore) {
- const bool hasSQLBackingStore = IDBSQLiteBackingStore::backingStoreExists(securityOrigin.get(), dataDir);
+ bool hasSQLBackingStore = IDBSQLiteBackingStore::backingStoreExists(securityOrigin.get(), name, dataDir);
+ // LayoutTests: SQLite backing store may not exist on disk but may exist in cache.
+ String cachedSqliteBackingStoreIdentifier = computeFileIdentifier(securityOrigin.get(), SQLiteBackingStore);
+ if (!hasSQLBackingStore && (m_backingStoreMap.end() != m_backingStoreMap.find(cachedSqliteBackingStoreIdentifier)))
+ hasSQLBackingStore = true;
+
if (hasSQLBackingStore) {
bool migrationSucceeded = migrateFromSQLiteToLevelDB(name, securityOrigin.get(), dataDir, maximumSize);
(void)migrationSucceeded; // FIXME: When migration is actually implemented, we need error handling here.
@@ -120,9 +136,127 @@
m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
}
+#if ENABLE(LEVELDB)
+
+static bool migrateObjectStores(PassRefPtr<IDBBackingStore> fromBackingStore, int64_t fromDatabaseId, PassRefPtr<IDBBackingStore> toBackingStore, int64_t toDatabaseId)
+{
+ Vector<int64_t> fromObjStoreIds, toObjStoreIds;
+ Vector<String> fromObjStoreNames, toObjStoreNames;
+ Vector<String> fromKeyPaths, toKeyPaths;
+ Vector<bool> fromAutoIncrement, toAutoIncrement;
+
+ // Migrate objectStores. Check to see if the object store already exists in the target.
+ fromBackingStore->getObjectStores(fromDatabaseId, fromObjStoreIds, fromObjStoreNames, fromKeyPaths, fromAutoIncrement);
+
+ toBackingStore->getObjectStores(toDatabaseId, toObjStoreIds, toObjStoreNames, toKeyPaths, toAutoIncrement);
+
+ for (unsigned i = 0; i < fromObjStoreIds.size(); i++) {
+ if (toObjStoreNames.contains(fromObjStoreNames[i]))
+ continue;
+
+ int64_t assignedObjectStoreId = -1;
+
+ RefPtr<IDBBackingStore::Transaction> trans = toBackingStore->createTransaction();
+ trans->begin();
+
+ if (!toBackingStore->createObjectStore(toDatabaseId, fromObjStoreNames[i], fromKeyPaths[i], fromAutoIncrement[i], assignedObjectStoreId))
+ return false;
+
+ RefPtr<IDBBackingStore::Cursor> cursor = fromBackingStore->openObjectStoreCursor(fromDatabaseId, fromObjStoreIds[i], 0, IDBCursor::NEXT);
+ if (cursor) {
+ do {
+ RefPtr<IDBKey> key = cursor->key();
+ RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = toBackingStore->createInvalidRecordIdentifier();
+
+ if (!toBackingStore->putObjectStoreRecord(toDatabaseId, assignedObjectStoreId, *(key.get()), cursor->value(), recordIdentifier.get()))
+ return false;
+
+ } while (cursor->continueFunction());
+ }
+
+ // Populate any/all indexes for this objectstore.
+ Vector<int64_t> idxIds;
+ Vector<String> idxNames;
+ Vector<String> idxKeyPaths;
+ Vector<bool> idxUnique;
+ fromBackingStore->getIndexes(fromDatabaseId, fromObjStoreIds[i], idxIds, idxNames, idxKeyPaths, idxUnique);
+ for (unsigned j = 0; j < idxIds.size(); j++) {
+ int64_t indexId = -1;
+
+ if (!toBackingStore->createIndex(toDatabaseId, assignedObjectStoreId, idxNames[j], idxKeyPaths[j], idxUnique[j], indexId))
+ return false;
+
+ if (!IDBObjectStoreBackendImpl::populateIndex(*toBackingStore, toDatabaseId, assignedObjectStoreId, indexId, fromKeyPaths[i]))
+ return false;
+ }
+
+ trans->commit();
+ }
+
+ return true;
+}
+#endif // #if ENABLE(LEVELDB)
+
bool IDBFactoryBackendImpl::migrateFromSQLiteToLevelDB(const String& name, SecurityOrigin* securityOrigin, const String& dataDir, int64_t maximumSize)
{
- return false; // FIXME: To be implemented.
+#if ENABLE(LEVELDB)
+ String fromUniqueIdentifier = computeUniqueIdentifier(name, securityOrigin, SQLiteBackingStore);
+ String fromFileIdentifier = computeFileIdentifier(securityOrigin, SQLiteBackingStore);
+ String toUniqueIdentifier = computeUniqueIdentifier(name, securityOrigin, LevelDBBackingStore);
+ String toFileIdentifier = computeFileIdentifier(securityOrigin, LevelDBBackingStore);
+ RefPtr<IDBTransactionCoordinator> transactionCoordinator = IDBTransactionCoordinator::create();
+ RefPtr<IDBBackingStore> fromBackingStore;
+ RefPtr<IDBDatabaseBackendImpl> fromDatabaseBackend;
+ RefPtr<IDBBackingStore> toBackingStore;
+
+
+ // Open "From" backing store and backend. When running LayoutTests, the
+ // "from" database may be cached in this class instance, so look for it there first.
+ IDBBackingStoreMap::iterator it = m_backingStoreMap.find(fromFileIdentifier);
+ if (it != m_backingStoreMap.end())
+ fromBackingStore = it->second;
+ else
+ fromBackingStore = IDBSQLiteBackingStore::open(securityOrigin, dataDir, maximumSize, fromFileIdentifier, this);
+
+ if (!fromBackingStore)
+ return false;
+
+ IDBDatabaseBackendMap::iterator it2 = m_databaseBackendMap.find(fromUniqueIdentifier);
+ if (it2 != m_databaseBackendMap.end())
+ fromDatabaseBackend = it2->second;
+ else {
+ fromDatabaseBackend = IDBDatabaseBackendImpl::create(name, fromBackingStore.get(), transactionCoordinator.get(), this, fromUniqueIdentifier);
+ m_databaseBackendMap.set(fromUniqueIdentifier, fromDatabaseBackend.get());
+ }
+
+ if (!fromDatabaseBackend)
+ return false;
+
+ // Open "To" database. First find out if it already exists -- this will determine if
+ // it is safe to call IDBLevelDBBackingStore::extractIDBDatabaseMetaData.
+ it = m_backingStoreMap.find(toFileIdentifier);
+ if (it != m_backingStoreMap.end())
+ toBackingStore = it->second;
+ else
+ toBackingStore = IDBLevelDBBackingStore::open(securityOrigin, dataDir, maximumSize, toFileIdentifier, this);
+
+ if (!toBackingStore)
+ return false;
+
+
+ String toDatabaseName = fromDatabaseBackend->name();
+ String toDatabaseVersion = fromDatabaseBackend->version();
+ int64_t toDatabaseId = -1;
+
+ if (!toBackingStore->extractIDBDatabaseMetaData(toDatabaseName, toDatabaseVersion, toDatabaseId)) {
+ if (!toBackingStore->setIDBDatabaseMetaData(toDatabaseName, toDatabaseVersion, toDatabaseId, true))
+ return false;
+ }
+
+ return migrateObjectStores(fromBackingStore, fromDatabaseBackend->id(), toBackingStore, toDatabaseId);
+
+#endif // ENABLE(LEVELDB)
+ return false;
}
} // namespace WebCore
Modified: trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBLevelDBBackingStore.cpp 2011-06-28 19:19:33 UTC (rev 89948)
@@ -1304,7 +1304,7 @@
m_backingStore->m_currentTransaction.clear();
}
-bool IDBLevelDBBackingStore::backingStoreExists(SecurityOrigin* securityOrigin, const String& pathBaseArg)
+bool IDBLevelDBBackingStore::backingStoreExists(SecurityOrigin* securityOrigin, const String&, const String& pathBaseArg)
{
String pathBase = pathBaseArg;
@@ -1314,11 +1314,8 @@
// FIXME: We should eventually use the same LevelDB database for all origins.
String path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb.leveldb");
- // FIXME: It would be more thorough to open the database here but also more expensive.
- if (fileExists(path+"/CURRENT"))
- return true;
-
- return false;
+ // FIXME: this is checking for presence of the domain, not the database itself
+ return fileExists(path+"/CURRENT");
}
// FIXME: deleteDatabase should be part of IDBBackingStore.
Modified: trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBLevelDBBackingStore.h 2011-06-28 19:19:33 UTC (rev 89948)
@@ -76,7 +76,7 @@
virtual PassRefPtr<Transaction> createTransaction();
virtual IDBFactoryBackendInterface::BackingStoreType backingStoreType() const { return IDBFactoryBackendInterface::LevelDBBackingStore; }
- static bool backingStoreExists(SecurityOrigin*, const String& pathBase);
+ static bool backingStoreExists(SecurityOrigin*, const String& name, const String& pathBase);
private:
IDBLevelDBBackingStore(const String& identifier, IDBFactoryBackendImpl*, PassOwnPtr<LevelDBDatabase>);
Modified: trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp 2011-06-28 19:19:33 UTC (rev 89948)
@@ -375,7 +375,7 @@
};
}
-static bool populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath)
+bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath)
{
PopulateIndexCallback callback(backingStore, indexKeyPath, databaseId, objectStoreId, indexId);
if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
Modified: trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h 2011-06-28 19:19:33 UTC (rev 89948)
@@ -77,6 +77,8 @@
virtual void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ static bool populateIndex(IDBBackingStore&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath);
+
private:
IDBObjectStoreBackendImpl(IDBBackingStore*, int64_t databaseId, int64_t id, const String& name, const String& keyPath, bool autoIncrement);
IDBObjectStoreBackendImpl(IDBBackingStore*, int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement);
Modified: trunk/Source/WebCore/storage/IDBSQLiteBackingStore.cpp (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBSQLiteBackingStore.cpp 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBSQLiteBackingStore.cpp 2011-06-28 19:19:33 UTC (rev 89948)
@@ -991,18 +991,19 @@
return cursor.release();
}
-bool IDBSQLiteBackingStore::backingStoreExists(SecurityOrigin* securityOrigin, const String& pathBase)
+bool IDBSQLiteBackingStore::backingStoreExists(SecurityOrigin* securityOrigin, const String& name, const String& pathBase)
{
String path = pathByAppendingComponent(pathBase, securityOrigin->databaseIdentifier() + ".indexeddb");
- if (!fileExists(path))
- return false;
-
SQLiteDatabase db;
if (!db.open(path))
return false;
- db.close();
- return true;
+ SQLiteStatement databaseQuery(db, "SELECT id, version FROM Databases WHERE name = ?");
+ if (databaseQuery.prepare() != SQLResultOk)
+ return false;
+
+ databaseQuery.bindText(1, name);
+ return (databaseQuery.step() == SQLResultRow);
}
namespace {
Modified: trunk/Source/WebCore/storage/IDBSQLiteBackingStore.h (89947 => 89948)
--- trunk/Source/WebCore/storage/IDBSQLiteBackingStore.h 2011-06-28 19:01:29 UTC (rev 89947)
+++ trunk/Source/WebCore/storage/IDBSQLiteBackingStore.h 2011-06-28 19:19:33 UTC (rev 89948)
@@ -71,7 +71,7 @@
virtual PassRefPtr<Transaction> createTransaction();
virtual IDBFactoryBackendInterface::BackingStoreType backingStoreType() const { return IDBFactoryBackendInterface::SQLiteBackingStore; }
- static bool backingStoreExists(SecurityOrigin*, const String& pathBase);
+ static bool backingStoreExists(SecurityOrigin*, const String& name, const String& pathBase);
private:
IDBSQLiteBackingStore(const String& identifier, IDBFactoryBackendImpl*);