Title: [124675] trunk/Source
Revision
124675
Author
[email protected]
Date
2012-08-03 17:28:25 -0700 (Fri, 03 Aug 2012)

Log Message

IndexedDB: Core upgradeneeded logic
https://bugs.webkit.org/show_bug.cgi?id=92558

Reviewed by Ojan Vafai.

Source/WebCore:

This is the backend webkit logic needed for integer versions. The rest
is in https://bugs.webkit.org/show_bug.cgi?id=89505.

I tried to make use of the existing processPendingCalls and added two
more queues, pendingOpenWithVersionCalls and
pendingSecondHalfOpenWithVersionCalls. The "second half" refers to
how there are two events that need to be fired in response to an
open-with-version call. The "second half" queue holds the open
requests that should immediately follow the caller's upgradeneeded
handler.

No new tests, there are so many they are in their own patch:
https://bugs.webkit.org/show_bug.cgi?id=92560

Though this patch doesn't change any expected behavior anyway, lack of
regressions is what we're hoping for here.

* Modules/indexeddb/IDBBackingStore.h:
(IDBBackingStore):
* Modules/indexeddb/IDBCallbacks.h:
(WebCore::IDBCallbacks::onBlocked):
(WebCore::IDBCallbacks::onUpgradeNeeded):
* Modules/indexeddb/IDBDatabaseBackendImpl.cpp:
(IDBDatabaseBackendImpl::PendingOpenCall):
(IDBDatabaseBackendImpl::PendingOpenWithVersionCall):
(WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::create):
(WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::callbacks):
(WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::version):
(WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::PendingOpenWithVersionCall):
(WebCore):
(WebCore::IDBDatabaseBackendImpl::IDBDatabaseBackendImpl):
(WebCore::IDBDatabaseBackendImpl::openInternal):
(WebCore::IDBDatabaseBackendImpl::metadata):
(WebCore::IDBDatabaseBackendImpl::setVersion):
(WebCore::IDBDatabaseBackendImpl::setIntVersionInternal):
(WebCore::IDBDatabaseBackendImpl::transactionFinished):
(WebCore::IDBDatabaseBackendImpl::transactionFinishedAndEventsFired):
When an upgradeneeded event is fired in response to an
open-with-version call, the version change transaction must receive its
complete event before processPendingCalls fires a success event at
IDBOpenDBRequest. In the future this should probably be changed
instead to transactionFinishedAndAbortFired and
transactionFinishedAndCompleteFired so that we'll know to fire a
success or error event at IDBOpenDBRequest. Currently, instead of
firing error when there's an abort, we don't fire anything.

(WebCore::IDBDatabaseBackendImpl::processPendingCalls):
Now that this is called after a connection is opened, we unfortunately
lose the invariant that there is only one existing connection when this
is called, but nothing inside this function actually relied on that.
Additionally, the secondHalfOpen calls only ever need to be serviced
in one place: right after a version change transaction completes, so
it could be moved out of here.

(WebCore::IDBDatabaseBackendImpl::registerFrontendCallbacks):
Now that setVersion and deleteDatabase calls are queued up behind
secondHalfOpen calls, we have to service those queues when
secondHalfOpen calls complete, which is here.  So call
processPendingCalls().

(WebCore::IDBDatabaseBackendImpl::runIntVersionChangeTransaction):
(WebCore::IDBDatabaseBackendImpl::openConnectionWithVersion):
(WebCore::IDBDatabaseBackendImpl::deleteDatabase):
(WebCore::IDBDatabaseBackendImpl::close):
* Modules/indexeddb/IDBDatabaseBackendImpl.h:
(IDBDatabaseBackendImpl):
* Modules/indexeddb/IDBDatabaseCallbacks.h:
(WebCore::IDBDatabaseCallbacks::onVersionChange):
* Modules/indexeddb/IDBFactoryBackendImpl.cpp:
(WebCore::IDBFactoryBackendImpl::open):
This is refactored some so that the call to openConection{WithVersion}
happens once, at the end.

* Modules/indexeddb/IDBLevelDBBackingStore.cpp:
(WebCore::IDBLevelDBBackingStore::getIDBDatabaseMetaData):
(WebCore::IDBLevelDBBackingStore::createIDBDatabaseMetaData):
(WebCore::IDBLevelDBBackingStore::updateIDBDatabaseIntVersion):
(WebCore):
(WebCore::IDBLevelDBBackingStore::deleteDatabase):
* Modules/indexeddb/IDBLevelDBBackingStore.h:
(IDBLevelDBBackingStore):
* Modules/indexeddb/IDBTransactionBackendImpl.cpp:
(WebCore::IDBTransactionBackendImpl::commit):
See above comments about transactionFinishedAndEventsFired. I tried
moving the call to transactionFinished after the events were fired but
that failed some asserts. But changing those asserts is still an
alternative to splitting up transactionFinished as is done here.

