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