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