diff options
Diffstat (limited to 'Source/WebCore/storage/IDBTransaction.cpp')
-rw-r--r-- | Source/WebCore/storage/IDBTransaction.cpp | 129 |
1 files changed, 72 insertions, 57 deletions
diff --git a/Source/WebCore/storage/IDBTransaction.cpp b/Source/WebCore/storage/IDBTransaction.cpp index e3625d4..1f696b3 100644 --- a/Source/WebCore/storage/IDBTransaction.cpp +++ b/Source/WebCore/storage/IDBTransaction.cpp @@ -28,8 +28,9 @@ #if ENABLE(INDEXED_DATABASE) -#include "Event.h" +#include "Document.h" #include "EventException.h" +#include "EventQueue.h" #include "IDBAbortEvent.h" #include "IDBCompleteEvent.h" #include "IDBDatabase.h" @@ -38,20 +39,22 @@ #include "IDBObjectStore.h" #include "IDBObjectStoreBackendInterface.h" #include "IDBPendingTransactionMonitor.h" -#include "IDBTimeoutEvent.h" -#include "ScriptExecutionContext.h" namespace WebCore { +PassRefPtr<IDBTransaction> IDBTransaction::create(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db) +{ + return adoptRef(new IDBTransaction(context, backend, db)); +} + IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTransactionBackendInterface> backend, IDBDatabase* db) : ActiveDOMObject(context, this) , m_backend(backend) , m_database(db) , m_mode(m_backend->mode()) - , m_onAbortTimer(this, &IDBTransaction::onAbortTimerFired) - , m_onCompleteTimer(this, &IDBTransaction::onCompleteTimerFired) - , m_onTimeoutTimer(this, &IDBTransaction::onTimeoutTimerFired) + , m_finished(false) { + ASSERT(m_backend); IDBPendingTransactionMonitor::addPendingTransaction(m_backend.get()); } @@ -59,19 +62,29 @@ IDBTransaction::~IDBTransaction() { } +IDBTransactionBackendInterface* IDBTransaction::backend() const +{ + return m_backend.get(); +} + +bool IDBTransaction::finished() const +{ + return m_finished; +} + unsigned short IDBTransaction::mode() const { return m_mode; } -IDBDatabase* IDBTransaction::db() +IDBDatabase* IDBTransaction::db() const { return m_database.get(); } PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, ExceptionCode& ec) { - if (!m_backend) { + if (m_finished) { ec = IDBDatabaseException::NOT_ALLOWED_ERR; return 0; } @@ -80,94 +93,96 @@ PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, Excep ASSERT(ec); return 0; } - RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, m_backend.get()); + RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, this); return objectStore.release(); } void IDBTransaction::abort() { + RefPtr<IDBTransaction> selfRef = this; if (m_backend) m_backend->abort(); } -ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const -{ - return ActiveDOMObject::scriptExecutionContext(); -} - void IDBTransaction::onAbort() { - ASSERT(!m_onAbortTimer.isActive()); - ASSERT(!m_onCompleteTimer.isActive()); - ASSERT(!m_onTimeoutTimer.isActive()); - m_selfRef = this; - m_onAbortTimer.startOneShot(0); - m_backend.clear(); // Release the backend as it holds a (circular) reference back to us. + enqueueEvent(IDBAbortEvent::create(IDBAny::create(this))); } void IDBTransaction::onComplete() { - ASSERT(!m_onAbortTimer.isActive()); - ASSERT(!m_onCompleteTimer.isActive()); - ASSERT(!m_onTimeoutTimer.isActive()); - m_selfRef = this; - m_onCompleteTimer.startOneShot(0); - m_backend.clear(); // Release the backend as it holds a (circular) reference back to us. + enqueueEvent(IDBCompleteEvent::create(IDBAny::create(this))); } -void IDBTransaction::onTimeout() +bool IDBTransaction::hasPendingActivity() const { - ASSERT(!m_onAbortTimer.isActive()); - ASSERT(!m_onCompleteTimer.isActive()); - ASSERT(!m_onTimeoutTimer.isActive()); - m_selfRef = this; - m_onTimeoutTimer.startOneShot(0); - m_backend.clear(); // Release the backend as it holds a (circular) reference back to us. + // FIXME: In an ideal world, we should return true as long as anyone has a or can + // get a handle to us or any child request object and any of those have + // event listeners. This is in order to handle user generated events properly. + return !m_finished || ActiveDOMObject::hasPendingActivity(); } -bool IDBTransaction::canSuspend() const +ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const { - // We may be in the middle of a transaction so we cannot suspend our object. - // Instead, we simply don't allow the owner page to go into the back/forward cache. - return false; + return ActiveDOMObject::scriptExecutionContext(); } -void IDBTransaction::stop() +bool IDBTransaction::dispatchEvent(PassRefPtr<Event> event) { - if (m_backend) - m_backend->abort(); + ASSERT(!m_finished); + ASSERT(scriptExecutionContext()); + ASSERT(event->target() == this); + ASSERT(!m_finished); + m_finished = true; + + Vector<RefPtr<EventTarget> > targets; + targets.append(this); + targets.append(db()); + + ASSERT(event->isIDBAbortEvent() || event->isIDBCompleteEvent()); + return static_cast<IDBEvent*>(event.get())->dispatch(targets); } -EventTargetData* IDBTransaction::eventTargetData() +bool IDBTransaction::canSuspend() const { - return &m_eventTargetData; + // FIXME: Technically we can suspend before the first request is schedule + // and after the complete/abort event is enqueued. + return m_finished; } -EventTargetData* IDBTransaction::ensureEventTargetData() +void IDBTransaction::contextDestroyed() { - return &m_eventTargetData; + ActiveDOMObject::contextDestroyed(); + + // Must happen in contextDestroyed since it can result in ActiveDOMObjects being destructed + // (and contextDestroyed is the only one resilient against this). + RefPtr<IDBTransaction> selfRef = this; + if (m_backend) + m_backend->abort(); + + m_finished = true; } -void IDBTransaction::onAbortTimerFired(Timer<IDBTransaction>* transaction) +void IDBTransaction::enqueueEvent(PassRefPtr<Event> event) { - ASSERT(m_selfRef); - RefPtr<IDBTransaction> selfRef = m_selfRef.release(); - dispatchEvent(IDBAbortEvent::create()); + ASSERT(!m_finished); + if (!scriptExecutionContext()) + return; + + ASSERT(scriptExecutionContext()->isDocument()); + EventQueue* eventQueue = static_cast<Document*>(scriptExecutionContext())->eventQueue(); + event->setTarget(this); + eventQueue->enqueueEvent(event); } -void IDBTransaction::onCompleteTimerFired(Timer<IDBTransaction>* transaction) +EventTargetData* IDBTransaction::eventTargetData() { - ASSERT(m_selfRef); - RefPtr<IDBTransaction> selfRef = m_selfRef.release(); - dispatchEvent(IDBCompleteEvent::create()); + return &m_eventTargetData; } - -void IDBTransaction::onTimeoutTimerFired(Timer<IDBTransaction>* transaction) +EventTargetData* IDBTransaction::ensureEventTargetData() { - ASSERT(m_selfRef); - RefPtr<IDBTransaction> selfRef = m_selfRef.release(); - dispatchEvent(IDBTimeoutEvent::create()); + return &m_eventTargetData; } } |