Source/WebKit/chromium:

Update overridden methods to match new signatures.

* tests/IDBAbortOnCorruptTest.cpp:
(WebCore::FailingBackingStore::createIDBDatabaseMetaData):
* tests/IDBFakeBackingStore.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (124674 => 124675)


--- trunk/Source/WebCore/ChangeLog	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/ChangeLog	2012-08-04 00:28:25 UTC (rev 124675)
@@ -1,3 +1,98 @@
+2012-08-03  David Grogan  <[email protected]>
+
+        IndexedDB: Core upgradeneeded logic
+        https://bugs.webkit.org/show_bug.cgi?id=92558
+
+        Reviewed by Ojan Vafai.
+
+        This is the backend webkit logic needed for integer versions. The rest
+        is in https://bugs.webkit.org/show_bug.cgi?id=89505.
+
+        I tried to make use of the existing processPendingCalls and added two
+        more queues, pendingOpenWithVersionCalls and
+        pendingSecondHalfOpenWithVersionCalls. The "second half" refers to
+        how there are two events that need to be fired in response to an
+        open-with-version call. The "second half" queue holds the open
+        requests that should immediately follow the caller's upgradeneeded
+        handler.
+
+        No new tests, there are so many they are in their own patch:
+        https://bugs.webkit.org/show_bug.cgi?id=92560
+
+        Though this patch doesn't change any expected behavior anyway, lack of
+        regressions is what we're hoping for here.
+
+        * Modules/indexeddb/IDBBackingStore.h:
+        (IDBBackingStore):
+        * Modules/indexeddb/IDBCallbacks.h:
+        (WebCore::IDBCallbacks::onBlocked):
+        (WebCore::IDBCallbacks::onUpgradeNeeded):
+        * Modules/indexeddb/IDBDatabaseBackendImpl.cpp:
+        (IDBDatabaseBackendImpl::PendingOpenCall):
+        (IDBDatabaseBackendImpl::PendingOpenWithVersionCall):
+        (WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::create):
+        (WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::callbacks):
+        (WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::version):
+        (WebCore::IDBDatabaseBackendImpl::PendingOpenWithVersionCall::PendingOpenWithVersionCall):
+        (WebCore):
+        (WebCore::IDBDatabaseBackendImpl::IDBDatabaseBackendImpl):
+        (WebCore::IDBDatabaseBackendImpl::openInternal):
+        (WebCore::IDBDatabaseBackendImpl::metadata):
+        (WebCore::IDBDatabaseBackendImpl::setVersion):
+        (WebCore::IDBDatabaseBackendImpl::setIntVersionInternal):
+        (WebCore::IDBDatabaseBackendImpl::transactionFinished):
+        (WebCore::IDBDatabaseBackendImpl::transactionFinishedAndEventsFired):
+        When an upgradeneeded event is fired in response to an
+        open-with-version call, the version change transaction must receive its
+        complete event before processPendingCalls fires a success event at
+        IDBOpenDBRequest. In the future this should probably be changed
+        instead to transactionFinishedAndAbortFired and
+        transactionFinishedAndCompleteFired so that we'll know to fire a
+        success or error event at IDBOpenDBRequest. Currently, instead of
+        firing error when there's an abort, we don't fire anything.
+
+        (WebCore::IDBDatabaseBackendImpl::processPendingCalls):
+        Now that this is called after a connection is opened, we unfortunately
+        lose the invariant that there is only one existing connection when this
+        is called, but nothing inside this function actually relied on that.
+        Additionally, the secondHalfOpen calls only ever need to be serviced
+        in one place: right after a version change transaction completes, so
+        it could be moved out of here.
+
+        (WebCore::IDBDatabaseBackendImpl::registerFrontendCallbacks):
+        Now that setVersion and deleteDatabase calls are queued up behind
+        secondHalfOpen calls, we have to service those queues when
+        secondHalfOpen calls complete, which is here.  So call
+        processPendingCalls().
+
+        (WebCore::IDBDatabaseBackendImpl::runIntVersionChangeTransaction):
+        (WebCore::IDBDatabaseBackendImpl::openConnectionWithVersion):
+        (WebCore::IDBDatabaseBackendImpl::deleteDatabase):
+        (WebCore::IDBDatabaseBackendImpl::close):
+        * Modules/indexeddb/IDBDatabaseBackendImpl.h:
+        (IDBDatabaseBackendImpl):
+        * Modules/indexeddb/IDBDatabaseCallbacks.h:
+        (WebCore::IDBDatabaseCallbacks::onVersionChange):
+        * Modules/indexeddb/IDBFactoryBackendImpl.cpp:
+        (WebCore::IDBFactoryBackendImpl::open):
+        This is refactored some so that the call to openConection{WithVersion}
+        happens once, at the end.
+
+        * Modules/indexeddb/IDBLevelDBBackingStore.cpp:
+        (WebCore::IDBLevelDBBackingStore::getIDBDatabaseMetaData):
+        (WebCore::IDBLevelDBBackingStore::createIDBDatabaseMetaData):
+        (WebCore::IDBLevelDBBackingStore::updateIDBDatabaseIntVersion):
+        (WebCore):
+        (WebCore::IDBLevelDBBackingStore::deleteDatabase):
+        * Modules/indexeddb/IDBLevelDBBackingStore.h:
+        (IDBLevelDBBackingStore):
+        * Modules/indexeddb/IDBTransactionBackendImpl.cpp:
+        (WebCore::IDBTransactionBackendImpl::commit):
+        See above comments about transactionFinishedAndEventsFired. I tried
+        moving the call to transactionFinished after the events were fired but
+        that failed some asserts. But changing those asserts is still an
+        alternative to splitting up transactionFinished as is done here.
+
 2012-08-03  Rick Byers  <[email protected]>
 
         Double tap gesture should send dblclick event

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -47,8 +47,9 @@
     virtual ~IDBBackingStore() {};
 
     virtual void getDatabaseNames(Vector<String>& foundNames) = 0;
