void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*) { IDB_TRACE("IDBTransactionBackendImpl::taskTimerFired"); ASSERT(!isTaskQueueEmpty()); if (m_state == StartPending) { m_transaction.begin(); m_state = Running; } // The last reference to this object may be released while performing the // tasks. Take take a self reference to keep this object alive so that // the loop termination conditions can be checked. RefPtr<IDBTransactionBackendImpl> protect(this); TaskQueue* taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; while (!taskQueue->isEmpty() && m_state != Finished) { ASSERT(m_state == Running); OwnPtr<Operation> task(taskQueue->takeFirst()); task->perform(this); // Event itself may change which queue should be processed next. taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; } // If there are no pending tasks, we haven't already committed/aborted, // and the front-end requested a commit, it is now safe to do so. if (!hasPendingTasks() && m_state != Finished && m_commitPending) commit(); }
void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendImpl>*) { IDB_TRACE("IDBTransactionBackendImpl::taskEventTimerFired"); ASSERT(m_state == Running); if (!m_pendingEvents && isTaskQueueEmpty()) { // The last task event has completed and the task // queue is empty. Commit the transaction. commit(); return; } // We are still waiting for other events to complete. However, // the task queue is non-empty and the timer is inactive. // We can therfore schedule the timer again. if (!isTaskQueueEmpty() && !m_taskTimer.isActive()) m_taskTimer.startOneShot(0); }
void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*) { IDB_TRACE("IDBTransactionBackendImpl::taskTimerFired"); ASSERT(!isTaskQueueEmpty()); if (m_state == StartPending) { m_transaction->begin(); m_state = Running; } TaskQueue* taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; while (!taskQueue->isEmpty() && m_state != Finished) { ASSERT(m_state == Running); OwnPtr<ScriptExecutionContext::Task> task(taskQueue->takeFirst()); m_pendingEvents++; task->performTask(0); // Event itself may change which queue should be processed next. taskQueue = m_pendingPreemptiveEvents ? &m_preemptiveTaskQueue : &m_taskQueue; } }
void IDBTransactionBackendImpl::commit() { IDB_TRACE("IDBTransactionBackendImpl::commit"); // The last reference to this object may be released while performing the // commit steps below. We therefore take a self reference to keep ourselves // alive while executing this method. RefPtr<IDBTransactionBackendImpl> self(this); ASSERT(m_state == Unused || m_state == Running); ASSERT(isTaskQueueEmpty()); bool unused = m_state == Unused; m_state = Finished; bool committed = unused || m_transaction->commit(); // Backing store resources (held via cursors) must be released before script callbacks // are fired, as the script callbacks may release references and allow the backing store // itself to be released, and order is critical. closeOpenCursors(); m_transaction = 0; // Transactions must also be marked as completed before the front-end is notified, as // the transaction completion unblocks operations like closing connections. if (!unused) m_database->transactionCoordinator()->didFinishTransaction(this); m_database->transactionFinished(this); if (committed) { m_callbacks->onComplete(); m_database->transactionFinishedAndCompleteFired(this); } else { m_callbacks->onAbort(); m_database->transactionFinishedAndAbortFired(this); } m_database = 0; }
bool IDBTransactionBackendImpl::hasPendingTasks() const { return m_pendingPreemptiveEvents || !isTaskQueueEmpty(); }