2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "IDBTransactionImpl.h"
29 #if ENABLE(INDEXED_DATABASE)
32 #include "EventQueue.h"
33 #include "IDBDatabaseImpl.h"
35 #include "IDBEventDispatcher.h"
36 #include "IDBObjectStore.h"
38 #include "ScriptExecutionContext.h"
43 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
45 return adoptRef(*new IDBTransaction(database, info));
48 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info)
49 : WebCore::IDBTransaction(database.scriptExecutionContext())
50 , m_database(database)
52 , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
55 m_activationTimer = std::make_unique<Timer>(*this, &IDBTransaction::activationTimerFired);
56 m_activationTimer->startOneShot(0);
58 if (m_info.mode() == IndexedDB::TransactionMode::VersionChange)
59 m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
62 m_state = IndexedDB::TransactionState::Running;
65 IDBTransaction::~IDBTransaction()
69 const String& IDBTransaction::mode() const
71 switch (m_info.mode()) {
72 case IndexedDB::TransactionMode::ReadOnly:
73 return IDBTransaction::modeReadOnly();
74 case IndexedDB::TransactionMode::ReadWrite:
75 return IDBTransaction::modeReadWrite();
76 case IndexedDB::TransactionMode::VersionChange:
77 return IDBTransaction::modeVersionChange();
80 RELEASE_ASSERT_NOT_REACHED();
83 WebCore::IDBDatabase* IDBTransaction::db()
85 return &m_database.get();
88 RefPtr<DOMError> IDBTransaction::error() const
94 RefPtr<IDBObjectStore> IDBTransaction::objectStore(const String&, ExceptionCode&)
100 void IDBTransaction::abort(ExceptionCode& ec)
102 LOG(IndexedDB, "IDBTransaction::abort");
104 if (isFinishedOrFinishing()) {
105 ec = INVALID_STATE_ERR;
109 m_state = IndexedDB::TransactionState::Aborting;
111 m_database->abortTransaction(*this);
114 const char* IDBTransaction::activeDOMObjectName() const
116 return "IDBTransaction";
119 bool IDBTransaction::canSuspendForPageCache() const
124 bool IDBTransaction::hasPendingActivity() const
126 return m_state != IndexedDB::TransactionState::Finished;
129 bool IDBTransaction::isActive() const
131 return m_state == IndexedDB::TransactionState::Running;
134 bool IDBTransaction::isFinishedOrFinishing() const
136 return m_state == IndexedDB::TransactionState::Committing
137 || m_state == IndexedDB::TransactionState::Aborting
138 || m_state == IndexedDB::TransactionState::Finished;
141 void IDBTransaction::activationTimerFired()
143 scheduleOperationTimer();
144 m_activationTimer = nullptr;
147 void IDBTransaction::scheduleOperationTimer()
149 if (!m_operationTimer.isActive())
150 m_operationTimer.startOneShot(0);
153 void IDBTransaction::operationTimerFired()
155 LOG(IndexedDB, "IDBTransaction::operationTimerFired");
157 if (m_state == IndexedDB::TransactionState::Unstarted)
160 // FIXME: Once transactions can do things, like configure the database or insert data into it,
161 // those operations will be handled here, and will prevent the transaction from committing
162 // as long as outstanding operations exist.
168 void IDBTransaction::commit()
170 LOG(IndexedDB, "IDBTransaction::commit");
172 if (m_state != IndexedDB::TransactionState::Running) {
173 m_state = IndexedDB::TransactionState::Finished;
177 m_state = IndexedDB::TransactionState::Committing;
179 m_database->commitTransaction(*this);
182 void IDBTransaction::didAbort(const IDBError& error)
184 LOG(IndexedDB, "IDBTransaction::didAbort");
186 ASSERT(m_state == IndexedDB::TransactionState::Aborting || m_state == IndexedDB::TransactionState::Running);
188 m_database->didAbortTransaction(*this);
193 m_state = IndexedDB::TransactionState::Finished;
196 void IDBTransaction::didCommit(const IDBError& error)
198 LOG(IndexedDB, "IDBTransaction::didCommit");
200 ASSERT(m_state == IndexedDB::TransactionState::Committing);
202 if (error.isNull()) {
203 m_database->didCommitTransaction(*this);
206 m_database->didAbortTransaction(*this);
211 m_state = IndexedDB::TransactionState::Finished;
214 void IDBTransaction::fireOnComplete()
216 LOG(IndexedDB, "IDBTransaction::fireOnComplete");
217 enqueueEvent(Event::create(eventNames().completeEvent, false, false));
220 void IDBTransaction::fireOnAbort()
222 LOG(IndexedDB, "IDBTransaction::fireOnAbort");
223 enqueueEvent(Event::create(eventNames().abortEvent, true, false));
226 void IDBTransaction::enqueueEvent(Ref<Event> event)
228 ASSERT(m_state != IndexedDB::TransactionState::Finished);
230 if (!scriptExecutionContext())
233 event->setTarget(this);
234 scriptExecutionContext()->eventQueue().enqueueEvent(&event.get());
237 bool IDBTransaction::dispatchEvent(PassRefPtr<Event> event)
239 LOG(IndexedDB, "IDBTransaction::dispatchEvent");
241 ASSERT(scriptExecutionContext());
242 ASSERT(event->target() == this);
243 ASSERT(event->type() == eventNames().completeEvent || event->type() == eventNames().abortEvent);
245 Vector<RefPtr<EventTarget>> targets;
246 targets.append(this);
247 targets.append(db());
249 return IDBEventDispatcher::dispatch(event.get(), targets);
252 } // namespace IDBClient
253 } // namespace WebCore
255 #endif // ENABLE(INDEXED_DATABASE)