Diff
Modified: trunk/Source/WebCore/ChangeLog (158640 => 158641)
--- trunk/Source/WebCore/ChangeLog 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/ChangeLog 2013-11-05 05:08:11 UTC (rev 158641)
@@ -1,3 +1,33 @@
+2013-11-04 Brady Eidson <beid...@apple.com>
+
+ IDB: Make opening/establishing a database asynchronous.
+ https://bugs.webkit.org/show_bug.cgi?id=123775
+
+ Reviewed by Andreas Kling.
+
+ No new tests (No behavior change for a tested port).
+
+ * Modules/indexeddb/IDBBackingStoreInterface.h: Add getOrEstablishIDBDatabaseMetadata with a callback,
+ removing getIDBDatabaseMetaData, getObjectStores, and createIDBDatabaseMetaData in the process.
+
+ * Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp:
+ (WebCore::IDBBackingStoreLevelDB::getOrEstablishIDBDatabaseMetadata): Adapted from getIDBDatabaseMetaData,
+ implement the asynchronous interface in terms of other LevelDB methods, always calling back synchronously.
+ (WebCore::IDBBackingStoreLevelDB::createIDBDatabaseMetaData):
+ * Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h:
+
+ * Modules/indexeddb/IDBDatabaseBackendImpl.cpp:
+ (WebCore::IDBDatabaseBackendImpl::create):
+ (WebCore::IDBDatabaseBackendImpl::openInternalAsync): Broken off from openInternal.
+ (WebCore::IDBDatabaseBackendImpl::didOpenInternalAsync): Broken off from openInternal.
+ (WebCore::IDBDatabaseBackendImpl::processPendingCalls):
+ (WebCore::IDBDatabaseBackendImpl::processPendingOpenCalls): Broken off to allow didOpenInternalAsync
+ to perform open callbacks in the failure case.
+ (WebCore::IDBDatabaseBackendImpl::openConnection): Always queue open connection calls, then immediately processPendingCalls.
+ (WebCore::IDBDatabaseBackendImpl::openConnectionInternal): Actually perform open connection calls.
+ * Modules/indexeddb/IDBDatabaseBackendImpl.h:
+
+
2013-11-04 Andreas Kling <akl...@apple.com>
CTTE: RenderFrameBase's widget is always a FrameView.
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBBackingStoreInterface.h (158640 => 158641)
--- trunk/Source/WebCore/Modules/indexeddb/IDBBackingStoreInterface.h 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBBackingStoreInterface.h 2013-11-05 05:08:11 UTC (rev 158641)
@@ -30,6 +30,7 @@
#include "IDBMetadata.h"
#include "IndexedDB.h"
+#include <functional>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
@@ -81,9 +82,9 @@
virtual std::unique_ptr<Transaction> createBackingStoreTransaction() = 0;
- virtual bool getIDBDatabaseMetaData(const String& name, IDBDatabaseMetadata*, bool& found) = 0;
- virtual bool getObjectStores(int64_t databaseId, IDBDatabaseMetadata::ObjectStoreMap* objectStores) = 0;
- virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId) = 0;
+ typedef std::function<void (const IDBDatabaseMetadata&, bool success)> GetIDBDatabaseMetadataFunction;
+ virtual void getOrEstablishIDBDatabaseMetadata(const String& name, GetIDBDatabaseMetadataFunction) = 0;
+
virtual bool keyExistsInObjectStore(IDBBackingStoreInterface::Transaction&, int64_t databaseId, int64_t objectStoreId, const IDBKey&, RefPtr<IDBRecordIdentifier>& foundIDBRecordIdentifier) = 0;
virtual bool putIndexDataForRecord(IDBBackingStoreInterface::Transaction&, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey&, const IDBRecordIdentifier*) = 0;
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp (158640 => 158641)
--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp 2013-11-05 05:08:11 UTC (rev 158641)
@@ -47,8 +47,8 @@
PassRefPtr<IDBDatabaseBackendImpl> IDBDatabaseBackendImpl::create(const String& name, IDBBackingStoreInterface* backingStore, IDBFactoryBackendInterface* factory, const String& uniqueIdentifier)
{
RefPtr<IDBDatabaseBackendImpl> backend = adoptRef(new IDBDatabaseBackendImpl(name, backingStore, factory, uniqueIdentifier));
- if (!backend->openInternal())
- return 0;
+ backend->openInternalAsync();
+
return backend.release();
}
@@ -103,17 +103,24 @@
m_metadata.objectStores.set(objectStoreId, objectStore);
}
-bool IDBDatabaseBackendImpl::openInternal()
+void IDBDatabaseBackendImpl::openInternalAsync()
{
- bool success = false;
- bool ok = m_backingStore->getIDBDatabaseMetaData(m_metadata.name, &m_metadata, success);
- ASSERT_WITH_MESSAGE(success == (m_metadata.id != InvalidId), "success = %s, m_id = %lld", success ? "true" : "false", static_cast<long long>(m_metadata.id));
- if (!ok)
- return false;
- if (success)
- return m_backingStore->getObjectStores(m_metadata.id, &m_metadata.objectStores);
+ RefPtr<IDBDatabaseBackendImpl> self = this;
+ m_backingStore->getOrEstablishIDBDatabaseMetadata(m_metadata.name, [self](const IDBDatabaseMetadata& metadata, bool success) {
+ self->didOpenInternalAsync(metadata, success);
+ });
+}
- return m_backingStore->createIDBDatabaseMetaData(m_metadata.name, String::number(m_metadata.version), m_metadata.version, m_metadata.id);
+void IDBDatabaseBackendImpl::didOpenInternalAsync(const IDBDatabaseMetadata& metadata, bool success)
+{
+ if (!success) {
+ processPendingOpenCalls(false);
+ return;
+ }
+
+ m_metadata = metadata;
+
+ processPendingCalls();
}
IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
@@ -413,17 +420,40 @@
// deleteDatabaseFinal should never re-queue calls.
ASSERT(m_pendingDeleteCalls.isEmpty());
- // This check is also not really needed, openConnection would just requeue its calls.
if (m_runningVersionChangeTransaction)
return;
- // Open calls can be requeued if an open call started a version change transaction.
+ processPendingOpenCalls(true);
+}
+
+void IDBDatabaseBackendImpl::processPendingOpenCalls(bool success)
+{
+ // Open calls can be requeued if an open call started a version change transaction or deletes the database.
Deque<OwnPtr<IDBPendingOpenCall>> pendingOpenCalls;
m_pendingOpenCalls.swap(pendingOpenCalls);
while (!pendingOpenCalls.isEmpty()) {
OwnPtr<IDBPendingOpenCall> pendingOpenCall = pendingOpenCalls.takeFirst();
- openConnection(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
+ if (success) {
+ if (m_metadata.id == InvalidId) {
+ // This database was deleted then quickly re-opened.
+ // openInternalAsync() will recreate it in the backing store and then resume processing pending callbacks.
+ pendingOpenCalls.prepend(pendingOpenCall.release());
+ pendingOpenCalls.swap(m_pendingOpenCalls);
+
+ openInternalAsync();
+ return;
+ }
+ openConnectionInternal(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
+ } else {
+ String message;
+ RefPtr<IDBDatabaseError> error;
+ if (pendingOpenCall->version() == IDBDatabaseMetadata::NoIntVersion)
+ message = "Internal error opening database with no version specified.";
+ else
+ message = String::format("Internal error opening database with version %llu", static_cast<unsigned long long>(pendingOpenCall->version()));
+ pendingOpenCall->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
+ }
}
}
@@ -440,31 +470,24 @@
void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, uint64_t version)
{
- ASSERT(m_backingStore.get());
RefPtr<IDBCallbacks> callbacks = prpCallbacks;
RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
- if (!m_pendingDeleteCalls.isEmpty() || m_runningVersionChangeTransaction) {
- m_pendingOpenCalls.append(IDBPendingOpenCall::create(*callbacks, *databaseCallbacks, transactionId, version));
- return;
- }
+ m_pendingOpenCalls.append(IDBPendingOpenCall::create(*callbacks, *databaseCallbacks, transactionId, version));
- if (m_metadata.id == InvalidId) {
- // The database was deleted then immediately re-opened; openInternal() recreates it in the backing store.
- if (openInternal())
- ASSERT(m_metadata.version == IDBDatabaseMetadata::NoIntVersion);
- else {
- String message;
- RefPtr<IDBDatabaseError> error;
- if (version == IDBDatabaseMetadata::NoIntVersion)
- message = "Internal error opening database with no version specified.";
- else
- message = String::format("Internal error opening database with version %llu", static_cast<unsigned long long>(version));
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
- return;
- }
- }
+ processPendingCalls();
+}
+
+void IDBDatabaseBackendImpl::openConnectionInternal(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, uint64_t version)
+{
+ ASSERT(m_backingStore.get());
+ ASSERT(m_pendingDeleteCalls.isEmpty());
+ ASSERT(!m_runningVersionChangeTransaction);
+
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
+
// We infer that the database didn't exist from its lack of either type of version.
bool isNewDatabase = m_metadata.version == IDBDatabaseMetadata::NoIntVersion;
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h (158640 => 158641)
--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h 2013-11-05 05:08:11 UTC (rev 158641)
@@ -105,10 +105,15 @@
private:
IDBDatabaseBackendImpl(const String& name, IDBBackingStoreInterface*, IDBFactoryBackendInterface*, const String& uniqueIdentifier);
- bool openInternal();
+ void openConnectionInternal(PassRefPtr<IDBCallbacks>, PassRefPtr<IDBDatabaseCallbacks>, int64_t transactionId, uint64_t version);
+
+ void openInternalAsync();
+ void didOpenInternalAsync(const IDBDatabaseMetadata&, bool success);
+
void runIntVersionChangeTransaction(PassRefPtr<IDBCallbacks>, PassRefPtr<IDBDatabaseCallbacks>, int64_t transactionId, int64_t requestedVersion);
size_t connectionCount();
void processPendingCalls();
+ void processPendingOpenCalls(bool success);
bool isDeleteDatabaseBlocked();
void deleteDatabaseFinal(PassRefPtr<IDBCallbacks>);
Modified: trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp (158640 => 158641)
--- trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.cpp 2013-11-05 05:08:11 UTC (rev 158641)
@@ -543,6 +543,64 @@
return true;
}
+void IDBBackingStoreLevelDB::getOrEstablishIDBDatabaseMetadata(const String& name, GetIDBDatabaseMetadataFunction 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);
@@ -570,21 +628,17 @@
return true;
}
-// FIXME: The version semantics have changed. String versions no longer exist, and the integer version is now a uint64_t
-bool IDBBackingStoreLevelDB::createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId)
+// FIXME: LevelDB needs to support uint64_t as the version type.
+bool IDBBackingStoreLevelDB::createIDBDatabaseMetaData(IDBDatabaseMetadata& metadata)
{
- bool ok = getNewDatabaseId(m_db.get(), rowId);
+ bool ok = getNewDatabaseId(m_db.get(), metadata.id);
if (!ok)
return false;
- ASSERT(rowId >= 0);
+ ASSERT(metadata.id >= 0);
- if (intVersion == IDBDatabaseMetadata::NoIntVersion)
- intVersion = IDBDatabaseMetadata::DefaultIntVersion;
-
RefPtr<LevelDBTransaction> transaction = LevelDBTransaction::create(m_db.get());
- putInt(transaction.get(), DatabaseNameKey::encode(m_identifier, name), rowId);
- putString(transaction.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::UserVersion), version);
- putVarInt(transaction.get(), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::UserIntVersion), intVersion);
+ 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;
@@ -600,12 +654,6 @@
return true;
}
-bool IDBBackingStoreLevelDB::updateIDBDatabaseMetaData(IDBBackingStoreInterface::Transaction& transaction, int64_t rowId, const String& version)
-{
- putString(Transaction::levelDBTransactionFrom(transaction), DatabaseMetaDataKey::encode(rowId, DatabaseMetaDataKey::UserVersion), version);
- return true;
-}
-
static void deleteRange(LevelDBTransaction* transaction, const Vector<char>& begin, const Vector<char>& end)
{
OwnPtr<LevelDBIterator> it = transaction->createIterator();
Modified: trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h (158640 => 158641)
--- trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h 2013-11-05 05:04:19 UTC (rev 158640)
+++ trunk/Source/WebCore/Modules/indexeddb/leveldb/IDBBackingStoreLevelDB.h 2013-11-05 05:08:11 UTC (rev 158641)
@@ -70,13 +70,12 @@
virtual std::unique_ptr<IDBBackingStoreInterface::Transaction> createBackingStoreTransaction();
virtual Vector<String> getDatabaseNames();
- virtual bool getIDBDatabaseMetaData(const String& name, IDBDatabaseMetadata*, bool& success) OVERRIDE WARN_UNUSED_RETURN;
- virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId) OVERRIDE;
- virtual bool updateIDBDatabaseMetaData(IDBBackingStoreInterface::Transaction&, int64_t rowId, const String& version);
+
+ virtual void getOrEstablishIDBDatabaseMetadata(const String& name, GetIDBDatabaseMetadataFunction) OVERRIDE;
+
virtual bool updateIDBDatabaseVersion(IDBBackingStoreInterface::Transaction&, int64_t rowId, uint64_t version) OVERRIDE;
virtual bool deleteDatabase(const String& name) OVERRIDE;
- virtual bool getObjectStores(int64_t databaseId, IDBDatabaseMetadata::ObjectStoreMap*) OVERRIDE WARN_UNUSED_RETURN;
virtual bool createObjectStore(IDBBackingStoreInterface::Transaction&, int64_t databaseId, int64_t objectStoreId, const String& name, const IDBKeyPath&, bool autoIncrement) OVERRIDE;
virtual bool deleteObjectStore(IDBBackingStoreInterface::Transaction&, int64_t databaseId, int64_t objectStoreId) OVERRIDE WARN_UNUSED_RETURN;
@@ -180,6 +179,11 @@
private:
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(IDBBackingStoreInterface::Transaction&, 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;