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