Changeset 122291 in webkit


Ignore:
Timestamp:
Jul 10, 2012 9:24:22 PM (12 years ago)
Author:
jsbell@chromium.org
Message:

IndexedDB: Ensure transaction abort events are deterministic in multiprocess ports
https://bugs.webkit.org/show_bug.cgi?id=90412

Reviewed by Tony Chang.

In multi-process ports (e.g. Chromium), transaction aborts triggered on the front-end could
be initiated while a "success" event was in-flight from the back end. This would lead to
apparently flaky behavior when requests would sometimes report success and sometimes report
an error. Address this by having front-end triggered aborts do the abort steps immediately,
then send the async abort request to the back end.

No new tests - behavior in single process ports (and DRT) covered by existing
tests. Will enable currently disabled Chromium tests to be enabled (crbug.com/83226).

  • Modules/indexeddb/IDBRequest.cpp:

(WebCore::IDBRequest::IDBRequest): Initialize a new m_requestAborted flag, used to prevent
dispatching if an in-flight request comes in after the abort.
(WebCore::IDBRequest::abort): Set flag to prevent double dispatching.
(WebCore::IDBRequest::onError): Handle aborted-then-received-event case.
(WebCore::IDBRequest::onSuccess): Ditto.
(WebCore::IDBRequest::onSuccessWithContinuation): Ditto.
(WebCore::IDBRequest::dispatchEvent): On uncaught error, trigger abort on transaction front-end.

  • Modules/indexeddb/IDBRequest.h:

(IDBRequest):

  • Modules/indexeddb/IDBTransaction.cpp:

