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