-    virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) = 0;
-    virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId) = 0;
+    virtual bool getIDBDatabaseMetaData(const String& name, String& foundStringVersion, int64_t& foundIntVersion, int64_t& foundId) = 0;
+    virtual bool createIDBDatabaseMetaData(const String& name, const String& stringVersion, int64_t intVersion, int64_t& rowId) = 0;
+    virtual bool updateIDBDatabaseIntVersion(int64_t rowId, int64_t intVersion) = 0;
     virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version) = 0;
     virtual bool deleteDatabase(const String& name) = 0;
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBCallbacks.h (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBCallbacks.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBCallbacks.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -30,9 +30,11 @@
 #define IDBCallbacks_h
 
 #include "DOMStringList.h"
+#include "IDBDatabaseBackendInterface.h"
 #include "IDBDatabaseError.h"
 #include "IDBKey.h"
 #include "IDBKeyPath.h"
+#include "IDBTransactionBackendInterface.h"
 #include "SerializedScriptValue.h"
 #include <wtf/Threading.h>
 
@@ -40,9 +42,7 @@
 
 namespace WebCore {
 class IDBCursorBackendInterface;
-class IDBDatabaseBackendInterface;
 class IDBObjectStoreBackendInterface;
-class IDBTransactionBackendInterface;
 
 // FIXME: All child classes need to be made threadsafe.
 class IDBCallbacks : public ThreadSafeRefCounted<IDBCallbacks> {
@@ -59,7 +59,9 @@
     virtual void onSuccess(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, const IDBKeyPath&) = 0;
     virtual void onSuccessWithContinuation() = 0;
     virtual void onSuccessWithPrefetch(const Vector<RefPtr<IDBKey> >& keys, const Vector<RefPtr<IDBKey> >& primaryKeys, const Vector<RefPtr<SerializedScriptValue> >& values) = 0;
-    virtual void onBlocked() = 0;
+    virtual void onBlocked() { ASSERT_NOT_REACHED(); }
+    virtual void onBlocked(int64_t existingVersion) { ASSERT_NOT_REACHED(); }
+    virtual void onUpgradeNeeded(int64_t oldVersion, PassRefPtr<IDBTransactionBackendInterface>, PassRefPtr<IDBDatabaseBackendInterface>) { ASSERT_NOT_REACHED(); }
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.cpp	2012-08-04 00:28:25 UTC (rev 124675)
@@ -52,9 +52,29 @@
         : m_callbacks(callbacks)
     {
     }
+
     RefPtr<IDBCallbacks> m_callbacks;
 };
 
+class IDBDatabaseBackendImpl::PendingOpenWithVersionCall : public RefCounted<PendingOpenWithVersionCall> {
+public:
+    static PassRefPtr<PendingOpenWithVersionCall> create(PassRefPtr<IDBCallbacks> callbacks, int64_t version)
+    {
+        return adoptRef(new PendingOpenWithVersionCall(callbacks, version));
+    }
+    PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
+    int64_t version() { return m_version; }
+
+private:
+    PendingOpenWithVersionCall(PassRefPtr<IDBCallbacks> callbacks, int64_t version)
+        : m_callbacks(callbacks)
+        , m_version(version)
+    {
+    }
+    RefPtr<IDBCallbacks> m_callbacks;
+    int64_t m_version;
+};
+
 class IDBDatabaseBackendImpl::PendingDeleteCall : public RefCounted<PendingDeleteCall> {
 public:
     static PassRefPtr<PendingDeleteCall> create(PassRefPtr<IDBCallbacks> callbacks)
@@ -106,6 +126,7 @@
     , m_id(InvalidId)
     , m_name(name)
     , m_version("")
+    , m_intVersion(IDBDatabaseMetadata::NoIntVersion)
     , m_identifier(uniqueIdentifier)
     , m_factory(factory)
     , m_transactionCoordinator(coordinator)
@@ -116,13 +137,13 @@
 
 bool IDBDatabaseBackendImpl::openInternal()
 {
-    bool success = m_backingStore->getIDBDatabaseMetaData(m_name, m_version, m_id);
-    ASSERT(success == (m_id != InvalidId));
+    bool success = m_backingStore->getIDBDatabaseMetaData(m_name, m_version, m_intVersion, m_id);
+    ASSERT_WITH_MESSAGE(success == (m_id != InvalidId), "success = %s, m_id = %lld", success ? "true" : "false", static_cast<long long>(m_id));
     if (success) {
         loadObjectStores();
         return true;
     }
-    return m_backingStore->createIDBDatabaseMetaData(m_name, m_version, m_id);
+    return m_backingStore->createIDBDatabaseMetaData(m_name, m_version, m_intVersion, m_id);
 }
 
 IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
@@ -136,7 +157,7 @@
 
 IDBDatabaseMetadata IDBDatabaseBackendImpl::metadata() const
 {
-    IDBDatabaseMetadata metadata(m_name, m_version, IDBDatabaseMetadata::NoIntVersion);
+    IDBDatabaseMetadata metadata(m_name, m_version, m_intVersion);
     for (ObjectStoreMap::const_iterator it = m_objectStores.begin(); it != m_objectStores.end(); ++it)
         metadata.objectStores.set(it->first, it->second->metadata());
     return metadata;
@@ -214,6 +235,10 @@
         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR, "Connection was closed before set version transaction was created"));
         return;
     }
+    if (m_intVersion != IDBDatabaseMetadata::NoIntVersion) {
+        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, String::format("You can't use the setVersion function if you've already set the version through an open call.  The current integer version is %lld", static_cast<long long>(m_intVersion))));
+        return;
+    }
     for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
         if (*it != databaseCallbacks)
             (*it)->onVersionChange(version);
