Changeset 80028 in webkit


Ignore:
Timestamp:
Mar 1, 2011 12:42:17 PM (13 years ago)
Author:
jorlow@chromium.org
Message:

2011-02-18 Jeremy Orlow <jorlow@chromium.org>

Reviewed by Steve Block.

When an IDBTransaction is aborted, all requests that have not yet fired should fire an ABORT_ERR
https://bugs.webkit.org/show_bug.cgi?id=54785

  • storage/indexeddb/transaction-abort.html: Added
  • storage/indexeddb/transaction-abort-expected.txt: Added

2011-02-18 Jeremy Orlow <jorlow@chromium.org>

Reviewed by Steve Block.

When an IDBTransaction is aborted, all requests that have not yet fired should fire an ABORT_ERR
https://bugs.webkit.org/show_bug.cgi?id=54785

This patch adds in a lot of sanity checks/ASSERTs to make sure we're doing
the right thing and continue to do the right thing. It also modifies EventQueue
so that we can cancel an event. To do this efficiently, the vector is now a
ListHashSet.

Canelling the event is harder/messier, but the most deterministic thing to do.
To the user, the work isn't done until we fire the onsuccess/onerror handler.
So the event (which does fire that) needs to be cancelable.

transaction-abort.html tests this.

  • dom/EventQueue.cpp: (WebCore::EventQueue::enqueueEvent): (WebCore::EventQueue::cancelEvent): (WebCore::EventQueue::pendingEventTimerFired): (WebCore::EventQueue::dispatchEvent):
  • dom/EventQueue.h:
  • dom/ExceptionCode.cpp:
  • storage/IDBCursor.cpp: (WebCore::IDBCursor::update): (WebCore::IDBCursor::deleteFunction):
  • storage/IDBDatabaseBackendImpl.cpp: (WebCore::IDBDatabaseBackendImpl::close):
  • storage/IDBDatabaseException.h:
  • storage/IDBIndex.cpp: (WebCore::IDBIndex::openCursor): (WebCore::IDBIndex::openKeyCursor): (WebCore::IDBIndex::get): (WebCore::IDBIndex::getKey):
  • storage/IDBObjectStore.cpp: (WebCore::IDBObjectStore::get): (WebCore::IDBObjectStore::add): (WebCore::IDBObjectStore::put): (WebCore::IDBObjectStore::deleteFunction): (WebCore::IDBObjectStore::clear): (WebCore::IDBObjectStore::openCursor):
  • storage/IDBRequest.cpp: (WebCore::IDBRequest::IDBRequest): (WebCore::IDBRequest::~IDBRequest): (WebCore::IDBRequest::readyState): (WebCore::IDBRequest::markEarlyDeath): (WebCore::IDBRequest::source): (WebCore::IDBRequest::abort): (WebCore::IDBRequest::onSuccess): (WebCore::IDBRequest::dispatchEvent): (WebCore::IDBRequest::enqueueEvent):
  • storage/IDBRequest.h:
  • storage/IDBTransaction.cpp: (WebCore::IDBTransaction::registerRequest): (WebCore::IDBTransaction::unregisterRequest): (WebCore::IDBTransaction::onAbort):
  • storage/IDBTransaction.h:
Location:
trunk
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r80027 r80028  
     12011-02-18  Jeremy Orlow  <jorlow@chromium.org>
     2
     3        Reviewed by Steve Block.
     4
     5        When an IDBTransaction is aborted, all requests that have not yet fired should fire an ABORT_ERR
     6        https://bugs.webkit.org/show_bug.cgi?id=54785
     7
     8        * storage/indexeddb/transaction-abort.html: Added
     9        * storage/indexeddb/transaction-abort-expected.txt: Added
     10
    1112011-03-01  Tony Gentilcore  <tonyg@chromium.org>
    212
  • trunk/Source/WebCore/ChangeLog

    r80025 r80028  
     12011-02-18  Jeremy Orlow  <jorlow@chromium.org>
     2
     3        Reviewed by Steve Block.
     4
     5        When an IDBTransaction is aborted, all requests that have not yet fired should fire an ABORT_ERR
     6        https://bugs.webkit.org/show_bug.cgi?id=54785
     7
     8        This patch adds in a lot of sanity checks/ASSERTs to make sure we're doing
     9        the right thing and continue to do the right thing. It also modifies EventQueue
     10        so that we can cancel an event. To do this efficiently, the vector is now a
     11        ListHashSet.
     12
     13        Canelling the event is harder/messier, but the most deterministic thing to do.
     14        To the user, the work isn't done until we fire the onsuccess/onerror handler.
     15        So the event (which does fire that) needs to be cancelable.
     16
     17        transaction-abort.html tests this.
     18
     19        * dom/EventQueue.cpp:
     20        (WebCore::EventQueue::enqueueEvent):
     21        (WebCore::EventQueue::cancelEvent):
     22        (WebCore::EventQueue::pendingEventTimerFired):
     23        (WebCore::EventQueue::dispatchEvent):
     24        * dom/EventQueue.h:
     25        * dom/ExceptionCode.cpp:
     26        * storage/IDBCursor.cpp:
     27        (WebCore::IDBCursor::update):
     28        (WebCore::IDBCursor::deleteFunction):
     29        * storage/IDBDatabaseBackendImpl.cpp:
     30        (WebCore::IDBDatabaseBackendImpl::close):
     31        * storage/IDBDatabaseException.h:
     32        * storage/IDBIndex.cpp:
     33        (WebCore::IDBIndex::openCursor):
     34        (WebCore::IDBIndex::openKeyCursor):
     35        (WebCore::IDBIndex::get):
     36        (WebCore::IDBIndex::getKey):
     37        * storage/IDBObjectStore.cpp:
     38        (WebCore::IDBObjectStore::get):
     39        (WebCore::IDBObjectStore::add):
     40        (WebCore::IDBObjectStore::put):
     41        (WebCore::IDBObjectStore::deleteFunction):
     42        (WebCore::IDBObjectStore::clear):
     43        (WebCore::IDBObjectStore::openCursor):
     44        * storage/IDBRequest.cpp:
     45        (WebCore::IDBRequest::IDBRequest):
     46        (WebCore::IDBRequest::~IDBRequest):
     47        (WebCore::IDBRequest::readyState):
     48        (WebCore::IDBRequest::markEarlyDeath):
     49        (WebCore::IDBRequest::source):
     50        (WebCore::IDBRequest::abort):
     51        (WebCore::IDBRequest::onSuccess):
     52        (WebCore::IDBRequest::dispatchEvent):
     53        (WebCore::IDBRequest::enqueueEvent):
     54        * storage/IDBRequest.h:
     55        * storage/IDBTransaction.cpp:
     56        (WebCore::IDBTransaction::registerRequest):
     57        (WebCore::IDBTransaction::unregisterRequest):
     58        (WebCore::IDBTransaction::onAbort):
     59        * storage/IDBTransaction.h:
     60
    1612011-02-28  Jeremy Orlow  <jorlow@chromium.org>
    262
  • trunk/Source/WebCore/dom/EventQueue.cpp

    r77650 r80028  
    6060{
    6161    ASSERT(event->target());
    62     m_queuedEvents.append(event);
     62    bool wasAdded = m_queuedEvents.add(event).second;
     63    ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
    6364   
    6465    if (!m_pendingEventTimer->isActive())
     
    7879}
    7980
     81bool EventQueue::cancelEvent(Event* event)
     82{
     83    bool found = m_queuedEvents.contains(event);
     84    m_queuedEvents.remove(event);
     85    if (m_queuedEvents.isEmpty())
     86        m_pendingEventTimer->stop();
     87    return found;
     88}
     89
    8090void EventQueue::pendingEventTimerFired()
    8191{
    8292    ASSERT(!m_pendingEventTimer->isActive());
     93    ASSERT(!m_queuedEvents.isEmpty());
    8394
    84     Vector<RefPtr<Event> > queuedEvents;
    85     queuedEvents.swap(m_queuedEvents);
    86    
    8795    m_nodesWithQueuedScrollEvents.clear();
    8896
    89     for (size_t i = 0; i < queuedEvents.size(); i++)
    90         dispatchEvent(queuedEvents[i].release());
     97    // Insert a marker for where we should stop.
     98    ASSERT(!m_queuedEvents.contains(0));
     99    bool wasAdded = m_queuedEvents.add(0).second;
     100    ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
     101
     102    while (!m_queuedEvents.isEmpty()) {
     103        ListHashSet<RefPtr<Event> >::iterator iter = m_queuedEvents.begin();
     104        RefPtr<Event> event = *iter;
     105        m_queuedEvents.remove(iter);
     106        if (!event)
     107            break;
     108        dispatchEvent(event.get());
     109    }
    91110}
    92111
     
    94113{
    95114    EventTarget* eventTarget = event->target();
    96     if (eventTarget->toNode())
    97         eventTarget->dispatchEvent(event);
    98     else if (eventTarget->toDOMWindow())
     115    if (eventTarget->toDOMWindow())
    99116        eventTarget->toDOMWindow()->dispatchEvent(event, 0);
    100117    else
  • trunk/Source/WebCore/dom/EventQueue.h

    r77355 r80028  
    2929
    3030#include <wtf/HashSet.h>
     31#include <wtf/ListHashSet.h>
    3132#include <wtf/Noncopyable.h>
    3233#include <wtf/OwnPtr.h>
    3334#include <wtf/PassOwnPtr.h>
    3435#include <wtf/RefPtr.h>
    35 #include <wtf/Vector.h>
    3636
    3737namespace WebCore {
     
    6161    void enqueueEvent(PassRefPtr<Event>);
    6262    void enqueueScrollEvent(PassRefPtr<Node>, ScrollEventTargetType);
     63    bool cancelEvent(Event*);
    6364
    6465private:
     
    6970
    7071    OwnPtr<EventQueueTimer> m_pendingEventTimer;
    71     Vector<RefPtr<Event> > m_queuedEvents;
     72    ListHashSet<RefPtr<Event> > m_queuedEvents;
    7273    HashSet<Node*> m_nodesWithQueuedScrollEvents;
    7374   
  • trunk/Source/WebCore/dom/ExceptionCode.cpp

    r75596 r80028  
    224224    "TIMEOUT_ERR",
    225225    "DEADLOCK_ERR",
    226     "READ_ONLY_ERR"
     226    "READ_ONLY_ERR",
     227    "ABORT_ERR"
    227228};
    228229
     
    239240    "TIMEOUT_ERR", // This can't be thrown.
    240241    "DEADLOCK_ERR", // This can't be thrown.
    241     "Write operations cannot be preformed on a read-only transaction."
     242    "Write operations cannot be preformed on a read-only transaction.",
     243    "The transaction was aborted, so the request cannot be fulfilled."
    242244};
    243245#endif
  • trunk/Source/WebCore/storage/IDBCursor.cpp

    r77689 r80028  
    7373    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    7474    m_backend->update(value, request, ec);
    75     if (ec)
     75    if (ec) {
     76        request->markEarlyDeath();
    7677        return 0;
     78    }
    7779    return request.release();
    7880}
     
    9294    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    9395    m_backend->deleteFunction(request, ec);
    94     if (ec)
     96    if (ec) {
     97        request->markEarlyDeath();
    9598        return 0;
     99    }
    96100    return request.release();
    97101}
  • trunk/Source/WebCore/storage/IDBDatabaseException.h

    r78525 r80028  
    5656        TIMEOUT_ERR = IDBDatabaseExceptionOffset + 10,
    5757        DEADLOCK_ERR = IDBDatabaseExceptionOffset + 11,
    58         READ_ONLY_ERR = IDBDatabaseExceptionOffset + 12
     58        READ_ONLY_ERR = IDBDatabaseExceptionOffset + 12,
     59        ABORT_ERR = IDBDatabaseExceptionOffset + 13
    5960    };
    6061
  • trunk/Source/WebCore/storage/IDBDatabaseException.idl

    r78525 r80028  
    5353        const unsigned short DEADLOCK_ERR = 11;
    5454        const unsigned short READ_ONLY_ERR = 12;
     55        const unsigned short ABORT_ERR = 13;
    5556    };
    5657
  • trunk/Source/WebCore/storage/IDBIndex.cpp

    r77689 r80028  
    6363    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    6464    m_backend->openCursor(keyRange, direction, request, m_transaction->backend(), ec);
    65     if (ec)
     65    if (ec) {
     66        request->markEarlyDeath();
    6667        return 0;
     68    }
    6769    return request;
    6870}
     
    7880    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    7981    m_backend->openKeyCursor(keyRange, direction, request, m_transaction->backend(), ec);
    80     if (ec)
     82    if (ec) {
     83        request->markEarlyDeath();
    8184        return 0;
     85    }
    8286    return request;
    8387}
     
    8791    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    8892    m_backend->get(key, request, m_transaction->backend(), ec);
    89     if (ec)
     93    if (ec) {
     94        request->markEarlyDeath();
    9095        return 0;
     96    }
    9197    return request;
    9298}
     
    96102    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    97103    m_backend->getKey(key, request, m_transaction->backend(), ec);
    98     if (ec)
     104    if (ec) {
     105        request->markEarlyDeath();
    99106        return 0;
     107    }
    100108    return request;
    101109}
  • trunk/Source/WebCore/storage/IDBObjectStore.cpp

    r78416 r80028  
    7272    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    7373    m_objectStore->get(key, request, m_transaction->backend(), ec);
    74     if (ec)
     74    if (ec) {
     75        request->markEarlyDeath();
    7576        return 0;
     77    }
    7678    return request.release();
    7779}
     
    8183    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    8284    m_objectStore->put(value, key, IDBObjectStoreBackendInterface::AddOnly, request, m_transaction->backend(), ec);
    83     if (ec)
     85    if (ec) {
     86        request->markEarlyDeath();
    8487        return 0;
    85     return request;
     88    }
     89    return request.release();
    8690}
    8791
     
    9094    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    9195    m_objectStore->put(value, key, IDBObjectStoreBackendInterface::AddOrUpdate, request, m_transaction->backend(), ec);
    92     if (ec)
     96    if (ec) {
     97        request->markEarlyDeath();
    9398        return 0;
    94     return request;
     99    }
     100    return request.release();
    95101}
    96102
     
    99105    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    100106    m_objectStore->deleteFunction(key, request, m_transaction->backend(), ec);
    101     if (ec)
     107    if (ec) {
     108        request->markEarlyDeath();
    102109        return 0;
    103     return request;
     110    }
     111    return request.release();
    104112}
    105113
     
    108116    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    109117    m_objectStore->clear(request, m_transaction->backend(), ec);
    110     if (ec)
     118    if (ec) {
     119        request->markEarlyDeath();
    111120        return 0;
    112     return request;
     121    }
     122    return request.release();
    113123}
    114124
     
    149159    RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
    150160    m_objectStore->openCursor(range, direction, request, m_transaction->backend(), ec);
    151     if (ec)
     161    if (ec) {
     162        request->markEarlyDeath();
    152163        return 0;
     164    }
    153165    return request.release();
    154166}
  • trunk/Source/WebCore/storage/IDBRequest.cpp

    r80025 r80028  
    4343#include "IDBObjectStore.h"
    4444#include "IDBPendingTransactionMonitor.h"
     45#include "IDBTransaction.h"
    4546
    4647namespace WebCore {
     
    5960    , m_finished(false)
    6061{
     62    if (m_transaction) {
     63        m_transaction->registerRequest(this);
     64        IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
     65    }
     66}
     67
     68IDBRequest::~IDBRequest()
     69{
     70    ASSERT(m_readyState == DONE || m_readyState == EarlyDeath);
    6171    if (m_transaction)
    62         IDBPendingTransactionMonitor::removePendingTransaction(m_transaction->backend());
    63 }
    64 
    65 IDBRequest::~IDBRequest()
    66 {
     72        m_transaction->unregisterRequest(this);
    6773}
    6874
     
    106112unsigned short IDBRequest::readyState() const
    107113{
     114    ASSERT(m_readyState == LOADING || m_readyState == DONE);
    108115    return m_readyState;
     116}
     117
     118void IDBRequest::markEarlyDeath()
     119{
     120    ASSERT(m_readyState == LOADING);
     121    m_readyState = EarlyDeath;
    109122}
    110123
     
    127140}
    128141
     142IDBAny* IDBRequest::source()
     143{
     144    return m_source.get();
     145}
     146
     147void IDBRequest::abort()
     148{
     149    if (m_readyState != LOADING) {
     150        ASSERT(m_readyState == DONE);
     151        return;
     152    }
     153
     154    ASSERT(scriptExecutionContext()->isDocument());
     155    EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
     156    for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
     157        bool removed = eventQueue->cancelEvent(m_enqueuedEvents[i].get());
     158        ASSERT_UNUSED(removed, removed);
     159    }
     160    m_enqueuedEvents.clear();
     161
     162    m_errorCode = 0;
     163    m_errorMessage = String();
     164    m_result.clear();
     165    onError(IDBDatabaseError::create(IDBDatabaseException::ABORT_ERR, "The transaction was aborted, so the request cannot be fulfilled."));
     166}
     167
    129168void IDBRequest::onError(PassRefPtr<IDBDatabaseError> error)
    130169{
     
    219258{
    220259    ASSERT(!m_finished);
     260    ASSERT(m_enqueuedEvents.size());
    221261    ASSERT(scriptExecutionContext());
    222262    ASSERT(event->target() == this);
     
    224264    if (event->type() != eventNames().blockedEvent)
    225265        m_readyState = DONE;
     266
     267    for (size_t i = 0; i < m_enqueuedEvents.size(); ++i) {
     268        if (m_enqueuedEvents[i].get() == event.get())
     269            m_enqueuedEvents.remove(i);
     270    }
    226271
    227272    Vector<RefPtr<EventTarget> > targets;
     
    241286
    242287    // If the result was of type IDBCursor, then we'll fire again.
    243 //    if (m_result && m_result->type() != IDBAny::IDBCursorType && event->type() != eventNames.blockedEvent)
    244288    if (m_result && m_result->type() != IDBAny::IDBCursorType)
    245289        m_finished = true;
     
    270314    EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue();
    271315    event->setTarget(this);
    272     eventQueue->enqueueEvent(event);
    273 }
    274 
    275 IDBAny* IDBRequest::source()
    276 {
    277     return m_source.get();
     316    eventQueue->enqueueEvent(event.get());
     317    m_enqueuedEvents.append(event);
    278318}
    279319
  • trunk/Source/WebCore/storage/IDBRequest.h

    r78908 r80028  
    5959    enum ReadyState {
    6060        LOADING = 1,
    61         DONE = 2
     61        DONE = 2,
     62        EarlyDeath = 3
    6263    };
    6364    unsigned short readyState() const;
     
    6667    DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
    6768
     69    void markEarlyDeath();
    6870    bool resetReadyState(IDBTransaction*);
    6971    IDBAny* source();
     72    void abort();
    7073
    7174    // IDBCallbacks
     
    112115    ReadyState m_readyState;
    113116    bool m_finished; // Is it possible that we'll fire any more events? If not, we're finished.
     117    Vector<RefPtr<Event> > m_enqueuedEvents;
    114118
    115119    EventTargetData m_eventTargetData;
  • trunk/Source/WebCore/storage/IDBTransaction.cpp

    r80025 r80028  
    104104}
    105105
     106void IDBTransaction::registerRequest(IDBRequest* request)
     107{
     108    m_childRequests.add(request);
     109}
     110
     111void IDBTransaction::unregisterRequest(IDBRequest* request)
     112{
     113    // If we aborted the request, it will already have been removed.
     114    m_childRequests.remove(request);
     115}
     116
    106117void IDBTransaction::onAbort()
    107118{
     119    while (!m_childRequests.isEmpty()) {
     120        IDBRequest* request = *m_childRequests.begin();
     121        m_childRequests.remove(request);
     122        request->abort();
     123    }
     124
    108125    enqueueEvent(Event::create(eventNames().abortEvent, true, false));
    109126}
  • trunk/Source/WebCore/storage/IDBTransaction.h

    r78280 r80028  
    6363    void abort();
    6464
     65    void registerRequest(IDBRequest*);
     66    void unregisterRequest(IDBRequest*);
     67
    6568    DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
    6669    DEFINE_ATTRIBUTE_EVENT_LISTENER(complete);
     
    101104    bool m_finished; // Is it possible that we'll fire any more events or allow any new transactions? If not, we're finished.
    102105
     106    ListHashSet<IDBRequest*> m_childRequests;
     107
    103108    EventTargetData m_eventTargetData;
    104109};
Note: See TracChangeset for help on using the changeset viewer.