(WebCore::IDBTransaction::abort): Do abort steps locally first, then notify back-end.
(WebCore::IDBTransaction::onAbort): If abort wasn't triggered locally, clean up is still necessary.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r122290 r122291  
     12012-07-10  Joshua Bell  <jsbell@chromium.org>
     2
     3        IndexedDB: Ensure transaction abort events are deterministic in multiprocess ports
     4        https://bugs.webkit.org/show_bug.cgi?id=90412
     5
     6        Reviewed by Tony Chang.
     7
     8        In multi-process ports (e.g. Chromium), transaction aborts triggered on the front-end could
     9        be initiated while a "success" event was in-flight from the back end. This would lead to
     10        apparently flaky behavior when requests would sometimes report success and sometimes report
     11        an error. Address this by having front-end triggered aborts do the abort steps immediately,
     12        then send the async abort request to the back end.
     13
     14        No new tests - behavior in single process ports (and DRT) covered by existing
     15        tests. Will enable currently disabled Chromium tests to be enabled (crbug.com/83226).
     16
     17        * Modules/indexeddb/IDBRequest.cpp:
     18        (WebCore::IDBRequest::IDBRequest): Initialize a new m_requestAborted flag, used to prevent
     19        dispatching if an in-flight request comes in after the abort.
     20        (WebCore::IDBRequest::abort): Set flag to prevent double dispatching.
     21        (WebCore::IDBRequest::onError): Handle aborted-then-received-event case.
     22        (WebCore::IDBRequest::onSuccess): Ditto.
     23        (WebCore::IDBRequest::onSuccessWithContinuation): Ditto.
     24        (WebCore::IDBRequest::dispatchEvent): On uncaught error, trigger abort on transaction front-end.
     25        * Modules/indexeddb/IDBRequest.h:
     26        (IDBRequest):
     27        * Modules/indexeddb/IDBTransaction.cpp:
     28        (WebCore::IDBTransaction::abort): Do abort steps locally first, then notify back-end.
     29        (WebCore::IDBTransaction::onAbort): If abort wasn't triggered locally, clean up is still necessary.
     30
    1312012-07-10  Julien Chaffraix  <jchaffraix@webkit.org>
    232
  • trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp

    r121612 r122291  
    5858    , m_transaction(transaction)
    5959    , m_readyState(PENDING)
     60    , m_requestAborted(false)
    6061    , m_requestFinished(false)
    6162    , m_cursorFinished(false)
     
    167168void IDBRequest::abort()
    168169{
     170    ASSERT(!m_requestAborted);
    169171    if (m_contextStopped || !scriptExecutionContext())
    170172        return;
     
    187189    m_result.clear();
    188190    onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
     191    m_requestAborted = true;
    189192}
    190193
     
    211214void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
    212215{
     216    if (m_requestAborted)
     217        return;
    213218    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_result);
    214219    m_errorCode = error->code();
     
    228233{
    229234    IDB_TRACE("IDBRequest::onSuccess(DOMStringList)");
     235    if (m_requestAborted)
     236        return;
    230237    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    231238    m_result = IDBAny::create(domStringList);
     
    236243{
    237244    IDB_TRACE("IDBRequest::onSuccess(IDBCursor)");
     245    if (m_requestAborted)
     246        return;
    238247    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    239248    ASSERT(m_cursorType != IDBCursorBackendInterface::InvalidCursorType);
     
    251260{
    252261    IDB_TRACE("IDBRequest::onSuccess(IDBDatabase)");
     262    if (m_requestAborted)
     263        return;
    253264    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    254265    if (m_contextStopped || !scriptExecutionContext())
     
    265276{
    266277    IDB_TRACE("IDBRequest::onSuccess(IDBKey)");
     278    if (m_requestAborted)
     279        return;
    267280    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    268281    if (idbKey && idbKey->isValid())
     
    276289{
    277290    IDB_TRACE("IDBRequest::onSuccess(IDBTransaction)");
     291    if (m_requestAborted)
     292        return;
    278293    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    279294    RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
     
    298313{
    299314    IDB_TRACE("IDBRequest::onSuccess(SerializedScriptValue)");
     315    if (m_requestAborted)
     316        return;
    300317    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    301318    m_result = IDBAny::create(serializedScriptValue);
     
    308325{
    309326    LOG_ERROR("CHECKING: onSuccess(value, key, keypath)");
     327    if (m_requestAborted)
     328        return;
    310329    RefPtr<SerializedScriptValue> serializedScriptValue = prpSerializedScriptValue;
    311330#ifndef NDEBUG
     
    322341{
    323342    IDB_TRACE("IDBRequest::onSuccessWithContinuation");
     343    if (m_requestAborted)
     344        return;
    324345    ASSERT(!m_errorCode && m_errorMessage.isNull() && !m_error && !m_result);
    325346    ASSERT(m_cursor);
     
    422443        if (dontPreventDefault && event->type() == eventNames().errorEvent) {
    423444            m_transaction->setError(m_error);
    424             m_transaction->backend()->abort();
     445            m_transaction->abort();
    425446        }
    426447        m_transaction->backend()->didCompleteTaskEvents();
  • trunk/Source/WebCore/Modules/indexeddb/IDBRequest.h

    r121612 r122291  
    129129
    130130    ReadyState m_readyState;
     131    bool m_requestAborted; // May be aborted by transaction then receive async onsuccess; ignore vs. assert.
    131132    bool m_requestFinished; // Is it possible that we'll fire any more events? If not, we're finished.
    132133    bool m_cursorFinished;
  • trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp

    r122172 r122291  
    214214    m_state = Finishing;
    215215    m_active = false;
     216
     217    while (!m_requestList.isEmpty()) {
     218        IDBRequest* request = *m_requestList.begin();
     219        m_requestList.remove(request);
     220        request->abort();
     221    }
     222
    216223    RefPtr<IDBTransaction> selfRef = this;
    217224    if (m_backend)
     
    268275{
    269276    ASSERT(m_state != Finished);
    270     m_state = Finishing;
    271     while (!m_requestList.isEmpty()) {
    272         IDBRequest* request = *m_requestList.begin();
    273         m_requestList.remove(request);
    274         request->abort();
     277
     278    if (m_state != Finishing) {
     279        // Abort was not triggered by front-end, so outstanding requests must
     280        // be aborted now.
     281        while (!m_requestList.isEmpty()) {
     282            IDBRequest* request = *m_requestList.begin();
     283            m_requestList.remove(request);
     284            request->abort();
     285        }
     286        m_state = Finishing;
    275287    }
    276288
Note: See TracChangeset for help on using the changeset viewer.