@@ -259,6 +284,20 @@
     callbacks->onSuccess(PassRefPtr<IDBTransactionBackendInterface>(transaction));
 }
 
+void IDBDatabaseBackendImpl::setIntVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+    int64_t databaseId = database->id();
+    int64_t oldVersion = database->m_intVersion;
+    ASSERT(version > oldVersion);
+    database->m_intVersion = version;
+    if (!database->m_backingStore->updateIDBDatabaseIntVersion(databaseId, database->m_intVersion)) {
+        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+        transaction->abort();
+        return;
+    }
+    callbacks->onUpgradeNeeded(oldVersion, transaction, database);
+}
+
 void IDBDatabaseBackendImpl::transactionStarted(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
 {
     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
@@ -276,6 +315,16 @@
     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
         ASSERT(transaction.get() == m_runningVersionChangeTransaction.get());
         m_runningVersionChangeTransaction.clear();
+    }
+}
+
+void IDBDatabaseBackendImpl::transactionFinishedAndEventsFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
+{
+    RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
+    if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
+        // If this was an open-with-version call, there will be a "second
+        // half" open call waiting for us in processPendingCalls.
+        // FIXME: When we no longer support setVersion, assert such a thing.
         processPendingCalls();
     }
 }
@@ -287,7 +336,16 @@
 
 void IDBDatabaseBackendImpl::processPendingCalls()
 {
-    ASSERT(connectionCount() <= 1);
+    // FIXME: Change from queue to just a single place holder.
+    ASSERT(m_pendingSecondHalfOpenWithVersionCalls.size() <= 1);
+    while (!m_pendingSecondHalfOpenWithVersionCalls.isEmpty()) {
+        RefPtr<PendingOpenWithVersionCall> pendingOpenWithVersionCall = m_pendingSecondHalfOpenWithVersionCalls.takeFirst();
+        ASSERT(pendingOpenWithVersionCall->version() == m_intVersion);
+        ASSERT(m_id != InvalidId);
+        ++m_pendingConnectionCount;
+        pendingOpenWithVersionCall->callbacks()->onSuccess(this);
+        return;
+    }
 
     // Pending calls may be requeued or aborted
     Deque<RefPtr<PendingSetVersionCall> > pendingSetVersionCalls;
@@ -325,6 +383,13 @@
     if (m_runningVersionChangeTransaction || !m_pendingSetVersionCalls.isEmpty() || !m_pendingDeleteCalls.isEmpty())
         return;
 
+    Deque<RefPtr<PendingOpenWithVersionCall> > pendingOpenWithVersionCalls;
+    m_pendingOpenWithVersionCalls.swap(pendingOpenWithVersionCalls);
+    while (!pendingOpenWithVersionCalls.isEmpty()) {
+        RefPtr<PendingOpenWithVersionCall> pendingOpenWithVersionCall = pendingOpenWithVersionCalls.takeFirst();
+        openConnectionWithVersion(pendingOpenWithVersionCall->callbacks(), pendingOpenWithVersionCall->version());
+    }
+
     // Given the check above, it appears that calls cannot be requeued by
     // openConnection, but use a different queue for iteration to be safe.
     Deque<RefPtr<PendingOpenCall> > pendingOpenCalls;
@@ -356,6 +421,10 @@
     ASSERT(m_pendingConnectionCount);
     --m_pendingConnectionCount;
     m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(callbacks));
