IndexedDB 2.0: Encapsulate cursor iteration parameters for easy future expansion.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBTransaction.cpp
1 /*
2  * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "IDBTransaction.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMError.h"
32 #include "DOMStringList.h"
33 #include "DOMWindow.h"
34 #include "Event.h"
35 #include "EventNames.h"
36 #include "EventQueue.h"
37 #include "IDBCursorWithValue.h"
38 #include "IDBDatabase.h"
39 #include "IDBDatabaseException.h"
40 #include "IDBError.h"
41 #include "IDBEventDispatcher.h"
42 #include "IDBGetRecordData.h"
43 #include "IDBIndex.h"
44 #include "IDBIterateCursorData.h"
45 #include "IDBKeyData.h"
46 #include "IDBKeyRangeData.h"
47 #include "IDBObjectStore.h"
48 #include "IDBOpenDBRequest.h"
49 #include "IDBRequest.h"
50 #include "IDBResultData.h"
51 #include "IDBValue.h"
52 #include "JSDOMWindowBase.h"
53 #include "Logging.h"
54 #include "ScriptExecutionContext.h"
55 #include "ScriptState.h"
56 #include "TransactionOperation.h"
57 #include <wtf/NeverDestroyed.h>
58
59 using namespace JSC;
60
61 namespace WebCore {
62
63 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
64 {
65     return adoptRef(*new IDBTransaction(database, info, nullptr));
66 }
67
68 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest& request)
69 {
70     return adoptRef(*new IDBTransaction(database, info, &request));
71 }
72
73 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
74     : IDBActiveDOMObject(database.scriptExecutionContext())
75     , m_database(database)
76     , m_info(info)
77     , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
78     , m_openDBRequest(request)
79
80 {
81     LOG(IndexedDB, "IDBTransaction::IDBTransaction - %s", m_info.loggingString().utf8().data());
82     ASSERT(currentThread() == m_database->originThreadID());
83
84     if (m_info.mode() == IDBTransactionMode::Versionchange) {
85         ASSERT(m_openDBRequest);
86         m_openDBRequest->setVersionChangeTransaction(*this);
87         m_startedOnServer = true;
88     } else {
89         activate();
90
91         auto* context = scriptExecutionContext();
92         ASSERT(context);
93
94         RefPtr<IDBTransaction> self;
95         JSC::VM& vm = context->vm();
96         vm.whenIdle([self, this]() {
97             deactivate();
98         });
99
100         establishOnServer();
101     }
102
103     suspendIfNeeded();
104 }
105
106 IDBTransaction::~IDBTransaction()
107 {
108     ASSERT(currentThread() == m_database->originThreadID());
109 }
110
111 IDBClient::IDBConnectionProxy& IDBTransaction::connectionProxy()
112 {
113     return m_database->connectionProxy();
114 }
115
116 Ref<DOMStringList> IDBTransaction::objectStoreNames() const
117 {
118     ASSERT(currentThread() == m_database->originThreadID());
119
120     const Vector<String> names = isVersionChange() ? m_database->info().objectStoreNames() : m_info.objectStores();
121
122     Ref<DOMStringList> objectStoreNames = DOMStringList::create();
123     for (auto& name : names)
124         objectStoreNames->append(name);
125
126     objectStoreNames->sort();
127     return objectStoreNames;
128 }
129
130 IDBDatabase* IDBTransaction::db()
131 {
132     ASSERT(currentThread() == m_database->originThreadID());
133     return m_database.ptr();
134 }
135
136 DOMError* IDBTransaction::error() const
137 {
138     ASSERT(currentThread() == m_database->originThreadID());
139     return m_domError.get();
140 }
141
142 ExceptionOr<Ref<IDBObjectStore>> IDBTransaction::objectStore(const String& objectStoreName)
143 {
144     LOG(IndexedDB, "IDBTransaction::objectStore");
145     ASSERT(currentThread() == m_database->originThreadID());
146
147     if (!scriptExecutionContext())
148         return Exception { IDBDatabaseException::InvalidStateError };
149
150     if (isFinishedOrFinishing())
151         return Exception { IDBDatabaseException::InvalidStateError, ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The transaction finished.") };
152
153     Locker<Lock> locker(m_referencedObjectStoreLock);
154
155     auto iterator = m_referencedObjectStores.find(objectStoreName);
156     if (iterator != m_referencedObjectStores.end())
157         return Ref<IDBObjectStore> { *iterator->value };
158
159     bool found = false;
160     for (auto& objectStore : m_info.objectStores()) {
161         if (objectStore == objectStoreName) {
162             found = true;
163             break;
164         }
165     }
166
167     auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
168     if (!info)
169         return Exception { IDBDatabaseException::NotFoundError, ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.") };
170
171     // Version change transactions are scoped to every object store in the database.
172     if (!info || (!found && !isVersionChange()))
173         return Exception { IDBDatabaseException::NotFoundError, ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.") };
174
175     auto objectStore = std::make_unique<IDBObjectStore>(*scriptExecutionContext(), *info, *this);
176     auto* rawObjectStore = objectStore.get();
177     m_referencedObjectStores.set(objectStoreName, WTFMove(objectStore));
178
179     return Ref<IDBObjectStore>(*rawObjectStore);
180 }
181
182
183 void IDBTransaction::abortDueToFailedRequest(DOMError& error)
184 {
185     LOG(IndexedDB, "IDBTransaction::abortDueToFailedRequest");
186     ASSERT(currentThread() == m_database->originThreadID());
187
188     if (isFinishedOrFinishing())
189         return;
190
191     m_domError = &error;
192     internalAbort();
193 }
194
195 void IDBTransaction::transitionedToFinishing(IndexedDB::TransactionState state)
196 {
197     ASSERT(currentThread() == m_database->originThreadID());
198
199     ASSERT(!isFinishedOrFinishing());
200     m_state = state;
201     ASSERT(isFinishedOrFinishing());
202 }
203
204 ExceptionOr<void> IDBTransaction::abort()
205 {
206     LOG(IndexedDB, "IDBTransaction::abort");
207     ASSERT(currentThread() == m_database->originThreadID());
208
209     if (isFinishedOrFinishing())
210         return Exception { IDBDatabaseException::InvalidStateError, ASCIILiteral("Failed to execute 'abort' on 'IDBTransaction': The transaction is inactive or finished.") };
211
212     internalAbort();
213
214     return { };
215 }
216
217 void IDBTransaction::internalAbort()
218 {
219     LOG(IndexedDB, "IDBTransaction::internalAbort");
220     ASSERT(currentThread() == m_database->originThreadID());
221     ASSERT(!isFinishedOrFinishing());
222
223     m_database->willAbortTransaction(*this);
224
225     if (isVersionChange()) {
226         Locker<Lock> locker(m_referencedObjectStoreLock);
227
228         auto& info = m_database->info();
229         for (auto& iterator : m_deletedObjectStores) {
230             if (info.infoForExistingObjectStore(iterator.key)) {
231                 auto name = iterator.value->info().name();
232                 m_referencedObjectStores.set(name, WTFMove(iterator.value));
233             }
234         }
235
236         for (auto& objectStore : m_referencedObjectStores.values())
237             objectStore->rollbackForVersionChangeAbort();
238     }
239
240     transitionedToFinishing(IndexedDB::TransactionState::Aborting);
241     
242     m_abortQueue.swap(m_transactionOperationQueue);
243
244     scheduleOperation(IDBClient::createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServerAndCancelRequests));
245 }
246
247 void IDBTransaction::abortOnServerAndCancelRequests(IDBClient::TransactionOperation& operation)
248 {
249     LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
250     ASSERT(currentThread() == m_database->originThreadID());
251     ASSERT(m_transactionOperationQueue.isEmpty());
252
253     m_database->connectionProxy().abortTransaction(*this);
254
255     ASSERT(m_transactionOperationMap.contains(operation.identifier()));
256     m_transactionOperationMap.remove(operation.identifier());
257
258     IDBError error(IDBDatabaseException::AbortError);
259     for (auto& operation : m_abortQueue)
260         operation->completed(IDBResultData::error(operation->identifier(), error));
261
262     // Since we're aborting, it should be impossible to have queued any further operations.
263     ASSERT(m_transactionOperationQueue.isEmpty());
264 }
265
266 const char* IDBTransaction::activeDOMObjectName() const
267 {
268     ASSERT(currentThread() == m_database->originThreadID());
269     return "IDBTransaction";
270 }
271
272 bool IDBTransaction::canSuspendForDocumentSuspension() const
273 {
274     ASSERT(currentThread() == m_database->originThreadID());
275     return false;
276 }
277
278 bool IDBTransaction::hasPendingActivity() const
279 {
280     ASSERT(currentThread() == m_database->originThreadID() || mayBeGCThread());
281     return !m_contextStopped && m_state != IndexedDB::TransactionState::Finished;
282 }
283
284 void IDBTransaction::stop()
285 {
286     LOG(IndexedDB, "IDBTransaction::stop - %s", m_info.loggingString().utf8().data());
287     ASSERT(currentThread() == m_database->originThreadID());
288
289     // IDBDatabase::stop() calls IDBTransaction::stop() for each of its active transactions.
290     // Since the order of calling ActiveDOMObject::stop() is random, we might already have been stopped.
291     if (m_contextStopped)
292         return;
293
294     removeAllEventListeners();
295
296     m_contextStopped = true;
297
298     if (isFinishedOrFinishing())
299         return;
300
301     internalAbort();
302 }
303
304 bool IDBTransaction::isActive() const
305 {
306     ASSERT(currentThread() == m_database->originThreadID());
307     return m_state == IndexedDB::TransactionState::Active;
308 }
309
310 bool IDBTransaction::isFinishedOrFinishing() const
311 {
312     ASSERT(currentThread() == m_database->originThreadID());
313
314     return m_state == IndexedDB::TransactionState::Committing
315         || m_state == IndexedDB::TransactionState::Aborting
316         || m_state == IndexedDB::TransactionState::Finished;
317 }
318
319 void IDBTransaction::addRequest(IDBRequest& request)
320 {
321     ASSERT(currentThread() == m_database->originThreadID());
322     m_openRequests.add(&request);
323 }
324
325 void IDBTransaction::removeRequest(IDBRequest& request)
326 {
327     ASSERT(currentThread() == m_database->originThreadID());
328     ASSERT(m_openRequests.contains(&request));
329     m_openRequests.remove(&request);
330 }
331
332 void IDBTransaction::scheduleOperation(RefPtr<IDBClient::TransactionOperation>&& operation)
333 {
334     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
335     ASSERT(currentThread() == m_database->originThreadID());
336
337     m_transactionOperationQueue.append(operation);
338     m_transactionOperationMap.set(operation->identifier(), WTFMove(operation));
339
340     scheduleOperationTimer();
341 }
342
343 void IDBTransaction::scheduleOperationTimer()
344 {
345     ASSERT(currentThread() == m_database->originThreadID());
346
347     if (!m_operationTimer.isActive())
348         m_operationTimer.startOneShot(0);
349 }
350
351 void IDBTransaction::operationTimerFired()
352 {
353     LOG(IndexedDB, "IDBTransaction::operationTimerFired (%p)", this);
354     ASSERT(currentThread() == m_database->originThreadID());
355
356     if (!m_startedOnServer)
357         return;
358
359     if (!m_transactionOperationQueue.isEmpty()) {
360         auto operation = m_transactionOperationQueue.takeFirst();
361         operation->perform();
362
363         return;
364     }
365
366     if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
367         return;
368
369     if (!isFinishedOrFinishing())
370         commit();
371 }
372
373 void IDBTransaction::commit()
374 {
375     LOG(IndexedDB, "IDBTransaction::commit");
376     ASSERT(currentThread() == m_database->originThreadID());
377     ASSERT(!isFinishedOrFinishing());
378
379     transitionedToFinishing(IndexedDB::TransactionState::Committing);
380     m_database->willCommitTransaction(*this);
381
382     scheduleOperation(IDBClient::createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer));
383 }
384
385 void IDBTransaction::commitOnServer(IDBClient::TransactionOperation& operation)
386 {
387     LOG(IndexedDB, "IDBTransaction::commitOnServer");
388     ASSERT(currentThread() == m_database->originThreadID());
389
390     m_database->connectionProxy().commitTransaction(*this);
391
392     ASSERT(m_transactionOperationMap.contains(operation.identifier()));
393     m_transactionOperationMap.remove(operation.identifier());
394 }
395
396 void IDBTransaction::finishAbortOrCommit()
397 {
398     ASSERT(m_state != IndexedDB::TransactionState::Finished);
399     ASSERT(currentThread() == m_database->originThreadID());
400
401     m_state = IndexedDB::TransactionState::Finished;
402 }
403
404 void IDBTransaction::didStart(const IDBError& error)
405 {
406     LOG(IndexedDB, "IDBTransaction::didStart");
407     ASSERT(currentThread() == m_database->originThreadID());
408
409     m_database->didStartTransaction(*this);
410
411     m_startedOnServer = true;
412
413     // It's possible the transaction failed to start on the server.
414     // That equates to an abort.
415     if (!error.isNull()) {
416         didAbort(error);
417         return;
418     }
419
420     scheduleOperationTimer();
421 }
422
423 void IDBTransaction::notifyDidAbort(const IDBError& error)
424 {
425     ASSERT(currentThread() == m_database->originThreadID());
426
427     m_database->didAbortTransaction(*this);
428     m_idbError = error;
429     fireOnAbort();
430
431     if (isVersionChange()) {
432         ASSERT(m_openDBRequest);
433         m_openDBRequest->fireErrorAfterVersionChangeCompletion();
434     }
435 }
436
437 void IDBTransaction::didAbort(const IDBError& error)
438 {
439     LOG(IndexedDB, "IDBTransaction::didAbort");
440     ASSERT(currentThread() == m_database->originThreadID());
441
442     if (m_state == IndexedDB::TransactionState::Finished)
443         return;
444
445     notifyDidAbort(error);
446
447     finishAbortOrCommit();
448 }
449
450 void IDBTransaction::didCommit(const IDBError& error)
451 {
452     LOG(IndexedDB, "IDBTransaction::didCommit");
453     ASSERT(currentThread() == m_database->originThreadID());
454     ASSERT(m_state == IndexedDB::TransactionState::Committing);
455
456     if (error.isNull()) {
457         m_database->didCommitTransaction(*this);
458         fireOnComplete();
459     } else {
460         m_database->willAbortTransaction(*this);
461         notifyDidAbort(error);
462     }
463
464     finishAbortOrCommit();
465 }
466
467 void IDBTransaction::fireOnComplete()
468 {
469     LOG(IndexedDB, "IDBTransaction::fireOnComplete");
470     ASSERT(currentThread() == m_database->originThreadID());
471     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
472 }
473
474 void IDBTransaction::fireOnAbort()
475 {
476     LOG(IndexedDB, "IDBTransaction::fireOnAbort");
477     ASSERT(currentThread() == m_database->originThreadID());
478     enqueueEvent(Event::create(eventNames().abortEvent, true, false));
479 }
480
481 void IDBTransaction::enqueueEvent(Ref<Event>&& event)
482 {
483     ASSERT(m_state != IndexedDB::TransactionState::Finished);
484     ASSERT(currentThread() == m_database->originThreadID());
485
486     if (!scriptExecutionContext() || m_contextStopped)
487         return;
488
489     event->setTarget(this);
490     scriptExecutionContext()->eventQueue().enqueueEvent(WTFMove(event));
491 }
492
493 bool IDBTransaction::dispatchEvent(Event& event)
494 {
495     LOG(IndexedDB, "IDBTransaction::dispatchEvent");
496
497     ASSERT(currentThread() == m_database->originThreadID());
498     ASSERT(scriptExecutionContext());
499     ASSERT(!m_contextStopped);
500     ASSERT(event.target() == this);
501     ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
502
503     Vector<RefPtr<EventTarget>> targets;
504     targets.append(this);
505     targets.append(db());
506
507     bool result = IDBEventDispatcher::dispatch(event, targets);
508
509     if (isVersionChange()) {
510         ASSERT(m_openDBRequest);
511         m_openDBRequest->versionChangeTransactionDidFinish();
512
513         if (event.type() == eventNames().completeEvent) {
514             if (m_database->isClosingOrClosed())
515                 m_openDBRequest->fireErrorAfterVersionChangeCompletion();
516             else
517                 m_openDBRequest->fireSuccessAfterVersionChangeCommit();
518         }
519
520         m_openDBRequest = nullptr;
521     }
522
523     return result;
524 }
525
526 Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
527 {
528     LOG(IndexedDB, "IDBTransaction::createObjectStore");
529     ASSERT(isVersionChange());
530     ASSERT(scriptExecutionContext());
531     ASSERT(currentThread() == m_database->originThreadID());
532
533     Locker<Lock> locker(m_referencedObjectStoreLock);
534
535     auto objectStore = std::make_unique<IDBObjectStore>(*scriptExecutionContext(), info, *this);
536     auto* rawObjectStore = objectStore.get();
537     m_referencedObjectStores.set(info.name(), WTFMove(objectStore));
538
539     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info));
540
541     return *rawObjectStore;
542 }
543
544 void IDBTransaction::createObjectStoreOnServer(IDBClient::TransactionOperation& operation, const IDBObjectStoreInfo& info)
545 {
546     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
547     ASSERT(currentThread() == m_database->originThreadID());
548     ASSERT(isVersionChange());
549
550     m_database->connectionProxy().createObjectStore(operation, info);
551 }
552
553 void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
554 {
555     LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
556     ASSERT(currentThread() == m_database->originThreadID());
557     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
558 }
559
560 void IDBTransaction::renameObjectStore(IDBObjectStore& objectStore, const String& newName)
561 {
562     LOG(IndexedDB, "IDBTransaction::renameObjectStore");
563
564     Locker<Lock> locker(m_referencedObjectStoreLock);
565
566     ASSERT(isVersionChange());
567     ASSERT(scriptExecutionContext());
568     ASSERT(currentThread() == m_database->originThreadID());
569
570     ASSERT(m_referencedObjectStores.contains(objectStore.info().name()));
571     ASSERT(!m_referencedObjectStores.contains(newName));
572     ASSERT(m_referencedObjectStores.get(objectStore.info().name()) == &objectStore);
573
574     uint64_t objectStoreIdentifier = objectStore.info().identifier();
575     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didRenameObjectStoreOnServer, &IDBTransaction::renameObjectStoreOnServer, objectStoreIdentifier, newName));
576
577     m_referencedObjectStores.set(newName, m_referencedObjectStores.take(objectStore.info().name()));
578 }
579
580 void IDBTransaction::renameObjectStoreOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& newName)
581 {
582     LOG(IndexedDB, "IDBTransaction::renameObjectStoreOnServer");
583     ASSERT(currentThread() == m_database->originThreadID());
584     ASSERT(isVersionChange());
585
586     m_database->connectionProxy().renameObjectStore(operation, objectStoreIdentifier, newName);
587 }
588
589 void IDBTransaction::didRenameObjectStoreOnServer(const IDBResultData& resultData)
590 {
591     LOG(IndexedDB, "IDBTransaction::didRenameObjectStoreOnServer");
592     ASSERT(currentThread() == m_database->originThreadID());
593     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::RenameObjectStoreSuccess || resultData.type() == IDBResultType::Error);
594 }
595
596 std::unique_ptr<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
597 {
598     LOG(IndexedDB, "IDBTransaction::createIndex");
599     ASSERT(isVersionChange());
600     ASSERT(currentThread() == m_database->originThreadID());
601
602     if (!scriptExecutionContext())
603         return nullptr;
604
605     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info));
606
607     return std::make_unique<IDBIndex>(*scriptExecutionContext(), info, objectStore);
608 }
609
610 void IDBTransaction::createIndexOnServer(IDBClient::TransactionOperation& operation, const IDBIndexInfo& info)
611 {
612     LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
613     ASSERT(currentThread() == m_database->originThreadID());
614     ASSERT(isVersionChange());
615
616     m_database->connectionProxy().createIndex(operation, info);
617 }
618
619 void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
620 {
621     LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
622     ASSERT(currentThread() == m_database->originThreadID());
623
624     if (resultData.type() == IDBResultType::CreateIndexSuccess)
625         return;
626
627     ASSERT(resultData.type() == IDBResultType::Error);
628
629     // This operation might have failed because the transaction is already aborting.
630     if (m_state == IndexedDB::TransactionState::Aborting)
631         return;
632
633     // Otherwise, failure to create an index forced abortion of the transaction.
634     abortDueToFailedRequest(DOMError::create(IDBDatabaseException::getErrorName(resultData.error().code()), resultData.error().message()));
635 }
636
637 void IDBTransaction::renameIndex(IDBIndex& index, const String& newName)
638 {
639     LOG(IndexedDB, "IDBTransaction::renameIndex");
640     Locker<Lock> locker(m_referencedObjectStoreLock);
641
642     ASSERT(isVersionChange());
643     ASSERT(scriptExecutionContext());
644     ASSERT(currentThread() == m_database->originThreadID());
645
646     ASSERT(m_referencedObjectStores.contains(index.objectStore().info().name()));
647     ASSERT(m_referencedObjectStores.get(index.objectStore().info().name()) == &index.objectStore());
648
649     index.objectStore().renameReferencedIndex(index, newName);
650
651     uint64_t objectStoreIdentifier = index.objectStore().info().identifier();
652     uint64_t indexIdentifier = index.info().identifier();
653     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didRenameIndexOnServer, &IDBTransaction::renameIndexOnServer, objectStoreIdentifier, indexIdentifier, newName));
654 }
655
656 void IDBTransaction::renameIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const uint64_t& indexIdentifier, const String& newName)
657 {
658     LOG(IndexedDB, "IDBTransaction::renameIndexOnServer");
659     ASSERT(currentThread() == m_database->originThreadID());
660     ASSERT(isVersionChange());
661
662     m_database->connectionProxy().renameIndex(operation, objectStoreIdentifier, indexIdentifier, newName);
663 }
664
665 void IDBTransaction::didRenameIndexOnServer(const IDBResultData& resultData)
666 {
667     LOG(IndexedDB, "IDBTransaction::didRenameIndexOnServer");
668     ASSERT(currentThread() == m_database->originThreadID());
669     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::RenameIndexSuccess || resultData.type() == IDBResultType::Error);
670 }
671
672 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ExecState& state, IDBObjectStore& objectStore, const IDBCursorInfo& info)
673 {
674     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
675     ASSERT(currentThread() == m_database->originThreadID());
676
677     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
678         return doRequestOpenCursor(state, IDBCursor::create(*this, objectStore, info));
679
680     return doRequestOpenCursor(state, IDBCursorWithValue::create(*this, objectStore, info));
681 }
682
683 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ExecState& state, IDBIndex& index, const IDBCursorInfo& info)
684 {
685     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
686     ASSERT(currentThread() == m_database->originThreadID());
687
688     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
689         return doRequestOpenCursor(state, IDBCursor::create(*this, index, info));
690
691     return doRequestOpenCursor(state, IDBCursorWithValue::create(*this, index, info));
692 }
693
694 Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ExecState& state, Ref<IDBCursor>&& cursor)
695 {
696     ASSERT(isActive());
697     ASSERT(currentThread() == m_database->originThreadID());
698
699     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
700
701     auto request = IDBRequest::create(*scriptExecutionContext(), cursor.get(), *this);
702     addRequest(request.get());
703
704     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info()));
705
706     return request;
707 }
708
709 void IDBTransaction::openCursorOnServer(IDBClient::TransactionOperation& operation, const IDBCursorInfo& info)
710 {
711     LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
712     ASSERT(currentThread() == m_database->originThreadID());
713
714     m_database->connectionProxy().openCursor(operation, info);
715 }
716
717 void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
718 {
719     LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
720     ASSERT(currentThread() == m_database->originThreadID());
721
722     request.didOpenOrIterateCursor(resultData);
723 }
724
725 void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBIterateCursorData& data)
726 {
727     LOG(IndexedDB, "IDBTransaction::iterateCursor");
728     ASSERT(isActive());
729     ASSERT(cursor.request());
730     ASSERT(currentThread() == m_database->originThreadID());
731
732     addRequest(*cursor.request());
733
734     scheduleOperation(IDBClient::createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, data));
735 }
736
737 // FIXME: changes here
738 void IDBTransaction::iterateCursorOnServer(IDBClient::TransactionOperation& operation, const IDBIterateCursorData& data)
739 {
740     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
741     ASSERT(currentThread() == m_database->originThreadID());
742
743     m_database->connectionProxy().iterateCursor(operation, data);
744 }
745
746 void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
747 {
748     LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
749     ASSERT(currentThread() == m_database->originThreadID());
750
751     request.didOpenOrIterateCursor(resultData);
752 }
753
754 Ref<IDBRequest> IDBTransaction::requestGetAllObjectStoreRecords(JSC::ExecState& state, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData, IndexedDB::GetAllType getAllType, Optional<uint32_t> count)
755 {
756     LOG(IndexedDB, "IDBTransaction::requestGetAllObjectStoreRecords");
757     ASSERT(isActive());
758     ASSERT(currentThread() == m_database->originThreadID());
759
760     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
761
762     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
763     addRequest(request.get());
764
765     IDBGetAllRecordsData getAllRecordsData { keyRangeData, getAllType, count, objectStore.info().identifier(), 0 };
766
767     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetAllRecordsOnServer, &IDBTransaction::getAllRecordsOnServer, getAllRecordsData));
768
769     return request;
770 }
771
772 Ref<IDBRequest> IDBTransaction::requestGetAllIndexRecords(JSC::ExecState& state, IDBIndex& index, const IDBKeyRangeData& keyRangeData, IndexedDB::GetAllType getAllType, Optional<uint32_t> count)
773 {
774     LOG(IndexedDB, "IDBTransaction::requestGetAllIndexRecords");
775     ASSERT(isActive());
776     ASSERT(currentThread() == m_database->originThreadID());
777
778     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
779
780     auto request = IDBRequest::create(*scriptExecutionContext(), index, *this);
781     addRequest(request.get());
782
783     IDBGetAllRecordsData getAllRecordsData { keyRangeData, getAllType, count, index.objectStore().info().identifier(), index.info().identifier() };
784
785     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetAllRecordsOnServer, &IDBTransaction::getAllRecordsOnServer, getAllRecordsData));
786
787     return request;
788 }
789
790 void IDBTransaction::getAllRecordsOnServer(IDBClient::TransactionOperation& operation, const IDBGetAllRecordsData& getAllRecordsData)
791 {
792     LOG(IndexedDB, "IDBTransaction::getAllRecordsOnServer");
793     ASSERT(currentThread() == m_database->originThreadID());
794
795     m_database->connectionProxy().getAllRecords(operation, getAllRecordsData);
796 }
797
798 void IDBTransaction::didGetAllRecordsOnServer(IDBRequest& request, const IDBResultData& resultData)
799 {
800     LOG(IndexedDB, "IDBTransaction::didGetAllRecordsOnServer");
801     ASSERT(currentThread() == m_database->originThreadID());
802
803     if (resultData.type() == IDBResultType::Error) {
804         request.requestCompleted(resultData);
805         return;
806     }
807
808     ASSERT(resultData.type() == IDBResultType::GetAllRecordsSuccess);
809
810     auto& getAllResult = resultData.getAllResult();
811     switch (getAllResult.type()) {
812     case IndexedDB::GetAllType::Keys:
813         request.setResult(getAllResult.keys());
814         break;
815     case IndexedDB::GetAllType::Values:
816         request.setResult(getAllResult.values());
817         break;
818     }
819
820     request.requestCompleted(resultData);
821 }
822
823 Ref<IDBRequest> IDBTransaction::requestGetRecord(ExecState& state, IDBObjectStore& objectStore, const IDBGetRecordData& getRecordData)
824 {
825     LOG(IndexedDB, "IDBTransaction::requestGetRecord");
826     ASSERT(isActive());
827     ASSERT(!getRecordData.keyRangeData.isNull);
828     ASSERT(currentThread() == m_database->originThreadID());
829
830     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
831
832     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
833     addRequest(request.get());
834
835     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, getRecordData));
836
837     return request;
838 }
839
840 Ref<IDBRequest> IDBTransaction::requestGetValue(ExecState& state, IDBIndex& index, const IDBKeyRangeData& range)
841 {
842     LOG(IndexedDB, "IDBTransaction::requestGetValue");
843     ASSERT(currentThread() == m_database->originThreadID());
844
845     return requestIndexRecord(state, index, IndexedDB::IndexRecordType::Value, range);
846 }
847
848 Ref<IDBRequest> IDBTransaction::requestGetKey(ExecState& state, IDBIndex& index, const IDBKeyRangeData& range)
849 {
850     LOG(IndexedDB, "IDBTransaction::requestGetValue");
851     ASSERT(currentThread() == m_database->originThreadID());
852
853     return requestIndexRecord(state, index, IndexedDB::IndexRecordType::Key, range);
854 }
855
856 Ref<IDBRequest> IDBTransaction::requestIndexRecord(ExecState& state, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData& range)
857 {
858     LOG(IndexedDB, "IDBTransaction::requestGetValue");
859     ASSERT(isActive());
860     ASSERT(!range.isNull);
861     ASSERT(currentThread() == m_database->originThreadID());
862
863     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
864
865     auto request = IDBRequest::createIndexGet(*scriptExecutionContext(), index, type, *this);
866     addRequest(request.get());
867
868     IDBGetRecordData getRecordData = { range };
869     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, getRecordData));
870
871     return request;
872 }
873
874 void IDBTransaction::getRecordOnServer(IDBClient::TransactionOperation& operation, const IDBGetRecordData& getRecordData)
875 {
876     LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
877     ASSERT(currentThread() == m_database->originThreadID());
878
879     m_database->connectionProxy().getRecord(operation, getRecordData);
880 }
881
882 void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
883 {
884     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
885     ASSERT(currentThread() == m_database->originThreadID());
886
887     if (resultData.type() == IDBResultType::Error) {
888         request.requestCompleted(resultData);
889         return;
890     }
891
892     ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
893
894     const IDBGetResult& result = resultData.getResult();
895
896     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
897         if (!result.keyData().isNull())
898             request.setResult(result.keyData());
899         else
900             request.setResultToUndefined();
901     } else {
902         if (resultData.getResult().value().data().data())
903             request.setResultToStructuredClone(resultData.getResult().value());
904         else
905             request.setResultToUndefined();
906     }
907
908     request.requestCompleted(resultData);
909 }
910
911 Ref<IDBRequest> IDBTransaction::requestCount(ExecState& state, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
912 {
913     LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
914     ASSERT(isActive());
915     ASSERT(!range.isNull);
916     ASSERT(currentThread() == m_database->originThreadID());
917
918     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
919
920     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
921     addRequest(request.get());
922
923     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
924
925     return request;
926 }
927
928 Ref<IDBRequest> IDBTransaction::requestCount(ExecState& state, IDBIndex& index, const IDBKeyRangeData& range)
929 {
930     LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
931     ASSERT(isActive());
932     ASSERT(!range.isNull);
933     ASSERT(currentThread() == m_database->originThreadID());
934
935     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
936
937     auto request = IDBRequest::create(*scriptExecutionContext(), index, *this);
938     addRequest(request.get());
939
940     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
941
942     return request;
943 }
944
945 void IDBTransaction::getCountOnServer(IDBClient::TransactionOperation& operation, const IDBKeyRangeData& keyRange)
946 {
947     LOG(IndexedDB, "IDBTransaction::getCountOnServer");
948     ASSERT(currentThread() == m_database->originThreadID());
949
950     m_database->connectionProxy().getCount(operation, keyRange);
951 }
952
953 void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
954 {
955     LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
956     ASSERT(currentThread() == m_database->originThreadID());
957
958     request.setResult(resultData.resultInteger());
959     request.requestCompleted(resultData);
960 }
961
962 Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ExecState& state, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
963 {
964     LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
965     ASSERT(isActive());
966     ASSERT(!range.isNull);
967     ASSERT(currentThread() == m_database->originThreadID());
968
969     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
970
971     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
972     addRequest(request.get());
973
974     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
975     return request;
976 }
977
978 void IDBTransaction::deleteRecordOnServer(IDBClient::TransactionOperation& operation, const IDBKeyRangeData& keyRange)
979 {
980     LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
981     ASSERT(currentThread() == m_database->originThreadID());
982
983     m_database->connectionProxy().deleteRecord(operation, keyRange);
984 }
985
986 void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
987 {
988     LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
989     ASSERT(currentThread() == m_database->originThreadID());
990
991     request.setResultToUndefined();
992     request.requestCompleted(resultData);
993 }
994
995 Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ExecState& state, IDBObjectStore& objectStore)
996 {
997     LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
998     ASSERT(isActive());
999     ASSERT(currentThread() == m_database->originThreadID());
1000
1001     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
1002
1003     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
1004     addRequest(request.get());
1005
1006     uint64_t objectStoreIdentifier = objectStore.info().identifier();
1007     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier));
1008
1009     return request;
1010 }
1011
1012 void IDBTransaction::clearObjectStoreOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
1013 {
1014     LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
1015     ASSERT(currentThread() == m_database->originThreadID());
1016
1017     m_database->connectionProxy().clearObjectStore(operation, objectStoreIdentifier);
1018 }
1019
1020 void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
1021 {
1022     LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
1023     ASSERT(currentThread() == m_database->originThreadID());
1024
1025     request.setResultToUndefined();
1026     request.requestCompleted(resultData);
1027 }
1028
1029 Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ExecState& state, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
1030 {
1031     LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
1032     ASSERT(isActive());
1033     ASSERT(!isReadOnly());
1034     ASSERT(objectStore.info().autoIncrement() || key);
1035     ASSERT(currentThread() == m_database->originThreadID());
1036
1037     ASSERT_UNUSED(state, scriptExecutionContext() == scriptExecutionContextFromExecState(&state));
1038
1039     auto request = IDBRequest::create(*scriptExecutionContext(), objectStore, *this);
1040     addRequest(request.get());
1041
1042     scheduleOperation(IDBClient::createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode));
1043
1044     return request;
1045 }
1046
1047 void IDBTransaction::putOrAddOnServer(IDBClient::TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
1048 {
1049     LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
1050     ASSERT(currentThread() == originThreadID());
1051     ASSERT(!isReadOnly());
1052     ASSERT(value);
1053
1054     if (!value->hasBlobURLs()) {
1055         m_database->connectionProxy().putOrAdd(operation, key.get(), *value, overwriteMode);
1056         return;
1057     }
1058
1059     // Due to current limitations on our ability to post tasks back to a worker thread,
1060     // workers currently write blobs to disk synchronously.
1061     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=157958 - Make this asynchronous after refactoring allows it.
1062     if (!isMainThread()) {
1063         auto idbValue = value->writeBlobsToDiskForIndexedDBSynchronously();
1064         if (idbValue.data().data())
1065             m_database->connectionProxy().putOrAdd(operation, key.get(), idbValue, overwriteMode);
1066         else {
1067             // If the IDBValue doesn't have any data, then something went wrong writing the blobs to disk.
1068             // In that case, we cannot successfully store this record, so we callback with an error.
1069             RefPtr<IDBClient::TransactionOperation> protectedOperation(&operation);
1070             auto result = IDBResultData::error(operation.identifier(), { IDBDatabaseException::UnknownError, ASCIILiteral("Error preparing Blob/File data to be stored in object store") });
1071             scriptExecutionContext()->postTask([protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)](ScriptExecutionContext&) {
1072                 protectedOperation->completed(result);
1073             });
1074         }
1075         return;
1076     }
1077
1078     value->writeBlobsToDiskForIndexedDB([protectedThis = makeRef(*this), this, protectedOperation = Ref<IDBClient::TransactionOperation>(operation), keyData = IDBKeyData(key.get()).isolatedCopy(), overwriteMode](const IDBValue& idbValue) mutable {
1079         ASSERT(currentThread() == originThreadID());
1080         ASSERT(isMainThread());
1081         if (idbValue.data().data()) {
1082             m_database->connectionProxy().putOrAdd(protectedOperation.get(), WTFMove(keyData), idbValue, overwriteMode);
1083             return;
1084         }
1085
1086         // If the IDBValue doesn't have any data, then something went wrong writing the blobs to disk.
1087         // In that case, we cannot successfully store this record, so we callback with an error.
1088         auto result = IDBResultData::error(protectedOperation->identifier(), { IDBDatabaseException::UnknownError, ASCIILiteral("Error preparing Blob/File data to be stored in object store") });
1089         callOnMainThread([protectedThis = WTFMove(protectedThis), protectedOperation = WTFMove(protectedOperation), result = WTFMove(result)]() mutable {
1090             protectedOperation->completed(result);
1091         });
1092     });
1093 }
1094
1095 void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
1096 {
1097     LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
1098     ASSERT(currentThread() == m_database->originThreadID());
1099
1100     if (auto* result = resultData.resultKey())
1101         request.setResult(*result);
1102     else
1103         request.setResultToUndefined();
1104     request.requestCompleted(resultData);
1105 }
1106
1107 void IDBTransaction::deleteObjectStore(const String& objectStoreName)
1108 {
1109     LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
1110     ASSERT(currentThread() == m_database->originThreadID());
1111     ASSERT(isVersionChange());
1112
1113     Locker<Lock> locker(m_referencedObjectStoreLock);
1114
1115     if (auto objectStore = m_referencedObjectStores.take(objectStoreName)) {
1116         objectStore->markAsDeleted();
1117         auto identifier = objectStore->info().identifier();
1118         m_deletedObjectStores.set(identifier, WTFMove(objectStore));
1119     }
1120
1121     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName));
1122 }
1123
1124 void IDBTransaction::deleteObjectStoreOnServer(IDBClient::TransactionOperation& operation, const String& objectStoreName)
1125 {
1126     LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
1127     ASSERT(isVersionChange());
1128     ASSERT(currentThread() == m_database->originThreadID());
1129
1130     m_database->connectionProxy().deleteObjectStore(operation, objectStoreName);
1131 }
1132
1133 void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
1134 {
1135     LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
1136     ASSERT(currentThread() == m_database->originThreadID());
1137     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess || resultData.type() == IDBResultType::Error);
1138 }
1139
1140 void IDBTransaction::deleteIndex(uint64_t objectStoreIdentifier, const String& indexName)
1141 {
1142     LOG(IndexedDB, "IDBTransaction::deleteIndex");
1143     ASSERT(currentThread() == m_database->originThreadID());
1144     ASSERT(isVersionChange());
1145
1146     scheduleOperation(IDBClient::createTransactionOperation(*this, &IDBTransaction::didDeleteIndexOnServer, &IDBTransaction::deleteIndexOnServer, objectStoreIdentifier, indexName));
1147 }
1148
1149 void IDBTransaction::deleteIndexOnServer(IDBClient::TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
1150 {
1151     LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
1152     ASSERT(isVersionChange());
1153     ASSERT(currentThread() == m_database->originThreadID());
1154
1155     m_database->connectionProxy().deleteIndex(operation, objectStoreIdentifier, indexName);
1156 }
1157
1158 void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
1159 {
1160     LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
1161     ASSERT(currentThread() == m_database->originThreadID());
1162     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
1163 }
1164
1165 void IDBTransaction::operationDidComplete(IDBClient::TransactionOperation& operation)
1166 {
1167     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
1168     ASSERT(currentThread() == m_database->originThreadID());
1169     ASSERT(currentThread() == operation.originThreadID());
1170
1171     m_transactionOperationMap.remove(operation.identifier());
1172
1173     scheduleOperationTimer();
1174 }
1175
1176 void IDBTransaction::establishOnServer()
1177 {
1178     LOG(IndexedDB, "IDBTransaction::establishOnServer");
1179     ASSERT(currentThread() == m_database->originThreadID());
1180
1181     m_database->connectionProxy().establishTransaction(*this);
1182 }
1183
1184 void IDBTransaction::activate()
1185 {
1186     ASSERT(currentThread() == m_database->originThreadID());
1187
1188     if (isFinishedOrFinishing())
1189         return;
1190
1191     m_state = IndexedDB::TransactionState::Active;
1192 }
1193
1194 void IDBTransaction::deactivate()
1195 {
1196     ASSERT(currentThread() == m_database->originThreadID());
1197
1198     if (m_state == IndexedDB::TransactionState::Active)
1199         m_state = IndexedDB::TransactionState::Inactive;
1200
1201     scheduleOperationTimer();
1202 }
1203
1204 void IDBTransaction::connectionClosedFromServer(const IDBError& error)
1205 {
1206     LOG(IndexedDB, "IDBTransaction::connectionClosedFromServer - %s", error.message().utf8().data());
1207
1208     m_state = IndexedDB::TransactionState::Aborting;
1209
1210     Vector<RefPtr<IDBClient::TransactionOperation>> operations;
1211     copyValuesToVector(m_transactionOperationMap, operations);
1212
1213     for (auto& operation : operations)
1214         operation->completed(IDBResultData::error(operation->identifier(), error));
1215
1216     connectionProxy().forgetActiveOperations(operations);
1217
1218     m_transactionOperationQueue.clear();
1219     m_abortQueue.clear();
1220     m_transactionOperationMap.clear();
1221
1222     m_idbError = error;
1223     m_domError = error.toDOMError();
1224     fireOnAbort();
1225 }
1226
1227 void IDBTransaction::visitReferencedObjectStores(JSC::SlotVisitor& visitor) const
1228 {
1229     Locker<Lock> locker(m_referencedObjectStoreLock);
1230     for (auto& objectStore : m_referencedObjectStores.values())
1231         visitor.addOpaqueRoot(objectStore.get());
1232     for (auto& objectStore : m_deletedObjectStores.values())
1233         visitor.addOpaqueRoot(objectStore.get());
1234 }
1235
1236 } // namespace WebCore
1237
1238 #endif // ENABLE(INDEXED_DATABASE)