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