+    // We give max priority to open calls that follow upgradeneeded
+    // events; trigger the rest of the queues to be serviced when those open
+    // calls are finished.
+    processPendingCalls();
 }
 
 void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> callbacks)
@@ -373,6 +442,80 @@
     }
 }
 
+void IDBDatabaseBackendImpl::runIntVersionChangeTransaction(int64_t requestedVersion, PassRefPtr<IDBCallbacks> prpCallbacks)
+{
+    // FIXME: This function won't be reached until it's exposed to script in
+    // wbk.ug/92897.
+    ASSERT_NOT_REACHED();
+
+    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+    ASSERT(callbacks);
+    for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
+        // Note that some connections might close in the versionchange event
+        // handler for some other connection, after which its own versionchange
+        // event should not be fired. The backend doesn't worry about this, we
+        // just queue up a version change event for every connection. The
+        // frontend takes care to only dispatch to open connections.
+        (*it)->onVersionChange(m_intVersion, requestedVersion);
+    }
+    // The spec dictates we wait until all the version change events are
+    // delivered and then check m_databaseCallbacks.empty() before proceeding
+    // or firing a blocked event, but instead we should be consistent with how
+    // the old setVersion (incorrectly) did it.
+    // FIXME: Remove the call to onBlocked and instead wait until the frontend
+    // tells us that all the blocked events have been delivered. See
+    // https://bugs.webkit.org/show_bug.cgi?id=71130
+    if (connectionCount() > 0)
+        callbacks->onBlocked(m_intVersion);
+    // FIXME: Add test for m_runningVersionChangeTransaction.
+    if (m_runningVersionChangeTransaction || connectionCount() > 0) {
+        m_pendingOpenWithVersionCalls.append(PendingOpenWithVersionCall::create(callbacks, requestedVersion));
+        return;
+    }
+
+    RefPtr<DOMStringList> objectStoreNames = DOMStringList::create();
+    ExceptionCode ec = 0;
+    RefPtr<IDBTransactionBackendInterface> transactionInterface = transaction(objectStoreNames.get(), IDBTransaction::VERSION_CHANGE, ec);
+    RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface.get());
+    ASSERT(!ec);
+
+    RefPtr<IDBDatabaseBackendImpl> database = this;
+    OwnPtr<ScriptExecutionContext::Task> intVersionTask = createCallbackTask(&IDBDatabaseBackendImpl::setIntVersionInternal, database, requestedVersion, callbacks, transaction);
+    // FIXME: Make this reset the integer version as well.
+    OwnPtr<ScriptExecutionContext::Task> resetVersionOnAbortTask = createCallbackTask(&IDBDatabaseBackendImpl::resetVersion, database, m_version);
+    if (!transaction->scheduleTask(intVersionTask.release(), resetVersionOnAbortTask.release()))
+        ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
+    m_pendingSecondHalfOpenWithVersionCalls.append(PendingOpenWithVersionCall::create(callbacks, requestedVersion));
+}
+
+void IDBDatabaseBackendImpl::openConnectionWithVersion(PassRefPtr<IDBCallbacks> prpCallbacks, int64_t version)
+{
+    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+    if (!m_pendingDeleteCalls.isEmpty() || m_runningVersionChangeTransaction || !m_pendingSetVersionCalls.isEmpty()) {
+        m_pendingOpenWithVersionCalls.append(PendingOpenWithVersionCall::create(callbacks, version));
+        return;
+    }
+    if (m_id == InvalidId) {
+        if (openInternal())
+            ASSERT(m_intVersion == IDBDatabaseMetadata::NoIntVersion);
+        else {
+            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+            return;
+        }
+    }
+    if (version > m_intVersion) {
+        runIntVersionChangeTransaction(version, callbacks);
+        return;
+    }
+    if (version < m_intVersion) {
+        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::VER_ERR, String::format("The requested version (%lld) is less than the existing version (%lld).", static_cast<long long>(version), static_cast<long long>(m_intVersion))));
+        return;
+    }
+    ASSERT(version == m_intVersion);
+    ++m_pendingConnectionCount;
+    callbacks->onSuccess(this);
+}
+
 void IDBDatabaseBackendImpl::deleteDatabase(PassRefPtr<IDBCallbacks> prpCallbacks)
 {
     if (m_runningVersionChangeTransaction || !m_pendingSetVersionCalls.isEmpty()) {
@@ -388,17 +531,19 @@
     // FIXME: Only fire onBlocked if there are open connections after the
     // VersionChangeEvents are received, not just set up to fire.
     // https://bugs.webkit.org/show_bug.cgi?id=71130
-    if (!m_databaseCallbacksSet.isEmpty()) {
+    if (connectionCount() >= 1) {
         m_pendingDeleteCalls.append(PendingDeleteCall::create(callbacks));
         callbacks->onBlocked();
         return;
     }
+    ASSERT(m_backingStore);
     if (!m_backingStore->deleteDatabase(m_name)) {
         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
         return;
     }
     m_version = "";
     m_id = InvalidId;
+    m_intVersion = IDBDatabaseMetadata::NoIntVersion;
     m_objectStores.clear();
     callbacks->onSuccess(SerializedScriptValue::nullValue());
 }
@@ -411,12 +556,17 @@
     if (connectionCount() > 1)
         return;
 
+    TransactionSet transactions(m_transactions);
     processPendingCalls();
 
-    if (!connectionCount()) {
-        TransactionSet transactions(m_transactions);
+    ASSERT(m_transactions.size() - transactions.size() <= 1);
+    // FIXME: Instead of relying on transactions.size(), make connectionCount
+    // aware of in-flight upgradeneeded events as well as in-flight success
+    // events.
+    if (!connectionCount() && !m_pendingDeleteCalls.size() && m_transactions.size() == transactions.size()) {
         for (TransactionSet::const_iterator it = transactions.begin(); it != transactions.end(); ++it)
             (*it)->abort();
+
         ASSERT(m_transactions.isEmpty());
 
         m_backingStore.clear();

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseBackendImpl.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -57,6 +57,7 @@
 
     void registerFrontendCallbacks(PassRefPtr<IDBDatabaseCallbacks>);
     void openConnection(PassRefPtr<IDBCallbacks>);
+    void openConnectionWithVersion(PassRefPtr<IDBCallbacks>, int64_t version);
     void deleteDatabase(PassRefPtr<IDBCallbacks>);
 
     // IDBDatabaseBackendInterface
@@ -71,11 +72,13 @@
     IDBTransactionCoordinator* transactionCoordinator() const { return m_transactionCoordinator.get(); }
     void transactionStarted(PassRefPtr<IDBTransactionBackendImpl>);
     void transactionFinished(PassRefPtr<IDBTransactionBackendImpl>);
+    void transactionFinishedAndEventsFired(PassRefPtr<IDBTransactionBackendImpl>);
 
 private:
     IDBDatabaseBackendImpl(const String& name, IDBBackingStore* database, IDBTransactionCoordinator*, IDBFactoryBackendImpl*, const String& uniqueIdentifier);
 
     bool openInternal();
+    void runIntVersionChangeTransaction(int64_t requestedVersion, PassRefPtr<IDBCallbacks>);
     void loadObjectStores();
     int32_t connectionCount();
     void processPendingCalls();
@@ -83,6 +86,7 @@
     static void createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendImpl>);
     static void deleteObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendImpl>);
     static void setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendImpl>);
+    static void setIntVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, int64_t version, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
 
     // These are used as setVersion transaction abort tasks.
     static void removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
@@ -93,6 +97,7 @@
     int64_t m_id;
     String m_name;
     String m_version;
+    int64_t m_intVersion;
 
     String m_identifier;
     // This might not need to be a RefPtr since the factory's lifetime is that of the page group, but it's better to be conservitive than sorry.
@@ -113,6 +118,10 @@
     class PendingOpenCall;
     Deque<RefPtr<PendingOpenCall> > m_pendingOpenCalls;
 
+    class PendingOpenWithVersionCall;
+    Deque<RefPtr<PendingOpenWithVersionCall> > m_pendingOpenWithVersionCalls;
+    Deque<RefPtr<PendingOpenWithVersionCall> > m_pendingSecondHalfOpenWithVersionCalls;
+
     class PendingDeleteCall;
     Deque<RefPtr<PendingDeleteCall> > m_pendingDeleteCalls;
 

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseCallbacks.h (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseCallbacks.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBDatabaseCallbacks.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -38,6 +38,7 @@
     virtual ~IDBDatabaseCallbacks() { }
 
     virtual void onVersionChange(const String& version) = 0;
+    virtual void onVersionChange(int64_t currentVersion, int64_t requestedVersion) { ASSERT_NOT_REACHED(); }
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp	2012-08-04 00:28:25 UTC (rev 124675)
@@ -35,6 +35,7 @@
 #include "IDBDatabaseException.h"
 #include "IDBLevelDBBackingStore.h"
 #include "IDBTransactionCoordinator.h"
+#include "SecurityOrigin.h"
 #include <wtf/Threading.h>
 #include <wtf/UnusedParam.h>
 
@@ -151,30 +152,34 @@
 
 void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> prpSecurityOrigin, ScriptExecutionContext*, const String& dataDirectory)
 {
+    // FIXME: Make this a parameter and plumb through from _javascript_.
+    int64_t version = IDBDatabaseMetadata::NoIntVersion;
     RefPtr<SecurityOrigin> securityOrigin = prpSecurityOrigin;
     const String uniqueIdentifier = computeUniqueIdentifier(name, securityOrigin.get());
 
+    RefPtr<IDBDatabaseBackendImpl> databaseBackend;
     IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentifier);
-    if (it != m_databaseBackendMap.end()) {
-        // If it's already been opened, we have to wait for any pending
-        // setVersion calls to complete.
-        it->second->openConnection(callbacks);
-        return;
-    }
+    if (it == m_databaseBackendMap.end()) {
+        RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
+        if (!backingStore) {
+            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+            return;
+        }
 
-    // FIXME: Everything from now on should be done on another thread.
-    RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
-    if (!backingStore) {
-        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
-        return;
-    }
+        databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), m_transactionCoordinator.get(), this, uniqueIdentifier);
+        if (databaseBackend)
+            m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
+        else {
+            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+            return;
+        }
+    } else
+        databaseBackend = it->second;
 
