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