1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "ActorsChild.h"
10 #include "BackgroundChildImpl.h"
11 #include "IDBDatabase.h"
12 #include "IDBEvents.h"
13 #include "IDBFactory.h"
15 #include "IDBObjectStore.h"
16 #include "IDBRequest.h"
17 #include "IDBTransaction.h"
18 #include "IndexedDatabase.h"
19 #include "IndexedDatabaseInlines.h"
20 #include "IndexedDBCommon.h"
21 #include "js/Array.h" // JS::NewArrayObject, JS::SetArrayLength
22 #include "js/Date.h" // JS::NewDateObject, JS::TimeClip
23 #include "js/PropertyAndElement.h" // JS_DefineElement, JS_DefineProperty
24 #include <mozIRemoteLazyInputStream.h>
25 #include "mozilla/ArrayAlgorithm.h"
26 #include "mozilla/BasicEvents.h"
27 #include "mozilla/CycleCollectedJSRuntime.h"
28 #include "mozilla/Maybe.h"
29 #include "mozilla/ResultExtensions.h"
30 #include "mozilla/dom/BlobImpl.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/Event.h"
33 #include "mozilla/dom/PermissionMessageUtils.h"
34 #include "mozilla/dom/BrowserChild.h"
35 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
36 #include "mozilla/dom/IPCBlobUtils.h"
37 #include "mozilla/dom/WorkerPrivate.h"
38 #include "mozilla/dom/WorkerRunnable.h"
39 #include "mozilla/dom/quota/ResultExtensions.h"
40 #include "mozilla/Encoding.h"
41 #include "mozilla/ipc/BackgroundUtils.h"
42 #include "mozilla/ProfilerLabels.h"
43 #include "mozilla/TaskQueue.h"
45 #include "nsContentUtils.h"
46 #include "nsIAsyncInputStream.h"
47 #include "nsIEventTarget.h"
48 #include "nsIFileStreams.h"
50 #include "nsPIDOMWindow.h"
51 #include "nsThreadUtils.h"
52 #include "nsTraceRefcnt.h"
53 #include "ProfilerHelpers.h"
54 #include "ReportInternalError.h"
55 #include "ThreadLocal.h"
58 # include "IndexedDatabaseManager.h"
61 #define GC_ON_IPC_MESSAGES 0
63 #if defined(DEBUG) || GC_ON_IPC_MESSAGES
65 # include "js/GCAPI.h"
66 # include "nsJSEnvironment.h"
68 # define BUILD_GC_ON_IPC_MESSAGES
70 #endif // DEBUG || GC_ON_IPC_MESSAGES
74 using ipc::PrincipalInfo
;
76 namespace dom::indexedDB
{
78 /*******************************************************************************
80 ******************************************************************************/
82 ThreadLocal::ThreadLocal(const nsID
& aBackgroundChildLoggingId
)
83 : mLoggingInfo(aBackgroundChildLoggingId
, 1, -1, 1),
84 mLoggingIdString(aBackgroundChildLoggingId
) {
85 MOZ_COUNT_CTOR(mozilla::dom::indexedDB::ThreadLocal
);
88 ThreadLocal::~ThreadLocal() {
89 MOZ_COUNT_DTOR(mozilla::dom::indexedDB::ThreadLocal
);
92 /*******************************************************************************
94 ******************************************************************************/
98 void MaybeCollectGarbageOnIPCMessage() {
99 #ifdef BUILD_GC_ON_IPC_MESSAGES
100 static const bool kCollectGarbageOnIPCMessages
=
101 # if GC_ON_IPC_MESSAGES
105 # endif // GC_ON_IPC_MESSAGES
107 if (!kCollectGarbageOnIPCMessages
) {
111 static bool haveWarnedAboutGC
= false;
112 static bool haveWarnedAboutNonMainThread
= false;
114 if (!haveWarnedAboutGC
) {
115 haveWarnedAboutGC
= true;
116 NS_WARNING("IndexedDB child actor GC debugging enabled!");
119 if (!NS_IsMainThread()) {
120 if (!haveWarnedAboutNonMainThread
) {
121 haveWarnedAboutNonMainThread
= true;
122 NS_WARNING("Don't know how to GC on a non-main thread yet.");
127 nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC
);
128 nsJSContext::CycleCollectNow(CCReason::API
);
129 #endif // BUILD_GC_ON_IPC_MESSAGES
132 class MOZ_STACK_CLASS AutoSetCurrentTransaction final
{
133 using BackgroundChildImpl
= mozilla::ipc::BackgroundChildImpl
;
135 Maybe
<IDBTransaction
&> const mTransaction
;
136 Maybe
<IDBTransaction
&> mPreviousTransaction
;
137 ThreadLocal
* mThreadLocal
;
140 AutoSetCurrentTransaction(const AutoSetCurrentTransaction
&) = delete;
141 AutoSetCurrentTransaction(AutoSetCurrentTransaction
&&) = delete;
142 AutoSetCurrentTransaction
& operator=(const AutoSetCurrentTransaction
&) =
144 AutoSetCurrentTransaction
& operator=(AutoSetCurrentTransaction
&&) = delete;
146 explicit AutoSetCurrentTransaction(Maybe
<IDBTransaction
&> aTransaction
)
147 : mTransaction(aTransaction
), mThreadLocal(nullptr) {
149 BackgroundChildImpl::ThreadLocal
* threadLocal
=
150 BackgroundChildImpl::GetThreadLocalForCurrentThread();
151 MOZ_ASSERT(threadLocal
);
153 // Hang onto this for resetting later.
154 mThreadLocal
= threadLocal
->mIndexedDBThreadLocal
.get();
155 MOZ_ASSERT(mThreadLocal
);
157 // Save the current value.
158 mPreviousTransaction
= mThreadLocal
->MaybeCurrentTransactionRef();
160 // Set the new value.
161 mThreadLocal
->SetCurrentTransaction(aTransaction
);
165 ~AutoSetCurrentTransaction() {
166 MOZ_ASSERT_IF(mThreadLocal
, mTransaction
);
167 MOZ_ASSERT_IF(mThreadLocal
,
168 ReferenceEquals(mThreadLocal
->MaybeCurrentTransactionRef(),
173 mThreadLocal
->SetCurrentTransaction(mPreviousTransaction
);
178 template <typename T
>
179 void SetResultAndDispatchSuccessEvent(
180 const NotNull
<RefPtr
<IDBRequest
>>& aRequest
,
181 const SafeRefPtr
<IDBTransaction
>& aTransaction
, T
& aPtr
,
182 RefPtr
<Event
> aEvent
= nullptr);
185 void DispatchSuccessEvent(const NotNull
<RefPtr
<IDBRequest
>>& aRequest
,
186 const SafeRefPtr
<IDBTransaction
>& aTransaction
,
187 const RefPtr
<Event
>& aEvent
);
190 std::enable_if_t
<std::is_same_v
<T
, IDBDatabase
> || std::is_same_v
<T
, IDBCursor
>,
192 GetResult(JSContext
* aCx
, T
* aDOMObject
, JS::MutableHandle
<JS::Value
> aResult
) {
198 const bool ok
= GetOrCreateDOMReflector(aCx
, aDOMObject
, aResult
);
199 if (NS_WARN_IF(!ok
)) {
200 IDB_REPORT_INTERNAL_ERR();
201 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
207 nsresult
GetResult(JSContext
* aCx
, const JS::Handle
<JS::Value
>* aValue
,
208 JS::MutableHandle
<JS::Value
> aResult
) {
209 aResult
.set(*aValue
);
213 nsresult
GetResult(JSContext
* aCx
, const uint64_t* aValue
,
214 JS::MutableHandle
<JS::Value
> aResult
) {
215 aResult
.set(JS::NumberValue(*aValue
));
219 nsresult
GetResult(JSContext
* aCx
, StructuredCloneReadInfoChild
&& aCloneInfo
,
220 JS::MutableHandle
<JS::Value
> aResult
) {
222 IDBObjectStore::DeserializeValue(aCx
, std::move(aCloneInfo
), aResult
);
224 if (NS_WARN_IF(!ok
)) {
225 return NS_ERROR_DOM_DATA_CLONE_ERR
;
231 nsresult
GetResult(JSContext
* aCx
, StructuredCloneReadInfoChild
* aCloneInfo
,
232 JS::MutableHandle
<JS::Value
> aResult
) {
233 return GetResult(aCx
, std::move(*aCloneInfo
), aResult
);
236 nsresult
GetResult(JSContext
* aCx
,
237 nsTArray
<StructuredCloneReadInfoChild
>* aCloneInfos
,
238 JS::MutableHandle
<JS::Value
> aResult
) {
239 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, 0));
240 if (NS_WARN_IF(!array
)) {
241 IDB_REPORT_INTERNAL_ERR();
242 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
245 if (!aCloneInfos
->IsEmpty()) {
246 const uint32_t count
= aCloneInfos
->Length();
248 if (NS_WARN_IF(!JS::SetArrayLength(aCx
, array
, count
))) {
249 IDB_REPORT_INTERNAL_ERR();
250 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
253 for (uint32_t index
= 0; index
< count
; index
++) {
254 auto& cloneInfo
= aCloneInfos
->ElementAt(index
);
256 JS::Rooted
<JS::Value
> value(aCx
);
258 const nsresult rv
= GetResult(aCx
, std::move(cloneInfo
), &value
);
259 if (NS_WARN_IF(NS_FAILED(rv
))) {
264 !JS_DefineElement(aCx
, array
, index
, value
, JSPROP_ENUMERATE
))) {
265 IDB_REPORT_INTERNAL_ERR();
266 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
271 aResult
.setObject(*array
);
275 nsresult
GetResult(JSContext
* aCx
, const Key
* aKey
,
276 JS::MutableHandle
<JS::Value
> aResult
) {
277 const nsresult rv
= aKey
->ToJSVal(aCx
, aResult
);
278 if (NS_WARN_IF(NS_FAILED(rv
))) {
284 nsresult
GetResult(JSContext
* aCx
, const nsTArray
<Key
>* aKeys
,
285 JS::MutableHandle
<JS::Value
> aResult
) {
286 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, 0));
287 if (NS_WARN_IF(!array
)) {
288 IDB_REPORT_INTERNAL_ERR();
289 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
292 if (!aKeys
->IsEmpty()) {
293 const uint32_t count
= aKeys
->Length();
295 if (NS_WARN_IF(!JS::SetArrayLength(aCx
, array
, count
))) {
296 IDB_REPORT_INTERNAL_ERR();
297 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
300 for (uint32_t index
= 0; index
< count
; index
++) {
301 const Key
& key
= aKeys
->ElementAt(index
);
302 MOZ_ASSERT(!key
.IsUnset());
304 JS::Rooted
<JS::Value
> value(aCx
);
306 const nsresult rv
= GetResult(aCx
, &key
, &value
);
307 if (NS_WARN_IF(NS_FAILED(rv
))) {
312 !JS_DefineElement(aCx
, array
, index
, value
, JSPROP_ENUMERATE
))) {
313 IDB_REPORT_INTERNAL_ERR();
314 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
319 aResult
.setObject(*array
);
322 } // namespace detail
324 auto DeserializeStructuredCloneFiles(
325 IDBDatabase
* aDatabase
,
326 const nsTArray
<SerializedStructuredCloneFile
>& aSerializedFiles
,
327 bool aForPreprocess
) {
328 MOZ_ASSERT_IF(aForPreprocess
, aSerializedFiles
.Length() == 1);
330 return TransformIntoNewArray(
332 [aForPreprocess
, &database
= *aDatabase
](
333 const auto& serializedFile
) -> StructuredCloneFileChild
{
336 serializedFile
.type() == StructuredCloneFileBase::eStructuredClone
);
338 const NullableBlob
& blob
= serializedFile
.file();
340 switch (serializedFile
.type()) {
341 case StructuredCloneFileBase::eBlob
: {
342 MOZ_ASSERT(blob
.type() == NullableBlob::TIPCBlob
);
344 const IPCBlob
& ipcBlob
= blob
.get_IPCBlob();
346 const RefPtr
<BlobImpl
> blobImpl
=
347 IPCBlobUtils::Deserialize(ipcBlob
);
348 MOZ_ASSERT(blobImpl
);
351 Blob::Create(database
.GetOwnerGlobal(), blobImpl
);
354 return {StructuredCloneFileBase::eBlob
, std::move(blob
)};
357 case StructuredCloneFileBase::eStructuredClone
: {
358 if (aForPreprocess
) {
359 MOZ_ASSERT(blob
.type() == NullableBlob::TIPCBlob
);
361 const IPCBlob
& ipcBlob
= blob
.get_IPCBlob();
363 const RefPtr
<BlobImpl
> blobImpl
=
364 IPCBlobUtils::Deserialize(ipcBlob
);
365 MOZ_ASSERT(blobImpl
);
368 Blob::Create(database
.GetOwnerGlobal(), blobImpl
);
371 return {StructuredCloneFileBase::eStructuredClone
,
374 MOZ_ASSERT(blob
.type() == NullableBlob::Tnull_t
);
376 return StructuredCloneFileChild
{
377 StructuredCloneFileBase::eStructuredClone
};
380 case StructuredCloneFileBase::eMutableFile
:
381 case StructuredCloneFileBase::eWasmBytecode
:
382 case StructuredCloneFileBase::eWasmCompiled
: {
383 MOZ_ASSERT(blob
.type() == NullableBlob::Tnull_t
);
385 return StructuredCloneFileChild
{serializedFile
.type()};
387 // Don't set mBlob, support for storing WebAssembly.Modules has been
388 // removed in bug 1469395. Support for de-serialization of
389 // WebAssembly.Modules has been removed in bug 1561876. Support for
390 // MutableFile has been removed in bug 1500343. Full removal is
391 // tracked in bug 1487479.
395 MOZ_CRASH("Should never get here!");
400 JSStructuredCloneData
PreprocessingNotSupported() {
401 MOZ_CRASH("Preprocessing not (yet) supported!");
404 template <typename PreprocessInfoAccessor
>
405 StructuredCloneReadInfoChild
DeserializeStructuredCloneReadInfo(
406 SerializedStructuredCloneReadInfo
&& aSerialized
,
407 IDBDatabase
* const aDatabase
,
408 PreprocessInfoAccessor preprocessInfoAccessor
) {
409 // XXX Make this a class invariant of SerializedStructuredCloneReadInfo.
410 MOZ_ASSERT_IF(aSerialized
.hasPreprocessInfo(),
411 0 == aSerialized
.data().data
.Size());
412 return {aSerialized
.hasPreprocessInfo() ? preprocessInfoAccessor()
413 : std::move(aSerialized
.data().data
),
414 DeserializeStructuredCloneFiles(aDatabase
, aSerialized
.files(),
415 /* aForPreprocess */ false),
419 // TODO: Remove duplication between DispatchErrorEvent and DispatchSucessEvent.
421 void DispatchErrorEvent(
422 MovingNotNull
<RefPtr
<IDBRequest
>> aRequest
, nsresult aErrorCode
,
423 const SafeRefPtr
<IDBTransaction
>& aTransaction
= nullptr,
424 RefPtr
<Event
> aEvent
= nullptr) {
425 const RefPtr
<IDBRequest
> request
= std::move(aRequest
);
427 request
->AssertIsOnOwningThread();
428 MOZ_ASSERT(NS_FAILED(aErrorCode
));
429 MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode
) == NS_ERROR_MODULE_DOM_INDEXEDDB
);
431 AUTO_PROFILER_LABEL("IndexedDB:DispatchErrorEvent", DOM
);
433 request
->SetError(aErrorCode
);
436 // Make an error event and fire it at the target.
437 aEvent
= CreateGenericEvent(request
, nsDependentString(kErrorEventType
),
438 eDoesBubble
, eCancelable
);
442 // XXX This is redundant if we are called from
443 // DispatchSuccessEvent.
444 Maybe
<AutoSetCurrentTransaction
> asct
;
446 asct
.emplace(SomeRef(*aTransaction
));
449 if (aTransaction
&& aTransaction
->IsInactive()) {
450 aTransaction
->TransitionToActive();
454 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
455 "Firing %s event with error 0x%x", "%s (0x%" PRIx32
")",
456 aTransaction
->LoggingSerialNumber(), request
->LoggingSerialNumber(),
457 IDB_LOG_STRINGIFY(aEvent
, kErrorEventType
),
458 static_cast<uint32_t>(aErrorCode
));
460 IDB_LOG_MARK_CHILD_REQUEST("Firing %s event with error 0x%x",
461 "%s (0x%" PRIx32
")",
462 request
->LoggingSerialNumber(),
463 IDB_LOG_STRINGIFY(aEvent
, kErrorEventType
),
464 static_cast<uint32_t>(aErrorCode
));
467 IgnoredErrorResult rv
;
468 const bool doDefault
=
469 request
->DispatchEvent(*aEvent
, CallerType::System
, rv
);
470 if (NS_WARN_IF(rv
.Failed())) {
474 MOZ_ASSERT(!aTransaction
|| aTransaction
->IsActive() ||
475 aTransaction
->IsAborted() ||
476 aTransaction
->WasExplicitlyCommitted());
478 if (aTransaction
&& aTransaction
->IsActive()) {
479 aTransaction
->TransitionToInactive();
481 // Do not abort the transaction here if this request is failed due to the
482 // abortion of its transaction to ensure that the correct error cause of
483 // the abort event be set in IDBTransaction::FireCompleteOrAbortEvents()
485 if (aErrorCode
!= NS_ERROR_DOM_INDEXEDDB_ABORT_ERR
) {
486 WidgetEvent
* const internalEvent
= aEvent
->WidgetEventPtr();
487 MOZ_ASSERT(internalEvent
);
489 if (internalEvent
->mFlags
.mExceptionWasRaised
) {
490 aTransaction
->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR
);
491 } else if (doDefault
) {
492 aTransaction
->Abort(request
);
498 template <typename T
>
499 void SetResultAndDispatchSuccessEvent(
500 const NotNull
<RefPtr
<IDBRequest
>>& aRequest
,
501 const SafeRefPtr
<IDBTransaction
>& aTransaction
, T
& aPtr
,
502 RefPtr
<Event
> aEvent
) {
503 const auto autoTransaction
=
504 AutoSetCurrentTransaction
{aTransaction
.maybeDeref()};
506 AUTO_PROFILER_LABEL("IndexedDB:SetResultAndDispatchSuccessEvent", DOM
);
508 aRequest
->AssertIsOnOwningThread();
510 if (aTransaction
&& aTransaction
->IsAborted()) {
511 DispatchErrorEvent(aRequest
, aTransaction
->AbortCode(), aTransaction
);
517 CreateGenericEvent(aRequest
.get(), nsDependentString(kSuccessEventType
),
518 eDoesNotBubble
, eNotCancelable
);
523 [&aPtr
](JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
) {
525 return detail::GetResult(aCx
, &aPtr
, aResult
);
528 detail::DispatchSuccessEvent(aRequest
, aTransaction
, aEvent
);
532 void DispatchSuccessEvent(const NotNull
<RefPtr
<IDBRequest
>>& aRequest
,
533 const SafeRefPtr
<IDBTransaction
>& aTransaction
,
534 const RefPtr
<Event
>& aEvent
) {
535 if (aTransaction
&& aTransaction
->IsInactive()) {
536 aTransaction
->TransitionToActive();
540 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
541 "Firing %s event", "%s", aTransaction
->LoggingSerialNumber(),
542 aRequest
->LoggingSerialNumber(),
543 IDB_LOG_STRINGIFY(aEvent
, kSuccessEventType
));
545 IDB_LOG_MARK_CHILD_REQUEST("Firing %s event", "%s",
546 aRequest
->LoggingSerialNumber(),
547 IDB_LOG_STRINGIFY(aEvent
, kSuccessEventType
));
550 MOZ_ASSERT_IF(aTransaction
&& !aTransaction
->WasExplicitlyCommitted(),
551 aTransaction
->IsActive() && !aTransaction
->IsAborted());
553 IgnoredErrorResult rv
;
554 aRequest
->DispatchEvent(*aEvent
, rv
);
555 if (NS_WARN_IF(rv
.Failed())) {
559 WidgetEvent
* const internalEvent
= aEvent
->WidgetEventPtr();
560 MOZ_ASSERT(internalEvent
);
562 if (aTransaction
&& aTransaction
->IsActive()) {
563 aTransaction
->TransitionToInactive();
565 if (internalEvent
->mFlags
.mExceptionWasRaised
) {
566 aTransaction
->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR
);
568 // To handle upgrade transaction.
569 aTransaction
->CommitIfNotStarted();
573 } // namespace detail
575 PRFileDesc
* GetFileDescriptorFromStream(nsIInputStream
* aStream
) {
578 const nsCOMPtr
<nsIFileMetadata
> fileMetadata
= do_QueryInterface(aStream
);
579 if (NS_WARN_IF(!fileMetadata
)) {
583 PRFileDesc
* fileDesc
;
584 const nsresult rv
= fileMetadata
->GetFileDescriptor(&fileDesc
);
585 if (NS_WARN_IF(NS_FAILED(rv
))) {
589 MOZ_ASSERT(fileDesc
);
594 auto GetKeyOperator(const IDBCursorDirection aDirection
) {
595 switch (aDirection
) {
596 case IDBCursorDirection::Next
:
597 case IDBCursorDirection::Nextunique
:
598 return &Key::operator>=;
599 case IDBCursorDirection::Prev
:
600 case IDBCursorDirection::Prevunique
:
601 return &Key::operator<=;
603 MOZ_CRASH("Should never get here.");
607 // Does not need to be threadsafe since this only runs on one thread, but
608 // inheriting from CancelableRunnable is easy.
609 template <typename T
>
610 class DelayedActionRunnable final
: public CancelableRunnable
{
611 using ActionFunc
= void (T::*)();
613 SafeRefPtr
<T
> mActor
;
614 RefPtr
<IDBRequest
> mRequest
;
615 ActionFunc mActionFunc
;
618 explicit DelayedActionRunnable(SafeRefPtr
<T
> aActor
, ActionFunc aActionFunc
)
619 : CancelableRunnable("indexedDB::DelayedActionRunnable"),
620 mActor(std::move(aActor
)),
621 mRequest(mActor
->GetRequest()),
622 mActionFunc(aActionFunc
) {
624 mActor
->AssertIsOnOwningThread();
625 MOZ_ASSERT(mRequest
);
626 MOZ_ASSERT(mActionFunc
);
630 ~DelayedActionRunnable() = default;
633 nsresult
Cancel() override
;
638 /*******************************************************************************
639 * Actor class declarations
640 ******************************************************************************/
642 // DiscardableRunnable is used to make workers happy.
643 class BackgroundRequestChild::PreprocessHelper final
644 : public DiscardableRunnable
,
645 public nsIInputStreamCallback
,
646 public nsIFileMetadataCallback
{
648 // Just created on the owning thread, dispatched to the thread pool. Next
649 // step is either Finishing if stream was ready to be read or
650 // WaitingForStreamReady if the stream is not ready.
653 // Waiting for stream to be ready on a thread pool thread. Next state is
655 WaitingForStreamReady
,
657 // Waiting to finish/finishing on the owning thread. Next step is Completed.
664 const nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
665 RefPtr
<TaskQueue
> mTaskQueue
;
666 nsCOMPtr
<nsIInputStream
> mStream
;
667 UniquePtr
<JSStructuredCloneData
> mCloneData
;
668 BackgroundRequestChild
* mActor
;
669 const uint32_t mCloneDataIndex
;
670 nsresult mResultCode
;
674 PreprocessHelper(uint32_t aCloneDataIndex
, BackgroundRequestChild
* aActor
)
675 : DiscardableRunnable(
676 "indexedDB::BackgroundRequestChild::PreprocessHelper"),
677 mOwningEventTarget(aActor
->GetActorEventTarget()),
679 mCloneDataIndex(aCloneDataIndex
),
681 mState(State::Initial
) {
682 AssertIsOnOwningThread();
684 aActor
->AssertIsOnOwningThread();
687 bool IsOnOwningThread() const {
688 MOZ_ASSERT(mOwningEventTarget
);
691 return NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)) &&
695 void AssertIsOnOwningThread() const { MOZ_ASSERT(IsOnOwningThread()); }
698 AssertIsOnOwningThread();
703 nsresult
Init(const StructuredCloneFileChild
& aFile
);
708 ~PreprocessHelper() {
709 MOZ_ASSERT(mState
== State::Initial
|| mState
== State::Completed
);
712 mTaskQueue
->BeginShutdown();
718 nsresult
ProcessStream();
722 NS_DECL_ISUPPORTS_INHERITED
724 NS_DECL_NSIINPUTSTREAMCALLBACK
725 NS_DECL_NSIFILEMETADATACALLBACK
728 /*******************************************************************************
729 * BackgroundRequestChildBase
730 ******************************************************************************/
732 BackgroundRequestChildBase::BackgroundRequestChildBase(
733 MovingNotNull
<RefPtr
<IDBRequest
>> aRequest
)
734 : mRequest(std::move(aRequest
)) {
735 mRequest
->AssertIsOnOwningThread();
737 MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChildBase
);
740 BackgroundRequestChildBase::~BackgroundRequestChildBase() {
741 AssertIsOnOwningThread();
743 MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChildBase
);
748 void BackgroundRequestChildBase::AssertIsOnOwningThread() const {
749 mRequest
->AssertIsOnOwningThread();
754 /*******************************************************************************
755 * BackgroundFactoryChild
756 ******************************************************************************/
758 BackgroundFactoryChild::BackgroundFactoryChild(IDBFactory
& aFactory
)
759 : mFactory(&aFactory
) {
760 AssertIsOnOwningThread();
761 mFactory
->AssertIsOnOwningThread();
763 MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryChild
);
766 BackgroundFactoryChild::~BackgroundFactoryChild() {
767 MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryChild
);
770 void BackgroundFactoryChild::SendDeleteMeInternal() {
771 AssertIsOnOwningThread();
774 mFactory
->ClearBackgroundActor();
777 MOZ_ALWAYS_TRUE(PBackgroundIDBFactoryChild::SendDeleteMe());
781 void BackgroundFactoryChild::ActorDestroy(ActorDestroyReason aWhy
) {
782 AssertIsOnOwningThread();
784 MaybeCollectGarbageOnIPCMessage();
787 mFactory
->ClearBackgroundActor();
794 PBackgroundIDBFactoryRequestChild
*
795 BackgroundFactoryChild::AllocPBackgroundIDBFactoryRequestChild(
796 const FactoryRequestParams
& aParams
) {
798 "PBackgroundIDBFactoryRequestChild actors should be manually "
802 bool BackgroundFactoryChild::DeallocPBackgroundIDBFactoryRequestChild(
803 PBackgroundIDBFactoryRequestChild
* aActor
) {
806 delete static_cast<BackgroundFactoryRequestChild
*>(aActor
);
810 already_AddRefed
<PBackgroundIDBDatabaseChild
>
811 BackgroundFactoryChild::AllocPBackgroundIDBDatabaseChild(
812 const DatabaseSpec
& aSpec
,
813 PBackgroundIDBFactoryRequestChild
* aRequest
) const {
814 AssertIsOnOwningThread();
816 auto* const request
= static_cast<BackgroundFactoryRequestChild
*>(aRequest
);
819 RefPtr
<BackgroundDatabaseChild
> actor
=
820 new BackgroundDatabaseChild(aSpec
, request
);
821 return actor
.forget();
824 mozilla::ipc::IPCResult
825 BackgroundFactoryChild::RecvPBackgroundIDBDatabaseConstructor(
826 PBackgroundIDBDatabaseChild
* aActor
, const DatabaseSpec
& aSpec
,
827 NotNull
<PBackgroundIDBFactoryRequestChild
*> aRequest
) {
828 AssertIsOnOwningThread();
834 /*******************************************************************************
835 * BackgroundFactoryRequestChild
836 ******************************************************************************/
838 BackgroundFactoryRequestChild::BackgroundFactoryRequestChild(
839 SafeRefPtr
<IDBFactory
> aFactory
,
840 MovingNotNull
<RefPtr
<IDBOpenDBRequest
>> aOpenRequest
, bool aIsDeleteOp
,
841 uint64_t aRequestedVersion
)
842 : BackgroundRequestChildBase(std::move(aOpenRequest
)),
843 mFactory(std::move(aFactory
)),
844 mDatabaseActor(nullptr),
845 mRequestedVersion(aRequestedVersion
),
846 mIsDeleteOp(aIsDeleteOp
) {
847 // Can't assert owning thread here because IPDL has not yet set our manager!
848 MOZ_ASSERT(mFactory
);
849 mFactory
->AssertIsOnOwningThread();
851 MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryRequestChild
);
854 BackgroundFactoryRequestChild::~BackgroundFactoryRequestChild() {
855 MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryRequestChild
);
858 NotNull
<IDBOpenDBRequest
*> BackgroundFactoryRequestChild::GetOpenDBRequest()
860 AssertIsOnOwningThread();
862 // XXX NotNull might provide something to encapsulate this
863 return WrapNotNullUnchecked(
864 static_cast<IDBOpenDBRequest
*>(mRequest
.get().get()));
867 void BackgroundFactoryRequestChild::SetDatabaseActor(
868 BackgroundDatabaseChild
* aActor
) {
869 AssertIsOnOwningThread();
870 MOZ_ASSERT(!aActor
|| !mDatabaseActor
);
872 mDatabaseActor
= aActor
;
875 void BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse
) {
876 AssertIsOnOwningThread();
877 MOZ_ASSERT(NS_FAILED(aResponse
));
878 MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse
) == NS_ERROR_MODULE_DOM_INDEXEDDB
);
882 DispatchErrorEvent(mRequest
, aResponse
);
884 if (mDatabaseActor
) {
885 mDatabaseActor
->ReleaseDOMObject();
886 MOZ_ASSERT(!mDatabaseActor
);
890 void BackgroundFactoryRequestChild::HandleResponse(
891 const OpenDatabaseRequestResponse
& aResponse
) {
892 AssertIsOnOwningThread();
896 auto* databaseActor
= static_cast<BackgroundDatabaseChild
*>(
897 aResponse
.database().AsChild().get());
898 MOZ_ASSERT(databaseActor
);
900 IDBDatabase
* const database
= [this, databaseActor
]() -> IDBDatabase
* {
901 IDBDatabase
* database
= databaseActor
->GetDOMObject();
905 if (NS_WARN_IF(!databaseActor
->EnsureDOMObject())) {
908 MOZ_ASSERT(mDatabaseActor
);
910 database
= databaseActor
->GetDOMObject();
911 MOZ_ASSERT(database
);
913 MOZ_ASSERT(!database
->IsClosed());
919 if (!database
|| database
->IsClosed()) {
920 // If the database was closed already, which is only possible if we fired an
921 // "upgradeneeded" event, then we shouldn't fire a "success" event here.
922 // Instead we fire an error event with AbortErr.
923 DispatchErrorEvent(mRequest
, NS_ERROR_DOM_INDEXEDDB_ABORT_ERR
);
925 SetResultAndDispatchSuccessEvent(mRequest
, nullptr, *database
);
929 MOZ_ASSERT(mDatabaseActor
== databaseActor
);
931 databaseActor
->ReleaseDOMObject();
933 databaseActor
->SendDeleteMeInternal();
935 MOZ_ASSERT(!mDatabaseActor
);
938 void BackgroundFactoryRequestChild::HandleResponse(
939 const DeleteDatabaseRequestResponse
& aResponse
) {
940 AssertIsOnOwningThread();
942 RefPtr
<Event
> successEvent
= IDBVersionChangeEvent::Create(
943 mRequest
.get(), nsDependentString(kSuccessEventType
),
944 aResponse
.previousVersion());
945 MOZ_ASSERT(successEvent
);
947 SetResultAndDispatchSuccessEvent(mRequest
, nullptr, JS::UndefinedHandleValue
,
948 std::move(successEvent
));
950 MOZ_ASSERT(!mDatabaseActor
);
953 void BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy
) {
954 AssertIsOnOwningThread();
956 MaybeCollectGarbageOnIPCMessage();
958 if (aWhy
!= Deletion
) {
959 GetOpenDBRequest()->NoteComplete();
963 mozilla::ipc::IPCResult
BackgroundFactoryRequestChild::Recv__delete__(
964 const FactoryRequestResponse
& aResponse
) {
965 AssertIsOnOwningThread();
967 MaybeCollectGarbageOnIPCMessage();
969 switch (aResponse
.type()) {
970 case FactoryRequestResponse::Tnsresult
:
971 HandleResponse(aResponse
.get_nsresult());
974 case FactoryRequestResponse::TOpenDatabaseRequestResponse
:
975 HandleResponse(aResponse
.get_OpenDatabaseRequestResponse());
978 case FactoryRequestResponse::TDeleteDatabaseRequestResponse
:
979 HandleResponse(aResponse
.get_DeleteDatabaseRequestResponse());
983 return IPC_FAIL(this, "Unknown response type!");
986 auto request
= GetOpenDBRequest();
987 request
->NoteComplete();
992 mozilla::ipc::IPCResult
BackgroundFactoryRequestChild::RecvBlocked(
993 const uint64_t aCurrentVersion
) {
994 AssertIsOnOwningThread();
996 MaybeCollectGarbageOnIPCMessage();
998 const nsDependentString
type(kBlockedEventType
);
1000 RefPtr
<Event
> blockedEvent
;
1003 IDBVersionChangeEvent::Create(mRequest
.get(), type
, aCurrentVersion
);
1004 MOZ_ASSERT(blockedEvent
);
1006 blockedEvent
= IDBVersionChangeEvent::Create(
1007 mRequest
.get(), type
, aCurrentVersion
, mRequestedVersion
);
1008 MOZ_ASSERT(blockedEvent
);
1011 RefPtr
<IDBRequest
> kungFuDeathGrip
= mRequest
;
1013 IDB_LOG_MARK_CHILD_REQUEST("Firing \"blocked\" event", "\"blocked\"",
1014 kungFuDeathGrip
->LoggingSerialNumber());
1016 IgnoredErrorResult rv
;
1017 kungFuDeathGrip
->DispatchEvent(*blockedEvent
, rv
);
1019 NS_WARNING("Failed to dispatch event!");
1025 /*******************************************************************************
1026 * BackgroundDatabaseChild
1027 ******************************************************************************/
1029 BackgroundDatabaseChild::BackgroundDatabaseChild(
1030 const DatabaseSpec
& aSpec
, BackgroundFactoryRequestChild
* aOpenRequestActor
)
1031 : mSpec(MakeUnique
<DatabaseSpec
>(aSpec
)),
1032 mOpenRequestActor(aOpenRequestActor
),
1033 mDatabase(nullptr) {
1034 // Can't assert owning thread here because IPDL has not yet set our manager!
1035 MOZ_ASSERT(aOpenRequestActor
);
1037 MOZ_COUNT_CTOR(indexedDB::BackgroundDatabaseChild
);
1040 BackgroundDatabaseChild::~BackgroundDatabaseChild() {
1041 MOZ_COUNT_DTOR(indexedDB::BackgroundDatabaseChild
);
1046 void BackgroundDatabaseChild::AssertIsOnOwningThread() const {
1047 static_cast<BackgroundFactoryChild
*>(Manager())->AssertIsOnOwningThread();
1052 void BackgroundDatabaseChild::SendDeleteMeInternal() {
1053 AssertIsOnOwningThread();
1054 MOZ_ASSERT(!mTemporaryStrongDatabase
);
1055 MOZ_ASSERT(!mOpenRequestActor
);
1058 mDatabase
->ClearBackgroundActor();
1059 mDatabase
= nullptr;
1061 MOZ_ALWAYS_TRUE(PBackgroundIDBDatabaseChild::SendDeleteMe());
1065 bool BackgroundDatabaseChild::EnsureDOMObject() {
1066 AssertIsOnOwningThread();
1067 MOZ_ASSERT(mOpenRequestActor
);
1069 if (mTemporaryStrongDatabase
) {
1071 MOZ_ASSERT(mDatabase
== mTemporaryStrongDatabase
);
1077 const auto request
= mOpenRequestActor
->GetOpenDBRequest();
1080 static_cast<BackgroundFactoryChild
*>(Manager())->GetDOMObject();
1082 if (!factory
.GetParentObject()) {
1083 // Already disconnected from global.
1085 // We need to clear mOpenRequestActor here, since that would otherwise be
1086 // done by ReleaseDOMObject, which cannot be called if EnsureDOMObject
1088 mOpenRequestActor
= nullptr;
1093 // TODO: This AcquireStrongRefFromRawPtr looks suspicious. This should be
1094 // changed or at least well explained, see also comment on
1095 // BackgroundFactoryChild.
1096 mTemporaryStrongDatabase
= IDBDatabase::Create(
1097 request
, SafeRefPtr
{&factory
, AcquireStrongRefFromRawPtr
{}}, this,
1100 MOZ_ASSERT(mTemporaryStrongDatabase
);
1101 mTemporaryStrongDatabase
->AssertIsOnOwningThread();
1103 mDatabase
= mTemporaryStrongDatabase
;
1105 mOpenRequestActor
->SetDatabaseActor(this);
1110 void BackgroundDatabaseChild::ReleaseDOMObject() {
1111 AssertIsOnOwningThread();
1112 MOZ_ASSERT(mTemporaryStrongDatabase
);
1113 mTemporaryStrongDatabase
->AssertIsOnOwningThread();
1114 MOZ_ASSERT(mOpenRequestActor
);
1115 MOZ_ASSERT(mDatabase
== mTemporaryStrongDatabase
);
1117 mOpenRequestActor
->SetDatabaseActor(nullptr);
1119 mOpenRequestActor
= nullptr;
1121 // This may be the final reference to the IDBDatabase object so we may end up
1122 // calling SendDeleteMeInternal() here. Make sure everything is cleaned up
1123 // properly before proceeding.
1124 mTemporaryStrongDatabase
= nullptr;
1126 // XXX Why isn't mDatabase set to nullptr here?
1129 void BackgroundDatabaseChild::ActorDestroy(ActorDestroyReason aWhy
) {
1130 AssertIsOnOwningThread();
1132 MaybeCollectGarbageOnIPCMessage();
1135 mDatabase
->ClearBackgroundActor();
1137 mDatabase
= nullptr;
1142 PBackgroundIDBDatabaseFileChild
*
1143 BackgroundDatabaseChild::AllocPBackgroundIDBDatabaseFileChild(
1144 const IPCBlob
& aIPCBlob
) {
1145 MOZ_CRASH("PBackgroundIDBFileChild actors should be manually constructed!");
1148 bool BackgroundDatabaseChild::DeallocPBackgroundIDBDatabaseFileChild(
1149 PBackgroundIDBDatabaseFileChild
* aActor
) const {
1150 AssertIsOnOwningThread();
1157 already_AddRefed
<PBackgroundIDBVersionChangeTransactionChild
>
1158 BackgroundDatabaseChild::AllocPBackgroundIDBVersionChangeTransactionChild(
1159 const uint64_t aCurrentVersion
, const uint64_t aRequestedVersion
,
1160 const int64_t aNextObjectStoreId
, const int64_t aNextIndexId
) {
1161 AssertIsOnOwningThread();
1163 return RefPtr
{new BackgroundVersionChangeTransactionChild(
1164 mOpenRequestActor
->GetOpenDBRequest())}
1168 mozilla::ipc::IPCResult
1169 BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
1170 PBackgroundIDBVersionChangeTransactionChild
* aActor
,
1171 const uint64_t& aCurrentVersion
, const uint64_t& aRequestedVersion
,
1172 const int64_t& aNextObjectStoreId
, const int64_t& aNextIndexId
) {
1173 AssertIsOnOwningThread();
1175 MOZ_ASSERT(mOpenRequestActor
);
1177 MaybeCollectGarbageOnIPCMessage();
1180 static_cast<BackgroundVersionChangeTransactionChild
*>(aActor
);
1182 if (!EnsureDOMObject()) {
1183 NS_WARNING("Factory is already disconnected from global");
1185 actor
->SendDeleteMeInternal(true);
1187 // XXX This is a hack to ensure that transaction/request serial numbers stay
1188 // in sync between parent and child. Actually, it might be better to create
1189 // an IDBTransaction in the child and abort that.
1191 << mozilla::ipc::BackgroundChildImpl::GetThreadLocalForCurrentThread()
1192 ->mIndexedDBThreadLocal
->NextTransactionSN(
1193 IDBTransaction::Mode::VersionChange
);
1194 Unused
<< IDBRequest::NextSerialNumber();
1196 // No reason to IPC_FAIL here.
1200 MOZ_ASSERT(!mDatabase
->IsInvalidated());
1202 // XXX NotNull might encapsulate this
1203 const auto request
=
1204 WrapNotNullUnchecked(RefPtr
{mOpenRequestActor
->GetOpenDBRequest().get()});
1206 SafeRefPtr
<IDBTransaction
> transaction
= IDBTransaction::CreateVersionChange(
1207 mDatabase
, actor
, request
, aNextObjectStoreId
, aNextIndexId
);
1208 MOZ_ASSERT(transaction
);
1210 transaction
->AssertIsOnOwningThread();
1212 actor
->SetDOMTransaction(transaction
.clonePtr());
1214 const auto database
= WrapNotNull(mDatabase
);
1216 database
->EnterSetVersionTransaction(aRequestedVersion
);
1218 request
->SetTransaction(transaction
.clonePtr());
1220 RefPtr
<Event
> upgradeNeededEvent
= IDBVersionChangeEvent::Create(
1221 request
.get(), nsDependentString(kUpgradeNeededEventType
),
1222 aCurrentVersion
, aRequestedVersion
);
1223 MOZ_ASSERT(upgradeNeededEvent
);
1225 SetResultAndDispatchSuccessEvent(
1226 WrapNotNullUnchecked
<RefPtr
<IDBRequest
>>(request
.get()), transaction
,
1227 *database
, std::move(upgradeNeededEvent
));
1232 mozilla::ipc::IPCResult
BackgroundDatabaseChild::RecvVersionChange(
1233 const uint64_t aOldVersion
, const Maybe
<uint64_t> aNewVersion
) {
1234 AssertIsOnOwningThread();
1236 MaybeCollectGarbageOnIPCMessage();
1238 if (!mDatabase
|| mDatabase
->IsClosed()) {
1242 RefPtr
<IDBDatabase
> kungFuDeathGrip
= mDatabase
;
1244 // Handle bfcache'd windows.
1245 if (nsPIDOMWindowInner
* owner
= kungFuDeathGrip
->GetOwner()) {
1246 // The database must be closed if the window is already frozen.
1247 bool shouldAbortAndClose
= owner
->IsFrozen();
1249 // Anything in the bfcache has to be evicted and then we have to close the
1251 if (owner
->RemoveFromBFCacheSync()) {
1252 shouldAbortAndClose
= true;
1255 if (shouldAbortAndClose
) {
1256 // Invalidate() doesn't close the database in the parent, so we have
1257 // to call Close() and AbortTransactions() manually.
1258 kungFuDeathGrip
->AbortTransactions(/* aShouldWarn */ false);
1259 kungFuDeathGrip
->Close();
1264 // Otherwise fire a versionchange event.
1265 const nsDependentString
type(kVersionChangeEventType
);
1267 RefPtr
<Event
> versionChangeEvent
;
1269 if (aNewVersion
.isNothing()) {
1270 versionChangeEvent
=
1271 IDBVersionChangeEvent::Create(kungFuDeathGrip
, type
, aOldVersion
);
1272 MOZ_ASSERT(versionChangeEvent
);
1274 versionChangeEvent
= IDBVersionChangeEvent::Create(
1275 kungFuDeathGrip
, type
, aOldVersion
, aNewVersion
.value());
1276 MOZ_ASSERT(versionChangeEvent
);
1279 IDB_LOG_MARK("Child : Firing \"versionchange\" event",
1280 "C: IDBDatabase \"versionchange\" event", IDB_LOG_ID_STRING());
1282 IgnoredErrorResult rv
;
1283 kungFuDeathGrip
->DispatchEvent(*versionChangeEvent
, rv
);
1285 NS_WARNING("Failed to dispatch event!");
1288 if (!kungFuDeathGrip
->IsClosed()) {
1295 mozilla::ipc::IPCResult
BackgroundDatabaseChild::RecvInvalidate() {
1296 AssertIsOnOwningThread();
1298 MaybeCollectGarbageOnIPCMessage();
1301 mDatabase
->Invalidate();
1307 mozilla::ipc::IPCResult
1308 BackgroundDatabaseChild::RecvCloseAfterInvalidationComplete() {
1309 AssertIsOnOwningThread();
1311 MaybeCollectGarbageOnIPCMessage();
1314 mDatabase
->DispatchTrustedEvent(nsDependentString(kCloseEventType
));
1320 /*******************************************************************************
1321 * BackgroundTransactionBase
1322 ******************************************************************************/
1324 BackgroundTransactionBase::BackgroundTransactionBase(
1325 SafeRefPtr
<IDBTransaction
> aTransaction
)
1326 : mTemporaryStrongTransaction(std::move(aTransaction
)),
1327 mTransaction(mTemporaryStrongTransaction
.unsafeGetRawPtr()) {
1328 MOZ_ASSERT(mTransaction
);
1329 mTransaction
->AssertIsOnOwningThread();
1331 MOZ_COUNT_CTOR(BackgroundTransactionBase
);
1336 void BackgroundTransactionBase::AssertIsOnOwningThread() const {
1337 MOZ_ASSERT(mTransaction
);
1338 mTransaction
->AssertIsOnOwningThread();
1343 void BackgroundTransactionBase::NoteActorDestroyed() {
1344 AssertIsOnOwningThread();
1345 MOZ_ASSERT_IF(mTemporaryStrongTransaction
, mTransaction
);
1348 mTransaction
->ClearBackgroundActor();
1350 // Normally this would be DEBUG-only but NoteActorDestroyed is also called
1351 // from SendDeleteMeInternal. In that case we're going to receive an actual
1352 // ActorDestroy call later and we don't want to touch a dead object.
1353 mTemporaryStrongTransaction
= nullptr;
1354 mTransaction
= nullptr;
1358 void BackgroundTransactionBase::SetDOMTransaction(
1359 SafeRefPtr
<IDBTransaction
> aTransaction
) {
1360 AssertIsOnOwningThread();
1361 MOZ_ASSERT(aTransaction
);
1362 aTransaction
->AssertIsOnOwningThread();
1363 MOZ_ASSERT(!mTemporaryStrongTransaction
);
1364 MOZ_ASSERT(!mTransaction
);
1366 mTemporaryStrongTransaction
= std::move(aTransaction
);
1367 mTransaction
= mTemporaryStrongTransaction
.unsafeGetRawPtr();
1370 void BackgroundTransactionBase::NoteComplete() {
1371 AssertIsOnOwningThread();
1372 MOZ_ASSERT_IF(mTransaction
, mTemporaryStrongTransaction
);
1374 mTemporaryStrongTransaction
= nullptr;
1377 /*******************************************************************************
1378 * BackgroundTransactionChild
1379 ******************************************************************************/
1381 BackgroundTransactionChild::BackgroundTransactionChild(
1382 SafeRefPtr
<IDBTransaction
> aTransaction
)
1383 : BackgroundTransactionBase(std::move(aTransaction
)) {
1384 MOZ_COUNT_CTOR(indexedDB::BackgroundTransactionChild
);
1387 BackgroundTransactionChild::~BackgroundTransactionChild() {
1388 MOZ_COUNT_DTOR(indexedDB::BackgroundTransactionChild
);
1393 void BackgroundTransactionChild::AssertIsOnOwningThread() const {
1394 static_cast<BackgroundDatabaseChild
*>(Manager())->AssertIsOnOwningThread();
1399 void BackgroundTransactionChild::SendDeleteMeInternal() {
1400 AssertIsOnOwningThread();
1403 NoteActorDestroyed();
1405 MOZ_ALWAYS_TRUE(PBackgroundIDBTransactionChild::SendDeleteMe());
1409 void BackgroundTransactionChild::ActorDestroy(ActorDestroyReason aWhy
) {
1410 AssertIsOnOwningThread();
1412 MaybeCollectGarbageOnIPCMessage();
1414 NoteActorDestroyed();
1417 mozilla::ipc::IPCResult
BackgroundTransactionChild::RecvComplete(
1418 const nsresult aResult
) {
1419 AssertIsOnOwningThread();
1420 MOZ_ASSERT(mTransaction
);
1422 MaybeCollectGarbageOnIPCMessage();
1424 mTransaction
->FireCompleteOrAbortEvents(aResult
);
1430 PBackgroundIDBRequestChild
*
1431 BackgroundTransactionChild::AllocPBackgroundIDBRequestChild(
1432 const RequestParams
& aParams
) {
1434 "PBackgroundIDBRequestChild actors should be manually "
1438 bool BackgroundTransactionChild::DeallocPBackgroundIDBRequestChild(
1439 PBackgroundIDBRequestChild
* aActor
) {
1442 delete static_cast<BackgroundRequestChild
*>(aActor
);
1446 PBackgroundIDBCursorChild
*
1447 BackgroundTransactionChild::AllocPBackgroundIDBCursorChild(
1448 const OpenCursorParams
& aParams
) {
1449 AssertIsOnOwningThread();
1451 MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
1454 bool BackgroundTransactionChild::DeallocPBackgroundIDBCursorChild(
1455 PBackgroundIDBCursorChild
* aActor
) {
1462 /*******************************************************************************
1463 * BackgroundVersionChangeTransactionChild
1464 ******************************************************************************/
1466 BackgroundVersionChangeTransactionChild::
1467 BackgroundVersionChangeTransactionChild(IDBOpenDBRequest
* aOpenDBRequest
)
1468 : mOpenDBRequest(aOpenDBRequest
) {
1469 MOZ_ASSERT(aOpenDBRequest
);
1470 aOpenDBRequest
->AssertIsOnOwningThread();
1472 MOZ_COUNT_CTOR(indexedDB::BackgroundVersionChangeTransactionChild
);
1475 BackgroundVersionChangeTransactionChild::
1476 ~BackgroundVersionChangeTransactionChild() {
1477 AssertIsOnOwningThread();
1479 MOZ_COUNT_DTOR(indexedDB::BackgroundVersionChangeTransactionChild
);
1484 void BackgroundVersionChangeTransactionChild::AssertIsOnOwningThread() const {
1485 static_cast<BackgroundDatabaseChild
*>(Manager())->AssertIsOnOwningThread();
1490 void BackgroundVersionChangeTransactionChild::SendDeleteMeInternal(
1491 bool aFailedConstructor
) {
1492 AssertIsOnOwningThread();
1494 if (mTransaction
|| aFailedConstructor
) {
1495 NoteActorDestroyed();
1498 PBackgroundIDBVersionChangeTransactionChild::SendDeleteMe());
1502 void BackgroundVersionChangeTransactionChild::ActorDestroy(
1503 ActorDestroyReason aWhy
) {
1504 AssertIsOnOwningThread();
1506 MaybeCollectGarbageOnIPCMessage();
1508 mOpenDBRequest
= nullptr;
1510 NoteActorDestroyed();
1513 mozilla::ipc::IPCResult
BackgroundVersionChangeTransactionChild::RecvComplete(
1514 const nsresult aResult
) {
1515 AssertIsOnOwningThread();
1517 MaybeCollectGarbageOnIPCMessage();
1519 if (!mTransaction
) {
1523 MOZ_ASSERT(mOpenDBRequest
);
1525 IDBDatabase
* database
= mTransaction
->Database();
1526 MOZ_ASSERT(database
);
1528 database
->ExitSetVersionTransaction();
1530 if (NS_FAILED(aResult
)) {
1534 RefPtr
<IDBOpenDBRequest
> request
= mOpenDBRequest
;
1535 MOZ_ASSERT(request
);
1537 mTransaction
->FireCompleteOrAbortEvents(aResult
);
1539 request
->SetTransaction(nullptr);
1542 mOpenDBRequest
= nullptr;
1548 PBackgroundIDBRequestChild
*
1549 BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBRequestChild(
1550 const RequestParams
& aParams
) {
1552 "PBackgroundIDBRequestChild actors should be manually "
1556 bool BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBRequestChild(
1557 PBackgroundIDBRequestChild
* aActor
) {
1560 delete static_cast<BackgroundRequestChild
*>(aActor
);
1564 PBackgroundIDBCursorChild
*
1565 BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBCursorChild(
1566 const OpenCursorParams
& aParams
) {
1567 AssertIsOnOwningThread();
1569 MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
1572 bool BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBCursorChild(
1573 PBackgroundIDBCursorChild
* aActor
) {
1580 /*******************************************************************************
1581 * BackgroundRequestChild
1582 ******************************************************************************/
1584 BackgroundRequestChild::BackgroundRequestChild(
1585 MovingNotNull
<RefPtr
<IDBRequest
>> aRequest
)
1586 : BackgroundRequestChildBase(std::move(aRequest
)),
1587 mTransaction(mRequest
->AcquireTransaction()),
1588 mRunningPreprocessHelpers(0),
1589 mCurrentCloneDataIndex(0),
1590 mPreprocessResultCode(NS_OK
),
1592 MOZ_ASSERT(mTransaction
);
1593 mTransaction
->AssertIsOnOwningThread();
1595 MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChild
);
1598 BackgroundRequestChild::~BackgroundRequestChild() {
1599 AssertIsOnOwningThread();
1600 MOZ_ASSERT(!mTransaction
);
1602 MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChild
);
1605 void BackgroundRequestChild::MaybeSendContinue() {
1606 AssertIsOnOwningThread();
1607 MOZ_ASSERT(mRunningPreprocessHelpers
> 0);
1609 if (--mRunningPreprocessHelpers
== 0) {
1610 PreprocessResponse response
;
1612 if (NS_SUCCEEDED(mPreprocessResultCode
)) {
1614 response
= ObjectStoreGetAllPreprocessResponse();
1616 response
= ObjectStoreGetPreprocessResponse();
1619 response
= mPreprocessResultCode
;
1622 MOZ_ALWAYS_TRUE(SendContinue(response
));
1626 void BackgroundRequestChild::OnPreprocessFinished(
1627 uint32_t aCloneDataIndex
, UniquePtr
<JSStructuredCloneData
> aCloneData
) {
1628 AssertIsOnOwningThread();
1629 MOZ_ASSERT(aCloneDataIndex
< mCloneInfos
.Length());
1630 MOZ_ASSERT(aCloneData
);
1632 auto& cloneInfo
= mCloneInfos
[aCloneDataIndex
];
1633 MOZ_ASSERT(cloneInfo
.mPreprocessHelper
);
1634 MOZ_ASSERT(!cloneInfo
.mCloneData
);
1636 cloneInfo
.mCloneData
= std::move(aCloneData
);
1638 MaybeSendContinue();
1640 cloneInfo
.mPreprocessHelper
= nullptr;
1643 void BackgroundRequestChild::OnPreprocessFailed(uint32_t aCloneDataIndex
,
1644 nsresult aErrorCode
) {
1645 AssertIsOnOwningThread();
1646 MOZ_ASSERT(aCloneDataIndex
< mCloneInfos
.Length());
1647 MOZ_ASSERT(NS_FAILED(aErrorCode
));
1649 auto& cloneInfo
= mCloneInfos
[aCloneDataIndex
];
1650 MOZ_ASSERT(cloneInfo
.mPreprocessHelper
);
1651 MOZ_ASSERT(!cloneInfo
.mCloneData
);
1653 if (NS_SUCCEEDED(mPreprocessResultCode
)) {
1654 mPreprocessResultCode
= aErrorCode
;
1657 MaybeSendContinue();
1659 cloneInfo
.mPreprocessHelper
= nullptr;
1662 UniquePtr
<JSStructuredCloneData
> BackgroundRequestChild::GetNextCloneData() {
1663 AssertIsOnOwningThread();
1664 MOZ_ASSERT(mCurrentCloneDataIndex
< mCloneInfos
.Length());
1665 MOZ_ASSERT(mCloneInfos
[mCurrentCloneDataIndex
].mCloneData
);
1667 return std::move(mCloneInfos
[mCurrentCloneDataIndex
++].mCloneData
);
1670 void BackgroundRequestChild::HandleResponse(nsresult aResponse
) {
1671 AssertIsOnOwningThread();
1672 MOZ_ASSERT(NS_FAILED(aResponse
));
1673 MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse
) == NS_ERROR_MODULE_DOM_INDEXEDDB
);
1674 MOZ_ASSERT(mTransaction
);
1676 DispatchErrorEvent(mRequest
, aResponse
, mTransaction
.clonePtr());
1679 void BackgroundRequestChild::HandleResponse(const Key
& aResponse
) {
1680 AssertIsOnOwningThread();
1682 SetResultAndDispatchSuccessEvent(mRequest
, AcquireTransaction(), aResponse
);
1685 void BackgroundRequestChild::HandleResponse(const nsTArray
<Key
>& aResponse
) {
1686 AssertIsOnOwningThread();
1688 SetResultAndDispatchSuccessEvent(mRequest
, AcquireTransaction(), aResponse
);
1691 void BackgroundRequestChild::HandleResponse(
1692 SerializedStructuredCloneReadInfo
&& aResponse
) {
1693 AssertIsOnOwningThread();
1695 if (!mTransaction
->Database()->GetOwnerGlobal()) {
1696 // Ignore the response, since we have already been disconnected from the
1701 auto cloneReadInfo
= DeserializeStructuredCloneReadInfo(
1702 std::move(aResponse
), mTransaction
->Database(),
1703 [this] { return std::move(*GetNextCloneData()); });
1705 SetResultAndDispatchSuccessEvent(mRequest
, AcquireTransaction(),
1709 void BackgroundRequestChild::HandleResponse(
1710 nsTArray
<SerializedStructuredCloneReadInfo
>&& aResponse
) {
1711 AssertIsOnOwningThread();
1713 if (!mTransaction
->Database()->GetOwnerGlobal()) {
1714 // Ignore the response, since we have already been disconnected from the
1719 nsTArray
<StructuredCloneReadInfoChild
> cloneReadInfos
;
1721 QM_TRY(OkIf(cloneReadInfos
.SetCapacity(aResponse
.Length(), fallible
)),
1722 QM_VOID
, ([&aResponse
, this](const auto) {
1723 // Since we are under memory pressure, release aResponse early.
1726 DispatchErrorEvent(mRequest
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
,
1727 AcquireTransaction());
1729 MOZ_ASSERT(mTransaction
->IsAborted());
1732 std::transform(std::make_move_iterator(aResponse
.begin()),
1733 std::make_move_iterator(aResponse
.end()),
1734 MakeBackInserter(cloneReadInfos
),
1735 [database
= mTransaction
->Database(), this](
1736 SerializedStructuredCloneReadInfo
&& serializedCloneInfo
) {
1737 return DeserializeStructuredCloneReadInfo(
1738 std::move(serializedCloneInfo
), database
,
1739 [this] { return std::move(*GetNextCloneData()); });
1742 SetResultAndDispatchSuccessEvent(mRequest
, AcquireTransaction(),
1746 void BackgroundRequestChild::HandleResponse(JS::Handle
<JS::Value
> aResponse
) {
1747 AssertIsOnOwningThread();
1749 SetResultAndDispatchSuccessEvent(
1750 mRequest
, AcquireTransaction(),
1751 const_cast<const JS::Handle
<JS::Value
>&>(aResponse
));
1754 void BackgroundRequestChild::HandleResponse(const uint64_t aResponse
) {
1755 AssertIsOnOwningThread();
1757 SetResultAndDispatchSuccessEvent(mRequest
, AcquireTransaction(), aResponse
);
1760 nsresult
BackgroundRequestChild::HandlePreprocess(
1761 const PreprocessInfo
& aPreprocessInfo
) {
1762 return HandlePreprocessInternal(
1763 AutoTArray
<PreprocessInfo
, 1>{aPreprocessInfo
});
1766 nsresult
BackgroundRequestChild::HandlePreprocess(
1767 const nsTArray
<PreprocessInfo
>& aPreprocessInfos
) {
1768 AssertIsOnOwningThread();
1771 return HandlePreprocessInternal(aPreprocessInfos
);
1774 nsresult
BackgroundRequestChild::HandlePreprocessInternal(
1775 const nsTArray
<PreprocessInfo
>& aPreprocessInfos
) {
1776 AssertIsOnOwningThread();
1778 IDBDatabase
* database
= mTransaction
->Database();
1780 const uint32_t count
= aPreprocessInfos
.Length();
1782 mCloneInfos
.SetLength(count
);
1784 // TODO: Since we use the stream transport service, this can spawn 25 threads
1785 // and has the potential to cause some annoying browser hiccups.
1786 // Consider using a single thread or a very small threadpool.
1787 for (uint32_t index
= 0; index
< count
; index
++) {
1788 const PreprocessInfo
& preprocessInfo
= aPreprocessInfos
[index
];
1791 DeserializeStructuredCloneFiles(database
, preprocessInfo
.files(),
1792 /* aForPreprocess */ true);
1794 MOZ_ASSERT(files
.Length() == 1);
1796 auto& preprocessHelper
= mCloneInfos
[index
].mPreprocessHelper
;
1797 preprocessHelper
= MakeRefPtr
<PreprocessHelper
>(index
, this);
1799 nsresult rv
= preprocessHelper
->Init(files
[0]);
1800 if (NS_WARN_IF(NS_FAILED(rv
))) {
1804 rv
= preprocessHelper
->Dispatch();
1805 if (NS_WARN_IF(NS_FAILED(rv
))) {
1809 mRunningPreprocessHelpers
++;
1815 void BackgroundRequestChild::ActorDestroy(ActorDestroyReason aWhy
) {
1816 AssertIsOnOwningThread();
1818 MaybeCollectGarbageOnIPCMessage();
1820 for (auto& cloneInfo
: mCloneInfos
) {
1821 const auto& preprocessHelper
= cloneInfo
.mPreprocessHelper
;
1823 if (preprocessHelper
) {
1824 preprocessHelper
->ClearActor();
1827 mCloneInfos
.Clear();
1830 mTransaction
->AssertIsOnOwningThread();
1832 mTransaction
->OnRequestFinished(/* aRequestCompletedSuccessfully */
1835 mTransaction
= nullptr;
1840 mozilla::ipc::IPCResult
BackgroundRequestChild::Recv__delete__(
1841 RequestResponse
&& aResponse
) {
1842 AssertIsOnOwningThread();
1843 MOZ_ASSERT(mTransaction
);
1845 MaybeCollectGarbageOnIPCMessage();
1847 if (mTransaction
->IsAborted()) {
1848 // Always fire an "error" event with ABORT_ERR if the transaction was
1849 // aborted, even if the request succeeded or failed with another error.
1850 HandleResponse(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR
);
1852 switch (aResponse
.type()) {
1853 case RequestResponse::Tnsresult
:
1854 HandleResponse(aResponse
.get_nsresult());
1857 case RequestResponse::TObjectStoreAddResponse
:
1858 HandleResponse(aResponse
.get_ObjectStoreAddResponse().key());
1861 case RequestResponse::TObjectStorePutResponse
:
1862 HandleResponse(aResponse
.get_ObjectStorePutResponse().key());
1865 case RequestResponse::TObjectStoreGetResponse
:
1867 std::move(aResponse
.get_ObjectStoreGetResponse().cloneInfo()));
1870 case RequestResponse::TObjectStoreGetKeyResponse
:
1871 HandleResponse(aResponse
.get_ObjectStoreGetKeyResponse().key());
1874 case RequestResponse::TObjectStoreGetAllResponse
:
1876 std::move(aResponse
.get_ObjectStoreGetAllResponse().cloneInfos()));
1879 case RequestResponse::TObjectStoreGetAllKeysResponse
:
1880 HandleResponse(aResponse
.get_ObjectStoreGetAllKeysResponse().keys());
1883 case RequestResponse::TObjectStoreDeleteResponse
:
1884 case RequestResponse::TObjectStoreClearResponse
:
1885 HandleResponse(JS::UndefinedHandleValue
);
1888 case RequestResponse::TObjectStoreCountResponse
:
1889 HandleResponse(aResponse
.get_ObjectStoreCountResponse().count());
1892 case RequestResponse::TIndexGetResponse
:
1893 HandleResponse(std::move(aResponse
.get_IndexGetResponse().cloneInfo()));
1896 case RequestResponse::TIndexGetKeyResponse
:
1897 HandleResponse(aResponse
.get_IndexGetKeyResponse().key());
1900 case RequestResponse::TIndexGetAllResponse
:
1902 std::move(aResponse
.get_IndexGetAllResponse().cloneInfos()));
1905 case RequestResponse::TIndexGetAllKeysResponse
:
1906 HandleResponse(aResponse
.get_IndexGetAllKeysResponse().keys());
1909 case RequestResponse::TIndexCountResponse
:
1910 HandleResponse(aResponse
.get_IndexCountResponse().count());
1914 return IPC_FAIL(this, "Unknown response type!");
1918 mTransaction
->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
1920 // Null this out so that we don't try to call OnRequestFinished() again in
1922 mTransaction
= nullptr;
1927 mozilla::ipc::IPCResult
BackgroundRequestChild::RecvPreprocess(
1928 const PreprocessParams
& aParams
) {
1929 AssertIsOnOwningThread();
1930 MOZ_ASSERT(mTransaction
);
1932 MaybeCollectGarbageOnIPCMessage();
1936 switch (aParams
.type()) {
1937 case PreprocessParams::TObjectStoreGetPreprocessParams
: {
1938 const auto& params
= aParams
.get_ObjectStoreGetPreprocessParams();
1940 rv
= HandlePreprocess(params
.preprocessInfo());
1945 case PreprocessParams::TObjectStoreGetAllPreprocessParams
: {
1946 const auto& params
= aParams
.get_ObjectStoreGetAllPreprocessParams();
1948 rv
= HandlePreprocess(params
.preprocessInfos());
1954 return IPC_FAIL(this, "Unknown params type!");
1957 if (NS_WARN_IF(NS_FAILED(rv
))) {
1958 QM_WARNONLY_TRY(OkIf(SendContinue(rv
)));
1964 nsresult
BackgroundRequestChild::PreprocessHelper::Init(
1965 const StructuredCloneFileChild
& aFile
) {
1966 AssertIsOnOwningThread();
1967 MOZ_ASSERT(aFile
.HasBlob());
1968 MOZ_ASSERT(aFile
.Type() == StructuredCloneFileBase::eStructuredClone
);
1969 MOZ_ASSERT(mState
== State::Initial
);
1971 // The stream transport service is used for asynchronous processing. It has a
1972 // threadpool with a high cap of 25 threads. Fortunately, the service can be
1973 // used on workers too.
1974 nsCOMPtr
<nsIEventTarget
> target
=
1975 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID
);
1978 // We use a TaskQueue here in order to be sure that the events are dispatched
1979 // in the correct order. This is not guaranteed in case we use the I/O thread
1981 mTaskQueue
= TaskQueue::Create(target
.forget(), "BackgroundRequestChild");
1983 ErrorResult errorResult
;
1985 nsCOMPtr
<nsIInputStream
> stream
;
1986 // XXX After Bug 1620560, MutableBlob is not needed here anymore.
1987 aFile
.MutableBlob().CreateInputStream(getter_AddRefs(stream
), errorResult
);
1988 if (NS_WARN_IF(errorResult
.Failed())) {
1989 return errorResult
.StealNSResult();
1992 mStream
= std::move(stream
);
1994 mCloneData
= MakeUnique
<JSStructuredCloneData
>(
1995 JS::StructuredCloneScope::DifferentProcessForIndexedDB
);
2000 nsresult
BackgroundRequestChild::PreprocessHelper::Dispatch() {
2001 AssertIsOnOwningThread();
2002 MOZ_ASSERT(mState
== State::Initial
);
2004 nsresult rv
= mTaskQueue
->Dispatch(this, NS_DISPATCH_NORMAL
);
2005 if (NS_WARN_IF(NS_FAILED(rv
))) {
2012 nsresult
BackgroundRequestChild::PreprocessHelper::Start() {
2013 MOZ_ASSERT(!IsOnOwningThread());
2014 MOZ_ASSERT(mStream
);
2015 MOZ_ASSERT(mState
== State::Initial
);
2019 PRFileDesc
* fileDesc
= GetFileDescriptorFromStream(mStream
);
2021 rv
= ProcessStream();
2022 if (NS_WARN_IF(NS_FAILED(rv
))) {
2029 mState
= State::WaitingForStreamReady
;
2031 nsCOMPtr
<nsIAsyncFileMetadata
> asyncFileMetadata
= do_QueryInterface(mStream
);
2032 if (asyncFileMetadata
) {
2033 rv
= asyncFileMetadata
->AsyncFileMetadataWait(this, mTaskQueue
);
2034 if (NS_WARN_IF(NS_FAILED(rv
))) {
2041 nsCOMPtr
<nsIAsyncInputStream
> asyncStream
= do_QueryInterface(mStream
);
2043 return NS_ERROR_NO_INTERFACE
;
2046 rv
= asyncStream
->AsyncWait(this, 0, 0, mTaskQueue
);
2047 if (NS_WARN_IF(NS_FAILED(rv
))) {
2054 nsresult
BackgroundRequestChild::PreprocessHelper::ProcessStream() {
2055 MOZ_ASSERT(!IsOnOwningThread());
2056 MOZ_ASSERT(mStream
);
2057 MOZ_ASSERT(mState
== State::Initial
||
2058 mState
== State::WaitingForStreamReady
);
2060 // We need to get the internal stream (which is an nsFileInputStream) because
2061 // SnappyUncompressInputStream doesn't support reading from async input
2064 nsCOMPtr
<mozIRemoteLazyInputStream
> blobInputStream
=
2065 do_QueryInterface(mStream
);
2066 MOZ_ASSERT(blobInputStream
);
2068 nsCOMPtr
<nsIInputStream
> internalInputStream
;
2069 MOZ_ALWAYS_SUCCEEDS(
2070 blobInputStream
->TakeInternalStream(getter_AddRefs(internalInputStream
)));
2071 MOZ_ASSERT(internalInputStream
);
2073 QM_TRY(MOZ_TO_RESULT(
2074 SnappyUncompressStructuredCloneData(*internalInputStream
, *mCloneData
)));
2076 mState
= State::Finishing
;
2078 QM_TRY(MOZ_TO_RESULT(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
)));
2083 void BackgroundRequestChild::PreprocessHelper::Finish() {
2084 AssertIsOnOwningThread();
2087 if (NS_SUCCEEDED(mResultCode
)) {
2088 mActor
->OnPreprocessFinished(mCloneDataIndex
, std::move(mCloneData
));
2090 MOZ_ASSERT(!mCloneData
);
2092 mActor
->OnPreprocessFailed(mCloneDataIndex
, mResultCode
);
2096 mState
= State::Completed
;
2099 NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper
,
2100 DiscardableRunnable
, nsIInputStreamCallback
,
2101 nsIFileMetadataCallback
)
2104 BackgroundRequestChild::PreprocessHelper::Run() {
2108 case State::Initial
:
2112 case State::WaitingForStreamReady
:
2113 rv
= ProcessStream();
2116 case State::Finishing
:
2121 MOZ_CRASH("Bad state!");
2124 if (NS_WARN_IF(NS_FAILED(rv
)) && mState
!= State::Finishing
) {
2125 if (NS_SUCCEEDED(mResultCode
)) {
2129 // Must set mState before dispatching otherwise we will race with the owning
2131 mState
= State::Finishing
;
2133 if (IsOnOwningThread()) {
2136 MOZ_ALWAYS_SUCCEEDS(
2137 mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
2145 BackgroundRequestChild::PreprocessHelper::OnInputStreamReady(
2146 nsIAsyncInputStream
* aStream
) {
2147 MOZ_ASSERT(!IsOnOwningThread());
2148 MOZ_ASSERT(mState
== State::WaitingForStreamReady
);
2150 MOZ_ALWAYS_SUCCEEDS(this->Run());
2156 BackgroundRequestChild::PreprocessHelper::OnFileMetadataReady(
2157 nsIAsyncFileMetadata
* aObject
) {
2158 MOZ_ASSERT(!IsOnOwningThread());
2159 MOZ_ASSERT(mState
== State::WaitingForStreamReady
);
2161 MOZ_ALWAYS_SUCCEEDS(this->Run());
2166 /*******************************************************************************
2167 * BackgroundCursorChild
2168 ******************************************************************************/
2170 BackgroundCursorChildBase::BackgroundCursorChildBase(
2171 const NotNull
<IDBRequest
*> aRequest
, const Direction aDirection
)
2172 : mRequest(aRequest
),
2173 mTransaction(aRequest
->MaybeTransactionRef()),
2174 mStrongRequest(aRequest
),
2175 mDirection(aDirection
) {
2176 MOZ_ASSERT(mTransaction
);
2179 MovingNotNull
<RefPtr
<IDBRequest
>> BackgroundCursorChildBase::AcquireRequest()
2181 AssertIsOnOwningThread();
2183 // XXX This could be encapsulated by NotNull
2184 return WrapNotNullUnchecked(RefPtr
{mRequest
->get()});
2187 template <IDBCursorType CursorType
>
2188 BackgroundCursorChild
<CursorType
>::BackgroundCursorChild(
2189 const NotNull
<IDBRequest
*> aRequest
, SourceType
* aSource
,
2190 Direction aDirection
)
2191 : BackgroundCursorChildBase(aRequest
, aDirection
),
2192 mSource(WrapNotNull(aSource
)),
2194 mInFlightResponseInvalidationNeeded(false) {
2195 aSource
->AssertIsOnOwningThread();
2197 MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild
<CursorType
>);
2200 template <IDBCursorType CursorType
>
2201 BackgroundCursorChild
<CursorType
>::~BackgroundCursorChild() {
2202 MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild
<CursorType
>);
2205 template <IDBCursorType CursorType
>
2206 SafeRefPtr
<BackgroundCursorChild
<CursorType
>>
2207 BackgroundCursorChild
<CursorType
>::SafeRefPtrFromThis() {
2208 return BackgroundCursorChildBase::SafeRefPtrFromThis()
2209 .template downcast
<BackgroundCursorChild
>();
2212 template <IDBCursorType CursorType
>
2213 void BackgroundCursorChild
<CursorType
>::SendContinueInternal(
2214 const CursorRequestParams
& aParams
,
2215 const CursorData
<CursorType
>& aCurrentData
) {
2216 AssertIsOnOwningThread();
2217 MOZ_ASSERT(mRequest
);
2218 MOZ_ASSERT(mTransaction
);
2219 MOZ_ASSERT(mCursor
);
2220 MOZ_ASSERT(!mStrongRequest
);
2221 MOZ_ASSERT(!mStrongCursor
);
2223 // Make sure all our DOM objects stay alive.
2224 mStrongCursor
= mCursor
;
2226 MOZ_ASSERT(GetRequest()->ReadyState() == IDBRequestReadyState::Done
);
2227 GetRequest()->Reset();
2229 mTransaction
->OnNewRequest();
2231 CursorRequestParams params
= aParams
;
2232 Key currentKey
= aCurrentData
.mKey
;
2233 Key currentObjectStoreKey
;
2234 // TODO: This is still not nice.
2235 if constexpr (!CursorTypeTraits
<CursorType
>::IsObjectStoreCursor
) {
2236 currentObjectStoreKey
= aCurrentData
.mObjectStoreKey
;
2239 switch (params
.type()) {
2240 case CursorRequestParams::TContinueParams
: {
2241 const auto& key
= params
.get_ContinueParams().key();
2242 if (key
.IsUnset()) {
2246 // Discard cache entries before the target key.
2247 DiscardCachedResponses(
2248 [&key
, isLocaleAware
= mCursor
->IsLocaleAware(),
2249 keyOperator
= GetKeyOperator(mDirection
),
2250 transactionSerialNumber
= mTransaction
->LoggingSerialNumber(),
2251 requestSerialNumber
= GetRequest()->LoggingSerialNumber()](
2252 const auto& currentCachedResponse
) {
2253 // This duplicates the logic from the parent. We could avoid this
2254 // duplication if we invalidated the cached records always for any
2255 // continue-with-key operation, but would lose the benefits of
2257 const auto& cachedSortKey
=
2258 currentCachedResponse
.GetSortKey(isLocaleAware
);
2259 const bool discard
= !(cachedSortKey
.*keyOperator
)(key
);
2261 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2262 "PRELOAD: Continue to key %s, discarding cached key %s/%s",
2263 "Continue, discarding%.0s%.0s%.0s", transactionSerialNumber
,
2264 requestSerialNumber
, key
.GetBuffer().get(),
2265 cachedSortKey
.GetBuffer().get(),
2266 currentCachedResponse
.GetObjectStoreKeyForLogging());
2268 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2269 "PRELOAD: Continue to key %s, keeping cached key %s/%s and "
2271 "Continue, keeping%.0s%.0s%.0s", transactionSerialNumber
,
2272 requestSerialNumber
, key
.GetBuffer().get(),
2273 cachedSortKey
.GetBuffer().get(),
2274 currentCachedResponse
.GetObjectStoreKeyForLogging());
2283 case CursorRequestParams::TContinuePrimaryKeyParams
: {
2284 if constexpr (!CursorTypeTraits
<CursorType
>::IsObjectStoreCursor
) {
2285 const auto& key
= params
.get_ContinuePrimaryKeyParams().key();
2286 const auto& primaryKey
=
2287 params
.get_ContinuePrimaryKeyParams().primaryKey();
2288 if (key
.IsUnset() || primaryKey
.IsUnset()) {
2292 // Discard cache entries before the target key.
2293 DiscardCachedResponses([&key
, &primaryKey
,
2294 isLocaleAware
= mCursor
->IsLocaleAware(),
2295 keyCompareOperator
= GetKeyOperator(mDirection
),
2296 transactionSerialNumber
=
2297 mTransaction
->LoggingSerialNumber(),
2298 requestSerialNumber
=
2299 GetRequest()->LoggingSerialNumber()](
2300 const auto& currentCachedResponse
) {
2301 // This duplicates the logic from the parent. We could avoid this
2302 // duplication if we invalidated the cached records always for any
2303 // continue-with-key operation, but would lose the benefits of
2305 const auto& cachedSortKey
=
2306 currentCachedResponse
.GetSortKey(isLocaleAware
);
2307 const auto& cachedSortPrimaryKey
=
2308 currentCachedResponse
.mObjectStoreKey
;
2310 const bool discard
=
2311 (cachedSortKey
== key
&&
2312 !(cachedSortPrimaryKey
.*keyCompareOperator
)(primaryKey
)) ||
2313 !(cachedSortKey
.*keyCompareOperator
)(key
);
2316 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2317 "PRELOAD: Continue to key %s with primary key %s, discarding "
2318 "cached key %s with cached primary key %s",
2319 "Continue, discarding%.0s%.0s%.0s%.0s", transactionSerialNumber
,
2320 requestSerialNumber
, key
.GetBuffer().get(),
2321 primaryKey
.GetBuffer().get(), cachedSortKey
.GetBuffer().get(),
2322 cachedSortPrimaryKey
.GetBuffer().get());
2324 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2325 "PRELOAD: Continue to key %s with primary key %s, keeping "
2326 "cached key %s with cached primary key %s and further",
2327 "Continue, keeping%.0s%.0s%.0s%.0s", transactionSerialNumber
,
2328 requestSerialNumber
, key
.GetBuffer().get(),
2329 primaryKey
.GetBuffer().get(), cachedSortKey
.GetBuffer().get(),
2330 cachedSortPrimaryKey
.GetBuffer().get());
2336 MOZ_CRASH("Shouldn't get here");
2342 case CursorRequestParams::TAdvanceParams
: {
2343 uint32_t& advanceCount
= params
.get_AdvanceParams().count();
2344 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2345 "PRELOAD: Advancing %" PRIu32
" records", "Advancing %" PRIu32
,
2346 mTransaction
->LoggingSerialNumber(),
2347 GetRequest()->LoggingSerialNumber(), advanceCount
);
2349 // Discard cache entries.
2350 DiscardCachedResponses([&advanceCount
, ¤tKey
,
2351 ¤tObjectStoreKey
](
2352 const auto& currentCachedResponse
) {
2353 const bool res
= advanceCount
> 1;
2357 // TODO: We only need to update currentKey on the last entry, the
2358 // others are overwritten in the next iteration anyway.
2359 currentKey
= currentCachedResponse
.mKey
;
2360 if constexpr (!CursorTypeTraits
<CursorType
>::IsObjectStoreCursor
) {
2361 currentObjectStoreKey
= currentCachedResponse
.mObjectStoreKey
;
2363 Unused
<< currentObjectStoreKey
;
2372 MOZ_CRASH("Should never get here!");
2375 if (!mCachedResponses
.empty()) {
2376 // We need to remove the response here from mCachedResponses, since when
2377 // requests are interleaved, other events may be processed before
2378 // CompleteContinueRequestFromCache, which may modify mCachedResponses.
2379 mDelayedResponses
.emplace_back(std::move(mCachedResponses
.front()));
2380 mCachedResponses
.pop_front();
2382 // We cannot send the response right away, as we must preserve the request
2383 // order. Dispatching a DelayedActionRunnable only partially addresses this.
2384 // This is accompanied by invalidating cached entries at proper locations to
2385 // make it correct. To avoid this, further changes are necessary, see Bug
2387 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(
2388 MakeAndAddRef
<DelayedActionRunnable
<BackgroundCursorChild
<CursorType
>>>(
2389 SafeRefPtrFromThis(),
2390 &BackgroundCursorChild::CompleteContinueRequestFromCache
)));
2392 // TODO: Could we preload further entries in the background when the size of
2393 // mCachedResponses falls under some threshold? Or does the response
2394 // handling model disallow this?
2396 MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(
2397 params
, currentKey
, currentObjectStoreKey
));
2401 template <IDBCursorType CursorType
>
2402 void BackgroundCursorChild
<CursorType
>::CompleteContinueRequestFromCache() {
2403 AssertIsOnOwningThread();
2404 MOZ_ASSERT(mTransaction
);
2405 MOZ_ASSERT(mCursor
);
2406 MOZ_ASSERT(mStrongCursor
);
2407 MOZ_ASSERT(!mDelayedResponses
.empty());
2408 MOZ_ASSERT(mCursor
->GetType() == CursorType
);
2410 const RefPtr
<IDBCursor
> cursor
= std::move(mStrongCursor
);
2412 mCursor
->Reset(std::move(mDelayedResponses
.front()));
2413 mDelayedResponses
.pop_front();
2415 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2416 "PRELOAD: Consumed 1 cached response, %zu cached responses remaining",
2417 "Consumed cached response, %zu remaining",
2418 mTransaction
->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
2419 mDelayedResponses
.size() + mCachedResponses
.size());
2421 SetResultAndDispatchSuccessEvent(
2424 ? SafeRefPtr
{&mTransaction
.ref(), AcquireStrongRefFromRawPtr
{}}
2428 mTransaction
->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
2431 template <IDBCursorType CursorType
>
2432 void BackgroundCursorChild
<CursorType
>::SendDeleteMeInternal() {
2433 AssertIsOnOwningThread();
2434 MOZ_ASSERT(!mStrongRequest
);
2435 MOZ_ASSERT(!mStrongCursor
);
2438 mTransaction
= Nothing();
2439 // TODO: The things until here could be pulled up to
2440 // BackgroundCursorChildBase.
2445 mCursor
->ClearBackgroundActor();
2448 MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendDeleteMe());
2452 template <IDBCursorType CursorType
>
2453 void BackgroundCursorChild
<CursorType
>::InvalidateCachedResponses() {
2454 AssertIsOnOwningThread();
2455 MOZ_ASSERT(mTransaction
);
2456 MOZ_ASSERT(mRequest
);
2458 // TODO: With more information on the reason for the invalidation, we might
2459 // only selectively invalidate cached responses. If the reason is an updated
2460 // value, we do not need to care for key-only cursors. If the key of the
2461 // changed entry is not in the remaining range of the cursor, we also do not
2462 // need to care, etc.
2464 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2465 "PRELOAD: Invalidating all %zu cached responses", "Invalidating %zu",
2466 mTransaction
->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
2467 mCachedResponses
.size());
2469 mCachedResponses
.clear();
2471 // We only hold a strong cursor reference in mStrongCursor when
2472 // continue()/similar has been called. In those cases we expect a response
2473 // that will be received in the future, and it may include prefetched data
2474 // that needs to be discarded.
2475 if (mStrongCursor
) {
2476 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2477 "PRELOAD: Setting flag to invalidate in-flight responses",
2478 "Set flag to invalidate in-flight responses",
2479 mTransaction
->LoggingSerialNumber(),
2480 GetRequest()->LoggingSerialNumber());
2482 mInFlightResponseInvalidationNeeded
= true;
2486 template <IDBCursorType CursorType
>
2487 template <typename Condition
>
2488 void BackgroundCursorChild
<CursorType
>::DiscardCachedResponses(
2489 const Condition
& aConditionFunc
) {
2490 size_t discardedCount
= 0;
2491 while (!mCachedResponses
.empty() &&
2492 aConditionFunc(mCachedResponses
.front())) {
2493 mCachedResponses
.pop_front();
2496 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2497 "PRELOAD: Discarded %zu cached responses, %zu remaining",
2498 "Discarded %zu; remaining %zu", mTransaction
->LoggingSerialNumber(),
2499 GetRequest()->LoggingSerialNumber(), discardedCount
,
2500 mCachedResponses
.size());
2503 BackgroundCursorChildBase::~BackgroundCursorChildBase() = default;
2505 void BackgroundCursorChildBase::HandleResponse(nsresult aResponse
) {
2506 AssertIsOnOwningThread();
2507 MOZ_ASSERT(NS_FAILED(aResponse
));
2508 MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse
) == NS_ERROR_MODULE_DOM_INDEXEDDB
);
2509 MOZ_ASSERT(mRequest
);
2510 MOZ_ASSERT(mTransaction
);
2511 MOZ_ASSERT(!mStrongRequest
);
2512 MOZ_ASSERT(!mStrongCursor
);
2515 GetRequest(), aResponse
,
2516 SafeRefPtr
{&mTransaction
.ref(), AcquireStrongRefFromRawPtr
{}});
2519 template <IDBCursorType CursorType
>
2520 void BackgroundCursorChild
<CursorType
>::HandleResponse(
2521 const void_t
& aResponse
) {
2522 AssertIsOnOwningThread();
2523 MOZ_ASSERT(mRequest
);
2524 MOZ_ASSERT(mTransaction
);
2525 MOZ_ASSERT(!mStrongRequest
);
2526 MOZ_ASSERT(!mStrongCursor
);
2532 SetResultAndDispatchSuccessEvent(
2535 ? SafeRefPtr
{&mTransaction
.ref(), AcquireStrongRefFromRawPtr
{}}
2537 JS::NullHandleValue
);
2540 MOZ_ALWAYS_SUCCEEDS(this->GetActorEventTarget()->Dispatch(
2541 MakeAndAddRef
<DelayedActionRunnable
<BackgroundCursorChild
<CursorType
>>>(
2542 SafeRefPtrFromThis(), &BackgroundCursorChild::SendDeleteMeInternal
),
2543 NS_DISPATCH_NORMAL
));
2547 template <IDBCursorType CursorType
>
2548 template <typename
... Args
>
2550 BackgroundCursorChild
<CursorType
>::HandleIndividualCursorResponse(
2551 const bool aUseAsCurrentResult
, Args
&&... aArgs
) {
2553 if (aUseAsCurrentResult
) {
2554 mCursor
->Reset(CursorData
<CursorType
>{std::forward
<Args
>(aArgs
)...});
2556 mCachedResponses
.emplace_back(std::forward
<Args
>(aArgs
)...);
2561 MOZ_ASSERT(aUseAsCurrentResult
);
2563 // TODO: This still looks quite dangerous to me. Why is mCursor not a
2565 auto newCursor
= IDBCursor::Create(this, std::forward
<Args
>(aArgs
)...);
2566 mCursor
= newCursor
;
2570 template <IDBCursorType CursorType
>
2571 template <typename Func
>
2572 void BackgroundCursorChild
<CursorType
>::HandleMultipleCursorResponses(
2573 nsTArray
<ResponseType
>&& aResponses
, const Func
& aHandleRecord
) {
2574 AssertIsOnOwningThread();
2575 MOZ_ASSERT(mRequest
);
2576 MOZ_ASSERT(mTransaction
);
2577 MOZ_ASSERT(!mStrongRequest
);
2578 MOZ_ASSERT(!mStrongCursor
);
2579 MOZ_ASSERT(aResponses
.Length() > 0);
2581 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2582 "PRELOAD: Received %zu cursor responses", "Received %zu",
2583 mTransaction
->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
2584 aResponses
.Length());
2585 MOZ_ASSERT_IF(aResponses
.Length() > 1, mCachedResponses
.empty());
2587 // If a new cursor is created, we need to keep a reference to it until the
2588 // SetResultAndDispatchSuccessEvent creates a DOM Binding.
2589 RefPtr
<IDBCursor
> strongNewCursor
;
2591 bool isFirst
= true;
2592 for (auto& response
: aResponses
) {
2593 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2594 "PRELOAD: Processing response for key %s", "Processing%.0s",
2595 mTransaction
->LoggingSerialNumber(),
2596 GetRequest()->LoggingSerialNumber(), response
.key().GetBuffer().get());
2598 // TODO: At the moment, we only send a cursor request to the parent if
2599 // requested by the user code. Therefore, the first result is always used
2600 // as the current result, and the potential extra results are cached. If
2601 // we extended this towards preloading in the background, all results
2602 // might need to be cached.
2603 auto maybeNewCursor
=
2604 aHandleRecord(/* aUseAsCurrentResult */ isFirst
, std::move(response
));
2605 if (maybeNewCursor
) {
2606 MOZ_ASSERT(!strongNewCursor
);
2607 strongNewCursor
= std::move(maybeNewCursor
);
2611 if (mInFlightResponseInvalidationNeeded
) {
2612 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
2613 "PRELOAD: Discarding remaining responses since "
2614 "mInFlightResponseInvalidationNeeded is set",
2615 "Discarding responses", mTransaction
->LoggingSerialNumber(),
2616 GetRequest()->LoggingSerialNumber());
2618 mInFlightResponseInvalidationNeeded
= false;
2623 SetResultAndDispatchSuccessEvent(
2626 ? SafeRefPtr
{&mTransaction
.ref(), AcquireStrongRefFromRawPtr
{}}
2628 *static_cast<IDBCursor
*>(mCursor
));
2631 template <IDBCursorType CursorType
>
2632 void BackgroundCursorChild
<CursorType
>::HandleResponse(
2633 nsTArray
<ResponseType
>&& aResponses
) {
2634 AssertIsOnOwningThread();
2636 if constexpr (CursorType
== IDBCursorType::ObjectStore
||
2637 CursorType
== IDBCursorType::Index
) {
2638 MOZ_ASSERT(mTransaction
);
2640 if (!mTransaction
->Database()->GetOwnerGlobal()) {
2641 // Ignore the response, since we have already been disconnected from the
2647 if constexpr (CursorType
== IDBCursorType::ObjectStore
) {
2648 HandleMultipleCursorResponses(
2649 std::move(aResponses
), [this](const bool useAsCurrentResult
,
2650 ObjectStoreCursorResponse
&& response
) {
2651 // TODO: Maybe move the deserialization of the clone-read-info into
2652 // the cursor, so that it is only done for records actually accessed,
2653 // which might not be the case for all cached records.
2654 return HandleIndividualCursorResponse(
2655 useAsCurrentResult
, std::move(response
.key()),
2656 DeserializeStructuredCloneReadInfo(
2657 std::move(response
.cloneInfo()), mTransaction
->Database(),
2658 PreprocessingNotSupported
));
2661 if constexpr (CursorType
== IDBCursorType::ObjectStoreKey
) {
2662 HandleMultipleCursorResponses(
2663 std::move(aResponses
), [this](const bool useAsCurrentResult
,
2664 ObjectStoreKeyCursorResponse
&& response
) {
2665 return HandleIndividualCursorResponse(useAsCurrentResult
,
2666 std::move(response
.key()));
2669 if constexpr (CursorType
== IDBCursorType::Index
) {
2670 HandleMultipleCursorResponses(
2671 std::move(aResponses
),
2672 [this](const bool useAsCurrentResult
, IndexCursorResponse
&& response
) {
2673 return HandleIndividualCursorResponse(
2674 useAsCurrentResult
, std::move(response
.key()),
2675 std::move(response
.sortKey()), std::move(response
.objectKey()),
2676 DeserializeStructuredCloneReadInfo(
2677 std::move(response
.cloneInfo()), mTransaction
->Database(),
2678 PreprocessingNotSupported
));
2681 if constexpr (CursorType
== IDBCursorType::IndexKey
) {
2682 HandleMultipleCursorResponses(
2683 std::move(aResponses
), [this](const bool useAsCurrentResult
,
2684 IndexKeyCursorResponse
&& response
) {
2685 return HandleIndividualCursorResponse(
2686 useAsCurrentResult
, std::move(response
.key()),
2687 std::move(response
.sortKey()), std::move(response
.objectKey()));
2692 template <IDBCursorType CursorType
>
2693 void BackgroundCursorChild
<CursorType
>::ActorDestroy(ActorDestroyReason aWhy
) {
2694 AssertIsOnOwningThread();
2695 MOZ_ASSERT_IF(aWhy
== Deletion
, !mStrongRequest
);
2696 MOZ_ASSERT_IF(aWhy
== Deletion
, !mStrongCursor
);
2698 MaybeCollectGarbageOnIPCMessage();
2700 if (mStrongRequest
&& !mStrongCursor
&& mTransaction
) {
2701 mTransaction
->OnRequestFinished(/* aRequestCompletedSuccessfully */
2706 mCursor
->ClearBackgroundActor();
2713 mRequest
.maybeDestroy();
2714 mTransaction
= Nothing();
2715 mSource
.maybeDestroy();
2719 template <IDBCursorType CursorType
>
2720 mozilla::ipc::IPCResult BackgroundCursorChild
<CursorType
>::RecvResponse(
2721 CursorResponse
&& aResponse
) {
2722 AssertIsOnOwningThread();
2723 MOZ_ASSERT(aResponse
.type() != CursorResponse::T__None
);
2724 MOZ_ASSERT(mRequest
);
2725 MOZ_ASSERT(mTransaction
);
2726 MOZ_ASSERT_IF(mCursor
, mStrongCursor
);
2727 MOZ_ASSERT_IF(!mCursor
, mStrongRequest
);
2729 MaybeCollectGarbageOnIPCMessage();
2731 const RefPtr
<IDBRequest
> request
= std::move(mStrongRequest
);
2732 Unused
<< request
; // XXX see Bug 1605075
2733 const RefPtr
<IDBCursor
> cursor
= std::move(mStrongCursor
);
2734 Unused
<< cursor
; // XXX see Bug 1605075
2736 const auto transaction
=
2737 SafeRefPtr
{&mTransaction
.ref(), AcquireStrongRefFromRawPtr
{}};
2739 switch (aResponse
.type()) {
2740 case CursorResponse::Tnsresult
:
2741 HandleResponse(aResponse
.get_nsresult());
2744 case CursorResponse::Tvoid_t
:
2745 HandleResponse(aResponse
.get_void_t());
2748 case CursorResponse::TArrayOfObjectStoreCursorResponse
:
2749 if constexpr (CursorType
== IDBCursorType::ObjectStore
) {
2751 std::move(aResponse
.get_ArrayOfObjectStoreCursorResponse()));
2753 MOZ_CRASH("Response type mismatch");
2757 case CursorResponse::TArrayOfObjectStoreKeyCursorResponse
:
2758 if constexpr (CursorType
== IDBCursorType::ObjectStoreKey
) {
2760 std::move(aResponse
.get_ArrayOfObjectStoreKeyCursorResponse()));
2762 MOZ_CRASH("Response type mismatch");
2766 case CursorResponse::TArrayOfIndexCursorResponse
:
2767 if constexpr (CursorType
== IDBCursorType::Index
) {
2768 HandleResponse(std::move(aResponse
.get_ArrayOfIndexCursorResponse()));
2770 MOZ_CRASH("Response type mismatch");
2774 case CursorResponse::TArrayOfIndexKeyCursorResponse
:
2775 if constexpr (CursorType
== IDBCursorType::IndexKey
) {
2777 std::move(aResponse
.get_ArrayOfIndexKeyCursorResponse()));
2779 MOZ_CRASH("Response type mismatch");
2784 MOZ_CRASH("Should never get here!");
2787 transaction
->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
2792 template class BackgroundCursorChild
<IDBCursorType::ObjectStore
>;
2793 template class BackgroundCursorChild
<IDBCursorType::ObjectStoreKey
>;
2794 template class BackgroundCursorChild
<IDBCursorType::Index
>;
2795 template class BackgroundCursorChild
<IDBCursorType::IndexKey
>;
2797 template <typename T
>
2798 NS_IMETHODIMP DelayedActionRunnable
<T
>::Run() {
2800 mActor
->AssertIsOnOwningThread();
2801 MOZ_ASSERT(mRequest
);
2802 MOZ_ASSERT(mActionFunc
);
2804 ((*mActor
).*mActionFunc
)();
2812 template <typename T
>
2813 nsresult DelayedActionRunnable
<T
>::Cancel() {
2814 if (NS_WARN_IF(!mActor
)) {
2815 return NS_ERROR_UNEXPECTED
;
2818 // This must always run to clean up our state.
2824 /*******************************************************************************
2825 * BackgroundUtilsChild
2826 ******************************************************************************/
2828 BackgroundUtilsChild::BackgroundUtilsChild(IndexedDatabaseManager
* aManager
)
2829 : mManager(aManager
) {
2830 AssertIsOnOwningThread();
2831 MOZ_ASSERT(aManager
);
2833 MOZ_COUNT_CTOR(indexedDB::BackgroundUtilsChild
);
2836 BackgroundUtilsChild::~BackgroundUtilsChild() {
2837 MOZ_COUNT_DTOR(indexedDB::BackgroundUtilsChild
);
2840 void BackgroundUtilsChild::SendDeleteMeInternal() {
2841 AssertIsOnOwningThread();
2844 mManager
->ClearBackgroundActor();
2847 MOZ_ALWAYS_TRUE(PBackgroundIndexedDBUtilsChild::SendDeleteMe());
2851 void BackgroundUtilsChild::ActorDestroy(ActorDestroyReason aWhy
) {
2852 AssertIsOnOwningThread();
2855 mManager
->ClearBackgroundActor();
2862 } // namespace dom::indexedDB
2863 } // namespace mozilla