-    RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::create(name, backingStore.get(), m_transactionCoordinator.get(), this, uniqueIdentifier);
-    if (databaseBackend) {
-        m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get());
+    if (version == IDBDatabaseMetadata::NoIntVersion)
         databaseBackend->openConnection(callbacks);
-    } else
-        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
+    else
+        databaseBackend->openConnectionWithVersion(callbacks, version);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.cpp (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.cpp	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.cpp	2012-08-04 00:28:25 UTC (rev 124675)
@@ -234,7 +234,7 @@
     }
 }
 
-bool IDBLevelDBBackingStore::getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId)
+bool IDBLevelDBBackingStore::getIDBDatabaseMetaData(const String& name, String& foundStringVersion, int64_t& foundIntVersion, int64_t& foundId)
 {
     const Vector<char> key = DatabaseNameKey::encode(m_identifier, name);
 
@@ -242,7 +242,7 @@
     if (!ok)
         return false;
 
-    ok = getString(m_db.get(), DatabaseMetaDataKey::encode(foundId, DatabaseMetaDataKey::UserVersion), foundVersion);
+    ok = getString(m_db.get(), DatabaseMetaDataKey::encode(foundId, DatabaseMetaDataKey::UserVersion), foundStringVersion);
     if (!ok)
         return false;
 
@@ -264,7 +264,7 @@
     return databaseId;
 }
 
-bool IDBLevelDBBackingStore::createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId)
+bool IDBLevelDBBackingStore::createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId)
 {
     rowId = getNewDatabaseId(m_db.get());
     if (rowId < 0)
@@ -278,6 +278,12 @@
     return true;
 }
 
+bool IDBLevelDBBackingStore::updateIDBDatabaseIntVersion(int64_t rowId, int64_t intVersion)
+{
+    // FIXME: Make this actually do something. http://wkb.ug/92883
+    return true;
+}
+
 bool IDBLevelDBBackingStore::updateIDBDatabaseMetaData(int64_t rowId, const String& version)
 {
     ASSERT(m_currentTransaction);
@@ -305,7 +311,8 @@
 
     int64_t databaseId;
     String version;
-    if (!getIDBDatabaseMetaData(name, version, databaseId)) {
+    int64_t intVersion;
+    if (!getIDBDatabaseMetaData(name, version, intVersion, databaseId)) {
         transaction->rollback();
         return true;
     }

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.h (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBLevelDBBackingStore.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -45,9 +45,10 @@
     virtual ~IDBLevelDBBackingStore();
 
     virtual void getDatabaseNames(Vector<String>& foundNames);
-    virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId);
-    virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId);
+    virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundIntVersion, int64_t& foundId);
+    virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId);
     virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version);
+    virtual bool updateIDBDatabaseIntVersion(int64_t rowId, int64_t intVersion);
     virtual bool deleteDatabase(const String& name);
 
     virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<IDBKeyPath>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags);

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp (124674 => 124675)


--- trunk/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransactionBackendImpl.cpp	2012-08-04 00:28:25 UTC (rev 124675)
@@ -227,6 +227,8 @@
     else
         m_callbacks->onAbort();
 
+    m_database->transactionFinishedAndEventsFired(this);
+
     m_database = 0;
 }
 

Modified: trunk/Source/WebKit/chromium/ChangeLog (124674 => 124675)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-08-04 00:28:25 UTC (rev 124675)
@@ -1,3 +1,16 @@
+2012-08-03  David Grogan  <[email protected]>
+
+        IndexedDB: Core upgradeneeded logic
+        https://bugs.webkit.org/show_bug.cgi?id=92558
+
+        Reviewed by Ojan Vafai.
+
+        Update overridden methods to match new signatures.
+
+        * tests/IDBAbortOnCorruptTest.cpp:
+        (WebCore::FailingBackingStore::createIDBDatabaseMetaData):
+        * tests/IDBFakeBackingStore.h:
+
 2012-08-03  Rick Byers  <[email protected]>
 
         Double tap gesture should send dblclick event

Modified: trunk/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp (124674 => 124675)


--- trunk/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebKit/chromium/tests/IDBAbortOnCorruptTest.cpp	2012-08-04 00:28:25 UTC (rev 124675)
@@ -74,7 +74,7 @@
     {
         return adoptRef(new FailingBackingStore);
     }
-    virtual bool createIDBDatabaseMetaData(const String&, const String&, int64_t&)
+    virtual bool createIDBDatabaseMetaData(const String&, const String&, int64_t, int64_t&)
     {
         return false;
     }

Modified: trunk/Source/WebKit/chromium/tests/IDBFakeBackingStore.h (124674 => 124675)


--- trunk/Source/WebKit/chromium/tests/IDBFakeBackingStore.h	2012-08-04 00:10:30 UTC (rev 124674)
+++ trunk/Source/WebKit/chromium/tests/IDBFakeBackingStore.h	2012-08-04 00:28:25 UTC (rev 124675)
@@ -33,9 +33,10 @@
 class IDBFakeBackingStore : public IDBBackingStore {
 public:
     virtual void getDatabaseNames(Vector<String>& foundNames) OVERRIDE { }
-    virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundId) OVERRIDE { return false; }
-    virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t& rowId) OVERRIDE { return true; }
+    virtual bool getIDBDatabaseMetaData(const String& name, String& foundVersion, int64_t& foundIntVersion, int64_t& foundId) OVERRIDE { return false; }
+    virtual bool createIDBDatabaseMetaData(const String& name, const String& version, int64_t intVersion, int64_t& rowId) OVERRIDE { return true; }
     virtual bool updateIDBDatabaseMetaData(int64_t rowId, const String& version) OVERRIDE { return false; }
+    virtual bool updateIDBDatabaseIntVersion(int64_t rowId, int64_t version) OVERRIDE { return false; }
     virtual bool deleteDatabase(const String& name) OVERRIDE { return false; }
 
     virtual void getObjectStores(int64_t databaseId, Vector<int64_t>& foundIds, Vector<String>& foundNames, Vector<IDBKeyPath>& foundKeyPaths, Vector<bool>& foundAutoIncrementFlags) OVERRIDE { }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to