summaryrefslogtreecommitdiffstats
path: root/dom/indexedDB/ActorsParent.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /dom/indexedDB/ActorsParent.cpp
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/indexedDB/ActorsParent.cpp')
-rw-r--r--dom/indexedDB/ActorsParent.cpp1128
1 files changed, 862 insertions, 266 deletions
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 47360094ca..6609ea5b81 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -94,6 +94,7 @@
#include "mozilla/dom/FileBlobImpl.h"
#include "mozilla/dom/FlippedOnce.h"
#include "mozilla/dom/IDBCursorBinding.h"
+#include "mozilla/dom/IDBFactory.h"
#include "mozilla/dom/IPCBlob.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/IndexedDatabase.h"
@@ -122,6 +123,7 @@
#include "mozilla/dom/quota/CheckedUnsafePtr.h"
#include "mozilla/dom/quota/Client.h"
#include "mozilla/dom/quota/ClientImpl.h"
+#include "mozilla/dom/quota/DebugOnlyMacro.h"
#include "mozilla/dom/quota/DirectoryLock.h"
#include "mozilla/dom/quota/DecryptingInputStream_impl.h"
#include "mozilla/dom/quota/EncryptingOutputStream_impl.h"
@@ -1973,6 +1975,10 @@ class TransactionDatabaseOperationBase : public DatabaseOperationBase {
};
InitializedOnce<const NotNull<SafeRefPtr<TransactionBase>>> mTransaction;
+ // Unique request id within the context of the transaction, allocated by the
+ // transaction in the content process starting from 0. Values less than 0 are
+ // impossible and forbidden. Used to support the explicit commit() request.
+ const int64_t mRequestId;
InternalState mInternalState = InternalState::Initial;
bool mWaitingForContinue = false;
const bool mTransactionIsAborted;
@@ -2034,10 +2040,11 @@ class TransactionDatabaseOperationBase : public DatabaseOperationBase {
virtual void Cleanup();
protected:
- explicit TransactionDatabaseOperationBase(
- SafeRefPtr<TransactionBase> aTransaction);
+ TransactionDatabaseOperationBase(SafeRefPtr<TransactionBase> aTransaction,
+ int64_t aRequestId);
TransactionDatabaseOperationBase(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
uint64_t aLoggingSerialNumber);
~TransactionDatabaseOperationBase() override;
@@ -2141,6 +2148,14 @@ class Factory final : public PBackgroundIDBFactoryParent,
bool DeallocPBackgroundIDBFactoryRequestParent(
PBackgroundIDBFactoryRequestParent* aActor) override;
+
+ mozilla::ipc::IPCResult RecvGetDatabases(
+ const PersistenceType& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ GetDatabasesResolver&& aResolve) override;
+
+ private:
+ Maybe<ContentParentId> GetContentParentId() const;
};
class WaitForTransactionsHelper final : public Runnable {
@@ -2395,11 +2410,13 @@ class Database final
already_AddRefed<PBackgroundIDBTransactionParent>
AllocPBackgroundIDBTransactionParent(
- const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode) override;
+ const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode,
+ const Durability& aDurability) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBTransactionConstructor(
PBackgroundIDBTransactionParent* aActor,
- nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode) override;
+ nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode,
+ const Durability& aDurability) override;
mozilla::ipc::IPCResult RecvDeleteMe() override;
@@ -2418,6 +2435,7 @@ class Database::StartTransactionOp final
private:
explicit StartTransactionOp(SafeRefPtr<TransactionBase> aTransaction)
: TransactionDatabaseOperationBase(std::move(aTransaction),
+ /* aRequestId */ 0,
/* aLoggingSerialNumber */ 0) {}
~StartTransactionOp() override = default;
@@ -2591,6 +2609,7 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
protected:
using Mode = IDBTransaction::Mode;
+ using Durability = IDBTransaction::Durability;
private:
const SafeRefPtr<Database> mDatabase;
@@ -2602,6 +2621,7 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
uint64_t mActiveRequestCount;
Atomic<bool> mInvalidatedOnAnyThread;
const Mode mMode;
+ const Durability mDurability; // TODO: See bug 1883045
FlippedOnce<false> mInitialized;
FlippedOnce<false> mHasBeenActiveOnConnectionThread;
FlippedOnce<false> mActorDestroyed;
@@ -2661,6 +2681,8 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
Mode GetMode() const { return mMode; }
+ Durability GetDurability() const { return mDurability; }
+
const Database& GetDatabase() const {
MOZ_ASSERT(mDatabase);
@@ -2723,7 +2745,8 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
virtual ~TransactionBase();
protected:
- TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode);
+ TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode,
+ Durability aDurability);
void NoteActorDestroyed() {
AssertIsOnBackgroundThread();
@@ -2765,7 +2788,8 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
CommitOrAbort();
}
- PBackgroundIDBRequestParent* AllocRequest(RequestParams&& aParams,
+ PBackgroundIDBRequestParent* AllocRequest(const int64_t aRequestId,
+ RequestParams&& aParams,
bool aTrustParams);
bool StartRequest(PBackgroundIDBRequestParent* aActor);
@@ -2775,7 +2799,7 @@ class TransactionBase : public AtomicSafeRefCounted<TransactionBase> {
already_AddRefed<PBackgroundIDBCursorParent> AllocCursor(
const OpenCursorParams& aParams, bool aTrustParams);
- bool StartCursor(PBackgroundIDBCursorParent* aActor,
+ bool StartCursor(PBackgroundIDBCursorParent* aActor, const int64_t aRequestId,
const OpenCursorParams& aParams);
virtual void UpdateMetadata(nsresult aResult) {}
@@ -2858,26 +2882,27 @@ class NormalTransaction final : public TransactionBase,
mozilla::ipc::IPCResult RecvAbort(const nsresult& aResultCode) override;
PBackgroundIDBRequestParent* AllocPBackgroundIDBRequestParent(
- const RequestParams& aParams) override;
+ const int64_t& aRequestId, const RequestParams& aParams) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBRequestConstructor(
- PBackgroundIDBRequestParent* aActor,
+ PBackgroundIDBRequestParent* aActor, const int64_t& aRequestId,
const RequestParams& aParams) override;
bool DeallocPBackgroundIDBRequestParent(
PBackgroundIDBRequestParent* aActor) override;
already_AddRefed<PBackgroundIDBCursorParent> AllocPBackgroundIDBCursorParent(
- const OpenCursorParams& aParams) override;
+ const int64_t& aRequestId, const OpenCursorParams& aParams) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBCursorConstructor(
- PBackgroundIDBCursorParent* aActor,
+ PBackgroundIDBCursorParent* aActor, const int64_t& aRequestId,
const OpenCursorParams& aParams) override;
public:
// This constructor is only called by Database.
NormalTransaction(
SafeRefPtr<Database> aDatabase, TransactionBase::Mode aMode,
+ TransactionBase::Durability aDurability,
nsTArray<SafeRefPtr<FullObjectStoreMetadata>>&& aObjectStores);
MOZ_INLINE_DECL_SAFEREFCOUNTING_INHERITED(NormalTransaction, TransactionBase)
@@ -2950,26 +2975,25 @@ class VersionChangeTransaction final
const IndexOrObjectStoreId& aIndexId, const nsAString& aName) override;
PBackgroundIDBRequestParent* AllocPBackgroundIDBRequestParent(
- const RequestParams& aParams) override;
+ const int64_t& aRequestId, const RequestParams& aParams) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBRequestConstructor(
- PBackgroundIDBRequestParent* aActor,
+ PBackgroundIDBRequestParent* aActor, const int64_t& aRequestId,
const RequestParams& aParams) override;
bool DeallocPBackgroundIDBRequestParent(
PBackgroundIDBRequestParent* aActor) override;
already_AddRefed<PBackgroundIDBCursorParent> AllocPBackgroundIDBCursorParent(
- const OpenCursorParams& aParams) override;
+ const int64_t& aRequestId, const OpenCursorParams& aParams) override;
mozilla::ipc::IPCResult RecvPBackgroundIDBCursorConstructor(
- PBackgroundIDBCursorParent* aActor,
+ PBackgroundIDBCursorParent* aActor, const int64_t& aRequestId,
const OpenCursorParams& aParams) override;
};
class FactoryOp
: public DatabaseOperationBase,
- public PBackgroundIDBFactoryRequestParent,
public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> {
public:
struct MaybeBlockedDatabaseInfo final {
@@ -3008,9 +3032,20 @@ class FactoryOp
// Waiting for directory open allowed on the PBackground thread. The next
// step is either SendingResults if directory lock failed to acquire, or
- // DatabaseOpenPending if directory lock is acquired.
+ // DirectoryWorkOpen if the factory operation is not tied up to a specific
+ // database, or DatabaseOpenPending otherwise.
DirectoryOpenPending,
+ // Waiting to do/doing directory work on the QuotaManager IO thread. Its
+ // next step is DirectoryWorkDone if directory work was successful or
+ // SendingResults if directory work failed.
+ DirectoryWorkOpen,
+
+ // Checking if database work can be started. If the database is not blocked
+ // by other factory operations then the next step is DatabaseWorkOpen.
+ // Otherwise the next step is DatabaseOpenPending.
+ DirectoryWorkDone,
+
// Waiting for database open allowed on the PBackground thread. The next
// step is DatabaseWorkOpen.
DatabaseOpenPending,
@@ -3060,14 +3095,18 @@ class FactoryOp
// Must be released on the main thread!
RefPtr<DirectoryLock> mDirectoryLock;
- RefPtr<FactoryOp> mDelayedOp;
+ nsTArray<NotNull<RefPtr<FactoryOp>>> mBlocking;
+ nsTArray<NotNull<RefPtr<FactoryOp>>> mBlockedOn;
+
nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
- const CommonFactoryRequestParams mCommonParams;
+ const PrincipalInfo mPrincipalInfo;
OriginMetadata mOriginMetadata;
- nsCString mDatabaseId;
- nsString mDatabaseFilePath;
+ Maybe<nsString> mDatabaseName;
+ Maybe<nsCString> mDatabaseId;
+ Maybe<nsString> mDatabaseFilePath;
int64_t mDirectoryLockId;
+ const PersistenceType mPersistenceType;
State mState;
bool mWaitingForPermissionRetry;
bool mEnforcingQuota;
@@ -3081,17 +3120,23 @@ class FactoryOp
return mOriginMetadata.mOrigin;
}
+ const Maybe<nsString>& DatabaseNameRef() const {
+ AssertIsOnOwningThread();
+
+ return mDatabaseName;
+ }
+
bool DatabaseFilePathIsKnown() const {
AssertIsOnOwningThread();
- return !mDatabaseFilePath.IsEmpty();
+ return mDatabaseFilePath.isSome();
}
const nsAString& DatabaseFilePath() const {
AssertIsOnOwningThread();
- MOZ_ASSERT(!mDatabaseFilePath.IsEmpty());
+ MOZ_ASSERT(mDatabaseFilePath);
- return mDatabaseFilePath;
+ return mDatabaseFilePath.ref();
}
void NoteDatabaseBlocked(Database* aDatabase);
@@ -3109,7 +3154,9 @@ class FactoryOp
protected:
FactoryOp(SafeRefPtr<Factory> aFactory,
const Maybe<ContentParentId>& aContentParentId,
- const CommonFactoryRequestParams& aCommonParams, bool aDeleting);
+ const PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const Maybe<nsString>& aDatabaseName, bool aDeleting);
~FactoryOp() override {
// Normally this would be out-of-line since it is a virtual function but
@@ -3122,6 +3169,8 @@ class FactoryOp
nsresult DirectoryOpen();
+ nsresult DirectoryWorkDone();
+
nsresult SendToIOThread();
void WaitForTransactions();
@@ -3136,6 +3185,8 @@ class FactoryOp
const Maybe<uint64_t>& aNewVersion);
// Methods that subclasses must implement.
+ virtual nsresult DoDirectoryWork() = 0;
+
virtual nsresult DatabaseOpen() = 0;
virtual nsresult DoDatabaseWork() = 0;
@@ -3157,17 +3208,56 @@ class FactoryOp
void DirectoryLockFailed();
- // IPDL methods.
- void ActorDestroy(ActorDestroyReason aWhy) override;
-
virtual void SendBlockedNotification() = 0;
private:
// Test whether this FactoryOp needs to wait for the given op.
bool MustWaitFor(const FactoryOp& aExistingOp);
+
+ void AddBlockingOp(FactoryOp& aOp) {
+ AssertIsOnOwningThread();
+
+ mBlocking.AppendElement(WrapNotNull(&aOp));
+ }
+
+ void AddBlockedOnOp(FactoryOp& aOp) {
+ AssertIsOnOwningThread();
+
+ mBlockedOn.AppendElement(WrapNotNull(&aOp));
+ }
+
+ void MaybeUnblock(FactoryOp& aOp) {
+ AssertIsOnOwningThread();
+
+ mBlockedOn.RemoveElement(&aOp);
+ if (mBlockedOn.IsEmpty()) {
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
+ }
+ }
+};
+
+class FactoryRequestOp : public FactoryOp,
+ public PBackgroundIDBFactoryRequestParent {
+ protected:
+ const CommonFactoryRequestParams mCommonParams;
+
+ FactoryRequestOp(SafeRefPtr<Factory> aFactory,
+ const Maybe<ContentParentId>& aContentParentId,
+ const CommonFactoryRequestParams& aCommonParams,
+ bool aDeleting)
+ : FactoryOp(std::move(aFactory), aContentParentId,
+ aCommonParams.metadata().persistenceType(),
+ aCommonParams.principalInfo(),
+ Some(aCommonParams.metadata().name()), aDeleting),
+ mCommonParams(aCommonParams) {}
+
+ nsresult DoDirectoryWork() override;
+
+ // IPDL methods.
+ void ActorDestroy(ActorDestroyReason aWhy) override;
};
-class OpenDatabaseOp final : public FactoryOp {
+class OpenDatabaseOp final : public FactoryRequestOp {
friend class Database;
friend class VersionChangeTransaction;
@@ -3249,7 +3339,7 @@ class OpenDatabaseOp::VersionChangeOp final
explicit VersionChangeOp(OpenDatabaseOp* aOpenDatabaseOp)
: TransactionDatabaseOperationBase(
aOpenDatabaseOp->mVersionChangeTransaction.clonePtr(),
- aOpenDatabaseOp->LoggingSerialNumber()),
+ /* aRequestId */ 0, aOpenDatabaseOp->LoggingSerialNumber()),
mOpenDatabaseOp(aOpenDatabaseOp),
mRequestedVersion(aOpenDatabaseOp->mRequestedVersion),
mPreviousVersion(
@@ -3269,7 +3359,7 @@ class OpenDatabaseOp::VersionChangeOp final
void Cleanup() override;
};
-class DeleteDatabaseOp final : public FactoryOp {
+class DeleteDatabaseOp final : public FactoryRequestOp {
class VersionChangeOp;
nsString mDatabaseDirectoryPath;
@@ -3280,8 +3370,8 @@ class DeleteDatabaseOp final : public FactoryOp {
DeleteDatabaseOp(SafeRefPtr<Factory> aFactory,
const Maybe<ContentParentId>& aContentParentId,
const CommonFactoryRequestParams& aParams)
- : FactoryOp(std::move(aFactory), aContentParentId, aParams,
- /* aDeleting */ true),
+ : FactoryRequestOp(std::move(aFactory), aContentParentId, aParams,
+ /* aDeleting */ true),
mPreviousVersion(0) {}
private:
@@ -3327,6 +3417,43 @@ class DeleteDatabaseOp::VersionChangeOp final : public DatabaseOperationBase {
NS_DECL_NSIRUNNABLE
};
+class GetDatabasesOp final : public FactoryOp {
+ nsTHashMap<nsStringHashKey, DatabaseMetadata> mDatabaseMetadataTable;
+ nsTArray<DatabaseMetadata> mDatabaseMetadataArray;
+ Factory::GetDatabasesResolver mResolver;
+
+ public:
+ GetDatabasesOp(SafeRefPtr<Factory> aFactory,
+ const Maybe<ContentParentId>& aContentParentId,
+ const PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ Factory::GetDatabasesResolver&& aResolver)
+ : FactoryOp(std::move(aFactory), aContentParentId, aPersistenceType,
+ aPrincipalInfo, Nothing(), /* aDeleting */ false),
+ mResolver(std::move(aResolver)) {}
+
+ private:
+ ~GetDatabasesOp() override = default;
+
+ nsresult DatabasesNotAvailable();
+
+ nsresult DoDirectoryWork() override;
+
+ nsresult DatabaseOpen() override;
+
+ nsresult DoDatabaseWork() override;
+
+ nsresult BeginVersionChange() override;
+
+ bool AreActorsAlive() override;
+
+ void SendBlockedNotification() override;
+
+ nsresult DispatchToWorkThread() override;
+
+ void SendResults() override;
+};
+
class VersionChangeTransactionOp : public TransactionDatabaseOperationBase {
public:
void Cleanup() override;
@@ -3334,7 +3461,8 @@ class VersionChangeTransactionOp : public TransactionDatabaseOperationBase {
protected:
explicit VersionChangeTransactionOp(
SafeRefPtr<VersionChangeTransaction> aTransaction)
- : TransactionDatabaseOperationBase(std::move(aTransaction)) {}
+ : TransactionDatabaseOperationBase(std::move(aTransaction),
+ /* aRequestId */ 0) {}
~VersionChangeTransactionOp() override = default;
@@ -3519,8 +3647,9 @@ class NormalTransactionOp : public TransactionDatabaseOperationBase,
void Cleanup() override;
protected:
- explicit NormalTransactionOp(SafeRefPtr<TransactionBase> aTransaction)
- : TransactionDatabaseOperationBase(std::move(aTransaction))
+ NormalTransactionOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId)
+ : TransactionDatabaseOperationBase(std::move(aTransaction), aRequestId)
#ifdef DEBUG
,
mResponseSent(false)
@@ -3628,7 +3757,7 @@ class ObjectStoreAddOrPutRequestOp final : public NormalTransactionOp {
};
class SCInputStream;
- const ObjectStoreAddPutParams mParams;
+ ObjectStoreAddPutParams mParams;
Maybe<UniqueIndexTable> mUniqueIndexTable;
// This must be non-const so that we can update the mNextAutoIncrementId field
@@ -3647,6 +3776,7 @@ class ObjectStoreAddOrPutRequestOp final : public NormalTransactionOp {
private:
// Only created by TransactionBase.
ObjectStoreAddOrPutRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
RequestParams&& aParams);
~ObjectStoreAddOrPutRequestOp() override = default;
@@ -3883,6 +4013,7 @@ class ObjectStoreGetRequestOp final : public NormalTransactionOp {
private:
// Only created by TransactionBase.
ObjectStoreGetRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const RequestParams& aParams, bool aGetAll);
~ObjectStoreGetRequestOp() override = default;
@@ -3912,6 +4043,7 @@ class ObjectStoreGetKeyRequestOp final : public NormalTransactionOp {
private:
// Only created by TransactionBase.
ObjectStoreGetKeyRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const RequestParams& aParams, bool aGetAll);
~ObjectStoreGetKeyRequestOp() override = default;
@@ -3930,6 +4062,7 @@ class ObjectStoreDeleteRequestOp final : public NormalTransactionOp {
private:
ObjectStoreDeleteRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const ObjectStoreDeleteParams& aParams);
~ObjectStoreDeleteRequestOp() override = default;
@@ -3951,6 +4084,7 @@ class ObjectStoreClearRequestOp final : public NormalTransactionOp {
private:
ObjectStoreClearRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const ObjectStoreClearParams& aParams);
~ObjectStoreClearRequestOp() override = default;
@@ -3971,8 +4105,10 @@ class ObjectStoreCountRequestOp final : public NormalTransactionOp {
private:
ObjectStoreCountRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const ObjectStoreCountParams& aParams)
- : NormalTransactionOp(std::move(aTransaction)), mParams(aParams) {}
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
+ mParams(aParams) {}
~ObjectStoreCountRequestOp() override = default;
@@ -3990,8 +4126,8 @@ class IndexRequestOpBase : public NormalTransactionOp {
protected:
IndexRequestOpBase(SafeRefPtr<TransactionBase> aTransaction,
- const RequestParams& aParams)
- : NormalTransactionOp(std::move(aTransaction)),
+ const int64_t aRequestId, const RequestParams& aParams)
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mMetadata(IndexMetadataForParams(Transaction(), aParams)) {}
~IndexRequestOpBase() override = default;
@@ -4014,7 +4150,8 @@ class IndexGetRequestOp final : public IndexRequestOpBase {
private:
// Only created by TransactionBase.
IndexGetRequestOp(SafeRefPtr<TransactionBase> aTransaction,
- const RequestParams& aParams, bool aGetAll);
+ const int64_t aRequestId, const RequestParams& aParams,
+ bool aGetAll);
~IndexGetRequestOp() override = default;
@@ -4034,7 +4171,8 @@ class IndexGetKeyRequestOp final : public IndexRequestOpBase {
private:
// Only created by TransactionBase.
IndexGetKeyRequestOp(SafeRefPtr<TransactionBase> aTransaction,
- const RequestParams& aParams, bool aGetAll);
+ const int64_t aRequestId, const RequestParams& aParams,
+ bool aGetAll);
~IndexGetKeyRequestOp() override = default;
@@ -4052,8 +4190,8 @@ class IndexCountRequestOp final : public IndexRequestOpBase {
private:
// Only created by TransactionBase.
IndexCountRequestOp(SafeRefPtr<TransactionBase> aTransaction,
- const RequestParams& aParams)
- : IndexRequestOpBase(std::move(aTransaction), aParams),
+ const int64_t aRequestId, const RequestParams& aParams)
+ : IndexRequestOpBase(std::move(aTransaction), aRequestId, aParams),
mParams(aParams.get_IndexCountParams()) {}
~IndexCountRequestOp() override = default;
@@ -4153,7 +4291,8 @@ class CursorBase : public PBackgroundIDBCursorParent {
~CursorBase() override { MOZ_ASSERT(!mObjectStoreMetadata); }
private:
- virtual bool Start(const OpenCursorParams& aParams) = 0;
+ virtual bool Start(const int64_t aRequestId,
+ const OpenCursorParams& aParams) = 0;
};
class IndexCursorBase : public CursorBase {
@@ -4311,7 +4450,7 @@ class Cursor final
LazyInitializedOnce<const typename Base::ContinueQueries> mContinueQueries;
// Only called by TransactionBase.
- bool Start(const OpenCursorParams& aParams) final;
+ bool Start(const int64_t aRequestId, const OpenCursorParams& aParams) final;
void SendResponseInternal(CursorResponse& aResponse,
const FilesArrayT<CursorType>& aFiles);
@@ -4325,8 +4464,8 @@ class Cursor final
mozilla::ipc::IPCResult RecvDeleteMe() override;
mozilla::ipc::IPCResult RecvContinue(
- const CursorRequestParams& aParams, const Key& aCurrentKey,
- const Key& aCurrentObjectStoreKey) override;
+ const int64_t& aRequestId, const CursorRequestParams& aParams,
+ const Key& aCurrentKey, const Key& aCurrentObjectStoreKey) override;
public:
Cursor(SafeRefPtr<TransactionBase> aTransaction,
@@ -4373,8 +4512,9 @@ class Cursor<CursorType>::CursorOpBase
#endif
protected:
- explicit CursorOpBase(Cursor* aCursor)
- : TransactionDatabaseOperationBase(aCursor->mTransaction.clonePtr()),
+ explicit CursorOpBase(Cursor* aCursor, const int64_t aRequestId)
+ : TransactionDatabaseOperationBase(aCursor->mTransaction.clonePtr(),
+ /* aRequestId */ aRequestId),
mCursor(aCursor)
#ifdef DEBUG
,
@@ -4552,9 +4692,10 @@ class Cursor<CursorType>::OpenOp final : public CursorOpBase {
using CursorOpBase::mResponse;
// Only created by Cursor.
- OpenOp(Cursor* const aCursor,
+ OpenOp(Cursor* const aCursor, const int64_t aRequestId,
const Maybe<SerializedKeyRange>& aOptionalKeyRange)
- : CursorOpBase(aCursor), mOptionalKeyRange(aOptionalKeyRange) {}
+ : CursorOpBase(aCursor, aRequestId),
+ mOptionalKeyRange(aOptionalKeyRange) {}
// Reference counted.
~OpenOp() override = default;
@@ -4572,9 +4713,9 @@ class Cursor<CursorType>::ContinueOp final
const CursorRequestParams mParams;
// Only created by Cursor.
- ContinueOp(Cursor* const aCursor, CursorRequestParams aParams,
- CursorPosition<CursorType> aPosition)
- : CursorOpBase(aCursor),
+ ContinueOp(Cursor* const aCursor, int64_t aRequestId,
+ CursorRequestParams aParams, CursorPosition<CursorType> aPosition)
+ : CursorOpBase(aCursor, aRequestId),
mParams(std::move(aParams)),
mCurrentPosition{std::move(aPosition)} {
MOZ_ASSERT(mParams.type() != CursorRequestParams::T__None);
@@ -4691,6 +4832,8 @@ class DatabaseLoggingInfo final {
};
class QuotaClient final : public mozilla::dom::quota::Client {
+ friend class GetDatabasesOp;
+
static QuotaClient* sInstance;
nsCOMPtr<nsIEventTarget> mBackgroundThread;
@@ -4824,8 +4967,9 @@ class QuotaClient final : public mozilla::dom::quota::Client {
// checks those unfinished deletion and clean them up after that.
template <ObsoleteFilenamesHandling ObsoleteFilenames =
ObsoleteFilenamesHandling::Omit>
- Result<GetDatabaseFilenamesResult<ObsoleteFilenames>, nsresult>
- GetDatabaseFilenames(nsIFile& aDirectory, const AtomicBool& aCanceled);
+ Result<GetDatabaseFilenamesResult<ObsoleteFilenames>,
+ nsresult> static GetDatabaseFilenames(nsIFile& aDirectory,
+ const AtomicBool& aCanceled);
nsresult GetUsageForOriginInternal(PersistenceType aPersistenceType,
const OriginMetadata& aOriginMetadata,
@@ -4866,6 +5010,9 @@ class DeleteFilesRunnable final : public Runnable {
RefPtr<DirectoryLock> mDirectoryLock;
nsTArray<int64_t> mFileIds;
State mState;
+ DEBUGONLY(bool mDEBUGCountsAsPending = false);
+
+ static uint64_t sPendingRunnables;
public:
DeleteFilesRunnable(SafeRefPtr<DatabaseFileManager> aFileManager,
@@ -4873,8 +5020,14 @@ class DeleteFilesRunnable final : public Runnable {
void RunImmediately();
+ static bool IsDeletionPending() { return sPendingRunnables > 0; }
+
private:
+#ifdef DEBUG
+ ~DeleteFilesRunnable();
+#else
~DeleteFilesRunnable() = default;
+#endif
void Open();
@@ -4953,6 +5106,7 @@ class Maintenance final : public Runnable {
PRTime mStartTime;
RefPtr<UniversalDirectoryLock> mPendingDirectoryLock;
RefPtr<UniversalDirectoryLock> mDirectoryLock;
+ nsTArray<nsCOMPtr<nsIRunnable>> mCompleteCallbacks;
nsTArray<DirectoryInfo> mDirectoryInfos;
nsTHashMap<nsStringHashKey, DatabaseMaintenance*> mDatabaseMaintenances;
nsresult mResultCode;
@@ -4994,6 +5148,8 @@ class Maintenance final : public Runnable {
void UnregisterDatabaseMaintenance(DatabaseMaintenance* aDatabaseMaintenance);
+ bool HasDatabaseMaintenances() const { return mDatabaseMaintenances.Count(); }
+
RefPtr<DatabaseMaintenance> GetDatabaseMaintenance(
const nsAString& aDatabasePath) const {
AssertIsOnBackgroundThread();
@@ -5001,6 +5157,13 @@ class Maintenance final : public Runnable {
return mDatabaseMaintenances.Get(aDatabasePath);
}
+ void WaitForCompletion(nsIRunnable* aCallback) {
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(mDatabaseMaintenances.Count());
+
+ mCompleteCallbacks.AppendElement(aCallback);
+ }
+
void Stringify(nsACString& aResult) const;
private:
@@ -6410,9 +6573,9 @@ class DeserializeIndexValueHelper final : public Runnable {
value.setUndefined();
ErrorResult rv;
- IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mMultiEntry,
- mLocale, jsapi.cx(), value,
- &mUpdateInfoArray, &rv);
+ IDBObjectStore::AppendIndexUpdateInfo(
+ mIndexID, mKeyPath, mMultiEntry, &mUpdateInfoArray,
+ /* aAutoIncrementedObjectStoreKeyPath */ VoidString(), &rv);
return rv.Failed() ? rv.StealNSResult() : NS_OK;
}
#endif
@@ -6450,9 +6613,9 @@ class DeserializeIndexValueHelper final : public Runnable {
[this](const nsresult rv) { OperationCompleted(rv); });
ErrorResult errorResult;
- IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mMultiEntry,
- mLocale, cx, value, &mUpdateInfoArray,
- &errorResult);
+ IDBObjectStore::AppendIndexUpdateInfo(
+ mIndexID, mKeyPath, mMultiEntry, mLocale, cx, value, &mUpdateInfoArray,
+ /* aAutoIncrementedObjectStoreKeyPath */ VoidString(), &errorResult);
QM_TRY(OkIf(!errorResult.Failed()), NS_OK,
([this, &errorResult](const NotOk) {
OperationCompleted(errorResult.StealNSResult());
@@ -9111,20 +9274,9 @@ Factory::AllocPBackgroundIDBFactoryRequestParent(
return nullptr;
}
- Maybe<ContentParentId> contentParentId;
-
- uint64_t childID = BackgroundParent::GetChildID(Manager());
- if (childID) {
- // If childID is not zero we are dealing with an other-process actor. We
- // want to initialize OpenDatabaseOp/DeleteDatabaseOp here with the ID
- // (and later also Database) in that case, so Database::IsOwnedByProcess
- // can find Databases belonging to a particular content process when
- // QuotaClient::AbortOperationsForProcess is called which is currently used
- // to abort operations for content processes only.
- contentParentId = Some(ContentParentId(childID));
- }
+ Maybe<ContentParentId> contentParentId = GetContentParentId();
- auto actor = [&]() -> RefPtr<FactoryOp> {
+ auto actor = [&]() -> RefPtr<FactoryRequestOp> {
if (aParams.type() == FactoryRequestParams::TOpenDatabaseRequestParams) {
return MakeRefPtr<OpenDatabaseOp>(SafeRefPtrFromThis(), contentParentId,
*commonParams);
@@ -9151,7 +9303,7 @@ mozilla::ipc::IPCResult Factory::RecvPBackgroundIDBFactoryRequestConstructor(
MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
- auto* op = static_cast<FactoryOp*>(aActor);
+ auto* op = static_cast<FactoryRequestOp*>(aActor);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(op));
return IPC_OK();
@@ -9163,10 +9315,69 @@ bool Factory::DeallocPBackgroundIDBFactoryRequestParent(
MOZ_ASSERT(aActor);
// Transfer ownership back from IPDL.
- RefPtr<FactoryOp> op = dont_AddRef(static_cast<FactoryOp*>(aActor));
+ RefPtr<FactoryRequestOp> op =
+ dont_AddRef(static_cast<FactoryRequestOp*>(aActor));
return true;
}
+mozilla::ipc::IPCResult Factory::RecvGetDatabases(
+ const PersistenceType& aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo, GetDatabasesResolver&& aResolve) {
+ AssertIsOnBackgroundThread();
+
+ auto ResolveGetDatabasesAndReturn = [&aResolve](const nsresult rv) {
+ aResolve(rv);
+ return IPC_OK();
+ };
+
+ QM_TRY(MOZ_TO_RESULT(!QuotaClient::IsShuttingDownOnBackgroundThread()),
+ ResolveGetDatabasesAndReturn);
+
+ QM_TRY(MOZ_TO_RESULT(IsValidPersistenceType(aPersistenceType)),
+ QM_IPC_FAIL(this));
+
+ QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(aPrincipalInfo)),
+ QM_IPC_FAIL(this));
+
+ MOZ_ASSERT(aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo ||
+ aPrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
+
+ PersistenceType persistenceType =
+ IDBFactory::GetPersistenceType(aPrincipalInfo);
+
+ QM_TRY(MOZ_TO_RESULT(aPersistenceType == persistenceType), QM_IPC_FAIL(this));
+
+ Maybe<ContentParentId> contentParentId = GetContentParentId();
+
+ auto op = MakeRefPtr<GetDatabasesOp>(SafeRefPtrFromThis(), contentParentId,
+ aPersistenceType, aPrincipalInfo,
+ std::move(aResolve));
+
+ gFactoryOps->AppendElement(op);
+
+ // Balanced in CleanupMetadata() which is/must always called by SendResults().
+ IncreaseBusyCount();
+
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(op));
+
+ return IPC_OK();
+}
+
+Maybe<ContentParentId> Factory::GetContentParentId() const {
+ uint64_t childID = BackgroundParent::GetChildID(Manager());
+ if (childID) {
+ // If childID is not zero we are dealing with an other-process actor. We
+ // want to initialize OpenDatabaseOp/DeleteDatabaseOp here with the ID
+ // (and later also Database) in that case, so Database::IsOwnedByProcess
+ // can find Databases belonging to a particular content process when
+ // QuotaClient::AbortOperationsForProcess is called which is currently used
+ // to abort operations for content processes only.
+ return Some(ContentParentId(childID));
+ }
+
+ return Nothing();
+}
+
/*******************************************************************************
* WaitForTransactionsHelper
******************************************************************************/
@@ -9608,7 +9819,8 @@ bool Database::DeallocPBackgroundIDBDatabaseFileParent(
already_AddRefed<PBackgroundIDBTransactionParent>
Database::AllocPBackgroundIDBTransactionParent(
- const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode) {
+ const nsTArray<nsString>& aObjectStoreNames, const Mode& aMode,
+ const Durability& aDurability) {
AssertIsOnBackgroundThread();
// Once a database is closed it must not try to open new transactions.
@@ -9628,6 +9840,12 @@ Database::AllocPBackgroundIDBTransactionParent(
return nullptr;
}
+ if (NS_AUUF_OR_WARN_IF(aDurability != IDBTransaction::Durability::Default &&
+ aDurability != IDBTransaction::Durability::Strict &&
+ aDurability != IDBTransaction::Durability::Relaxed)) {
+ return nullptr;
+ }
+
const ObjectStoreTable& objectStores = mMetadata->mObjectStores;
const uint32_t nameCount = aObjectStoreNames.Length();
@@ -9670,13 +9888,15 @@ Database::AllocPBackgroundIDBTransactionParent(
nullptr);
return MakeSafeRefPtr<NormalTransaction>(SafeRefPtrFromThis(), aMode,
+ aDurability,
std::move(objectStoreMetadatas))
.forget();
}
mozilla::ipc::IPCResult Database::RecvPBackgroundIDBTransactionConstructor(
PBackgroundIDBTransactionParent* aActor,
- nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode) {
+ nsTArray<nsString>&& aObjectStoreNames, const Mode& aMode,
+ const Durability& aDurability) { // TODO: See bug 1883045
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
@@ -9684,6 +9904,9 @@ mozilla::ipc::IPCResult Database::RecvPBackgroundIDBTransactionConstructor(
aMode == IDBTransaction::Mode::ReadWrite ||
aMode == IDBTransaction::Mode::ReadWriteFlush ||
aMode == IDBTransaction::Mode::Cleanup);
+ MOZ_ASSERT(aDurability == IDBTransaction::Durability::Default ||
+ aDurability == IDBTransaction::Durability::Strict ||
+ aDurability == IDBTransaction::Durability::Relaxed);
MOZ_ASSERT(!mClosed);
if (IsInvalidated()) {
@@ -9815,7 +10038,8 @@ void Database::StartTransactionOp::Cleanup() {
* TransactionBase
******************************************************************************/
-TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode)
+TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode,
+ Durability aDurability)
: mDatabase(std::move(aDatabase)),
mDatabaseId(mDatabase->Id()),
mLoggingSerialNumber(
@@ -9823,6 +10047,7 @@ TransactionBase::TransactionBase(SafeRefPtr<Database> aDatabase, Mode aMode)
mActiveRequestCount(0),
mInvalidatedOnAnyThread(false),
mMode(aMode),
+ mDurability(aDurability),
mResultCode(NS_OK) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatabase);
@@ -9899,14 +10124,13 @@ void TransactionBase::CommitOrAbort() {
return;
}
- // In case of a failed request that was started after committing was
- // initiated, abort (cf.
- // https://w3c.github.io/IndexedDB/#async-execute-request step 5.3 vs. 5.4).
- // Note this can only happen here when we are committing explicitly, otherwise
- // the decision is made by the child.
+ // In case of a failed request and explicitly committed transaction, abort
+ // (cf. https://w3c.github.io/IndexedDB/#async-execute-request step 5.3
+ // vs. 5.4). It's worth emphasizing this can only happen here when we are
+ // committing explicitly, otherwise the decision is made by the child.
if (NS_SUCCEEDED(mResultCode) && mLastFailedRequest &&
*mLastRequestBeforeCommit &&
- *mLastFailedRequest >= **mLastRequestBeforeCommit) {
+ *mLastFailedRequest == **mLastRequestBeforeCommit) {
mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
}
@@ -10360,7 +10584,7 @@ void TransactionBase::Invalidate() {
}
PBackgroundIDBRequestParent* TransactionBase::AllocRequest(
- RequestParams&& aParams, bool aTrustParams) {
+ const int64_t aRequestId, RequestParams&& aParams, bool aTrustParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
@@ -10382,67 +10606,77 @@ PBackgroundIDBRequestParent* TransactionBase::AllocRequest(
switch (aParams.type()) {
case RequestParams::TObjectStoreAddParams:
case RequestParams::TObjectStorePutParams:
- actor = new ObjectStoreAddOrPutRequestOp(SafeRefPtrFromThis(),
+ actor = new ObjectStoreAddOrPutRequestOp(SafeRefPtrFromThis(), aRequestId,
std::move(aParams));
break;
case RequestParams::TObjectStoreGetParams:
- actor = new ObjectStoreGetRequestOp(SafeRefPtrFromThis(), aParams,
- /* aGetAll */ false);
+ actor =
+ new ObjectStoreGetRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
+ /* aGetAll */ false);
break;
case RequestParams::TObjectStoreGetAllParams:
- actor = new ObjectStoreGetRequestOp(SafeRefPtrFromThis(), aParams,
- /* aGetAll */ true);
+ actor =
+ new ObjectStoreGetRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
+ /* aGetAll */ true);
break;
case RequestParams::TObjectStoreGetKeyParams:
- actor = new ObjectStoreGetKeyRequestOp(SafeRefPtrFromThis(), aParams,
+ actor = new ObjectStoreGetKeyRequestOp(SafeRefPtrFromThis(), aRequestId,
+ aParams,
/* aGetAll */ false);
break;
case RequestParams::TObjectStoreGetAllKeysParams:
- actor = new ObjectStoreGetKeyRequestOp(SafeRefPtrFromThis(), aParams,
+ actor = new ObjectStoreGetKeyRequestOp(SafeRefPtrFromThis(), aRequestId,
+ aParams,
/* aGetAll */ true);
break;
case RequestParams::TObjectStoreDeleteParams:
- actor = new ObjectStoreDeleteRequestOp(
- SafeRefPtrFromThis(), aParams.get_ObjectStoreDeleteParams());
+ actor =
+ new ObjectStoreDeleteRequestOp(SafeRefPtrFromThis(), aRequestId,
+ aParams.get_ObjectStoreDeleteParams());
break;
case RequestParams::TObjectStoreClearParams:
- actor = new ObjectStoreClearRequestOp(
- SafeRefPtrFromThis(), aParams.get_ObjectStoreClearParams());
+ actor =
+ new ObjectStoreClearRequestOp(SafeRefPtrFromThis(), aRequestId,
+ aParams.get_ObjectStoreClearParams());
break;
case RequestParams::TObjectStoreCountParams:
- actor = new ObjectStoreCountRequestOp(
- SafeRefPtrFromThis(), aParams.get_ObjectStoreCountParams());
+ actor =
+ new ObjectStoreCountRequestOp(SafeRefPtrFromThis(), aRequestId,
+ aParams.get_ObjectStoreCountParams());
break;
case RequestParams::TIndexGetParams:
- actor = new IndexGetRequestOp(SafeRefPtrFromThis(), aParams,
+ actor = new IndexGetRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
/* aGetAll */ false);
break;
case RequestParams::TIndexGetKeyParams:
- actor = new IndexGetKeyRequestOp(SafeRefPtrFromThis(), aParams,
- /* aGetAll */ false);
+ actor =
+ new IndexGetKeyRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
+ /* aGetAll */ false);
break;
case RequestParams::TIndexGetAllParams:
- actor = new IndexGetRequestOp(SafeRefPtrFromThis(), aParams,
+ actor = new IndexGetRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
/* aGetAll */ true);
break;
case RequestParams::TIndexGetAllKeysParams:
- actor = new IndexGetKeyRequestOp(SafeRefPtrFromThis(), aParams,
- /* aGetAll */ true);
+ actor =
+ new IndexGetKeyRequestOp(SafeRefPtrFromThis(), aRequestId, aParams,
+ /* aGetAll */ true);
break;
case RequestParams::TIndexCountParams:
- actor = new IndexCountRequestOp(SafeRefPtrFromThis(), aParams);
+ actor =
+ new IndexCountRequestOp(SafeRefPtrFromThis(), aRequestId, aParams);
break;
default:
@@ -10552,6 +10786,7 @@ already_AddRefed<PBackgroundIDBCursorParent> TransactionBase::AllocCursor(
}
bool TransactionBase::StartCursor(PBackgroundIDBCursorParent* const aActor,
+ const int64_t aRequestId,
const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
@@ -10559,7 +10794,7 @@ bool TransactionBase::StartCursor(PBackgroundIDBCursorParent* const aActor,
auto* const op = static_cast<CursorBase*>(aActor);
- if (NS_WARN_IF(!op->Start(aParams))) {
+ if (NS_WARN_IF(!op->Start(aRequestId, aParams))) {
return false;
}
@@ -10572,8 +10807,9 @@ bool TransactionBase::StartCursor(PBackgroundIDBCursorParent* const aActor,
NormalTransaction::NormalTransaction(
SafeRefPtr<Database> aDatabase, TransactionBase::Mode aMode,
+ TransactionBase::Durability aDurability,
nsTArray<SafeRefPtr<FullObjectStoreMetadata>>&& aObjectStores)
- : TransactionBase(std::move(aDatabase), aMode),
+ : TransactionBase(std::move(aDatabase), aMode, aDurability),
mObjectStores{std::move(aObjectStores)} {
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mObjectStores.IsEmpty());
@@ -10638,16 +10874,18 @@ mozilla::ipc::IPCResult NormalTransaction::RecvAbort(
PBackgroundIDBRequestParent*
NormalTransaction::AllocPBackgroundIDBRequestParent(
- const RequestParams& aParams) {
+ const int64_t& aRequestId, const RequestParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
- return AllocRequest(std::move(const_cast<RequestParams&>(aParams)),
+ return AllocRequest(aRequestId,
+ std::move(const_cast<RequestParams&>(aParams)),
IsSameProcessActor());
}
mozilla::ipc::IPCResult NormalTransaction::RecvPBackgroundIDBRequestConstructor(
- PBackgroundIDBRequestParent* const aActor, const RequestParams& aParams) {
+ PBackgroundIDBRequestParent* const aActor, const int64_t& aRequestId,
+ const RequestParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
@@ -10668,19 +10906,20 @@ bool NormalTransaction::DeallocPBackgroundIDBRequestParent(
already_AddRefed<PBackgroundIDBCursorParent>
NormalTransaction::AllocPBackgroundIDBCursorParent(
- const OpenCursorParams& aParams) {
+ const int64_t& aRequestId, const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
return AllocCursor(aParams, IsSameProcessActor());
}
mozilla::ipc::IPCResult NormalTransaction::RecvPBackgroundIDBCursorConstructor(
- PBackgroundIDBCursorParent* const aActor, const OpenCursorParams& aParams) {
+ PBackgroundIDBCursorParent* const aActor, const int64_t& aRequestId,
+ const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
- if (!StartCursor(aActor, aParams)) {
+ if (!StartCursor(aActor, aRequestId, aParams)) {
return IPC_FAIL(this, "StartCursor failed!");
}
return IPC_OK();
@@ -10693,7 +10932,9 @@ mozilla::ipc::IPCResult NormalTransaction::RecvPBackgroundIDBCursorConstructor(
VersionChangeTransaction::VersionChangeTransaction(
OpenDatabaseOp* aOpenDatabaseOp)
: TransactionBase(aOpenDatabaseOp->mDatabase.clonePtr(),
- IDBTransaction::Mode::VersionChange),
+ IDBTransaction::Mode::VersionChange,
+ // VersionChange must not change durability.
+ IDBTransaction::Durability::Default), // Not used.
mOpenDatabaseOp(aOpenDatabaseOp) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aOpenDatabaseOp);
@@ -10755,7 +10996,7 @@ void VersionChangeTransaction::UpdateMetadata(nsresult aResult) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(!!mActorWasAlive == !!mOpenDatabaseOp->mDatabase);
- MOZ_ASSERT_IF(mActorWasAlive, !mOpenDatabaseOp->mDatabaseId.IsEmpty());
+ MOZ_ASSERT_IF(mActorWasAlive, !mOpenDatabaseOp->mDatabaseId.ref().IsEmpty());
if (IsActorDestroyed() || !mActorWasAlive) {
return;
@@ -11224,17 +11465,19 @@ mozilla::ipc::IPCResult VersionChangeTransaction::RecvRenameIndex(
PBackgroundIDBRequestParent*
VersionChangeTransaction::AllocPBackgroundIDBRequestParent(
- const RequestParams& aParams) {
+ const int64_t& aRequestId, const RequestParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
- return AllocRequest(std::move(const_cast<RequestParams&>(aParams)),
+ return AllocRequest(aRequestId,
+ std::move(const_cast<RequestParams&>(aParams)),
IsSameProcessActor());
}
mozilla::ipc::IPCResult
VersionChangeTransaction::RecvPBackgroundIDBRequestConstructor(
- PBackgroundIDBRequestParent* aActor, const RequestParams& aParams) {
+ PBackgroundIDBRequestParent* aActor, const int64_t& aRequestId,
+ const RequestParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
@@ -11255,7 +11498,7 @@ bool VersionChangeTransaction::DeallocPBackgroundIDBRequestParent(
already_AddRefed<PBackgroundIDBCursorParent>
VersionChangeTransaction::AllocPBackgroundIDBCursorParent(
- const OpenCursorParams& aParams) {
+ const int64_t& aRequestId, const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
return AllocCursor(aParams, IsSameProcessActor());
@@ -11263,12 +11506,13 @@ VersionChangeTransaction::AllocPBackgroundIDBCursorParent(
mozilla::ipc::IPCResult
VersionChangeTransaction::RecvPBackgroundIDBCursorConstructor(
- PBackgroundIDBCursorParent* aActor, const OpenCursorParams& aParams) {
+ PBackgroundIDBCursorParent* aActor, const int64_t& aRequestId,
+ const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
- if (!StartCursor(aActor, aParams)) {
+ if (!StartCursor(aActor, aRequestId, aParams)) {
return IPC_FAIL(this, "StartCursor failed!");
}
return IPC_OK();
@@ -11417,7 +11661,8 @@ bool Cursor<CursorType>::VerifyRequestParams(
}
template <IDBCursorType CursorType>
-bool Cursor<CursorType>::Start(const OpenCursorParams& aParams) {
+bool Cursor<CursorType>::Start(const int64_t aRequestId,
+ const OpenCursorParams& aParams) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() == ToOpenCursorParamsType(CursorType));
MOZ_ASSERT(this->mObjectStoreMetadata);
@@ -11429,7 +11674,7 @@ bool Cursor<CursorType>::Start(const OpenCursorParams& aParams) {
const Maybe<SerializedKeyRange>& optionalKeyRange =
GetCommonOpenCursorParams(aParams).optionalKeyRange();
- const RefPtr<OpenOp> openOp = new OpenOp(this, optionalKeyRange);
+ const RefPtr<OpenOp> openOp = new OpenOp(this, aRequestId, optionalKeyRange);
if (NS_WARN_IF(!openOp->Init(*mTransaction))) {
openOp->Cleanup();
@@ -11553,8 +11798,8 @@ mozilla::ipc::IPCResult Cursor<CursorType>::RecvDeleteMe() {
template <IDBCursorType CursorType>
mozilla::ipc::IPCResult Cursor<CursorType>::RecvContinue(
- const CursorRequestParams& aParams, const Key& aCurrentKey,
- const Key& aCurrentObjectStoreKey) {
+ const int64_t& aRequestId, const CursorRequestParams& aParams,
+ const Key& aCurrentKey, const Key& aCurrentObjectStoreKey) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
MOZ_ASSERT(this->mObjectStoreMetadata);
@@ -11604,7 +11849,7 @@ mozilla::ipc::IPCResult Cursor<CursorType>::RecvContinue(
}
const RefPtr<ContinueOp> continueOp =
- new ContinueOp(this, aParams, std::move(position));
+ new ContinueOp(this, aRequestId, aParams, std::move(position));
if (NS_WARN_IF(!continueOp->Init(*mTransaction))) {
continueOp->Cleanup();
return IPC_FAIL(this, "ContinueOp initialization failed!");
@@ -11626,15 +11871,18 @@ DatabaseFileManager::DatabaseFileManager(
PersistenceType aPersistenceType,
const quota::OriginMetadata& aOriginMetadata,
const nsAString& aDatabaseName, const nsCString& aDatabaseID,
- bool aEnforcingQuota, bool aIsInPrivateBrowsingMode)
+ const nsAString& aDatabaseFilePath, bool aEnforcingQuota,
+ bool aIsInPrivateBrowsingMode)
: mPersistenceType(aPersistenceType),
mOriginMetadata(aOriginMetadata),
mDatabaseName(aDatabaseName),
mDatabaseID(aDatabaseID),
+ mDatabaseFilePath(aDatabaseFilePath),
mCipherKeyManager(
aIsInPrivateBrowsingMode
? new IndexedDBCipherKeyManager("IndexedDBCipherKeyManager")
: nullptr),
+ mDatabaseVersion(0),
mEnforcingQuota(aEnforcingQuota),
mIsInPrivateBrowsingMode(aIsInPrivateBrowsingMode) {}
@@ -12488,6 +12736,17 @@ void QuotaClient::StopIdleMaintenance() {
void QuotaClient::InitiateShutdown() {
AssertIsOnBackgroundThread();
+ MOZ_ASSERT(IsShuttingDownOnBackgroundThread());
+
+ if (mDeleteTimer) {
+ // QuotaClient::AsyncDeleteFile will not schedule new timers beyond
+ // shutdown. And we expect all critical (PBM) deletions to have been
+ // triggered before this point via ClearPrivateRepository (w/out using
+ // DeleteFilesRunnable at all).
+ mDeleteTimer->Cancel();
+ mDeleteTimer = nullptr;
+ mPendingDeleteInfos.Clear();
+ }
AbortAllOperations();
}
@@ -12495,7 +12754,7 @@ void QuotaClient::InitiateShutdown() {
bool QuotaClient::IsShutdownCompleted() const {
return (!gFactoryOps || gFactoryOps->IsEmpty()) &&
(!gLiveDatabaseHashtable || !gLiveDatabaseHashtable->Count()) &&
- !mCurrentMaintenance;
+ !mCurrentMaintenance && !DeleteFilesRunnable::IsDeletionPending();
}
void QuotaClient::ForceKillActors() {
@@ -12575,17 +12834,20 @@ void QuotaClient::FinalizeShutdown() {
mMaintenanceThreadPool->Shutdown();
mMaintenanceThreadPool = nullptr;
}
-
- if (mDeleteTimer) {
- MOZ_ALWAYS_SUCCEEDS(mDeleteTimer->Cancel());
- mDeleteTimer = nullptr;
- }
}
void QuotaClient::DeleteTimerCallback(nsITimer* aTimer, void* aClosure) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aTimer);
+ // Even though we do not schedule new timers after shutdown has started,
+ // an already existing one might fire afterwards (actually we think it
+ // shouldn't, but there is no reason to enforce this invariant). We can
+ // just ignore it, the cleanup work is done in InitiateShutdown.
+ if (NS_WARN_IF(IsShuttingDownOnBackgroundThread())) {
+ return;
+ }
+
auto* const self = static_cast<QuotaClient*>(aClosure);
MOZ_ASSERT(self);
MOZ_ASSERT(self->mDeleteTimer);
@@ -12728,6 +12990,8 @@ void QuotaClient::ProcessMaintenanceQueue() {
* DeleteFilesRunnable
******************************************************************************/
+uint64_t DeleteFilesRunnable::sPendingRunnables = 0;
+
DeleteFilesRunnable::DeleteFilesRunnable(
SafeRefPtr<DatabaseFileManager> aFileManager, nsTArray<int64_t>&& aFileIds)
: Runnable("dom::indexeddb::DeleteFilesRunnable"),
@@ -12736,6 +13000,12 @@ DeleteFilesRunnable::DeleteFilesRunnable(
mFileIds(std::move(aFileIds)),
mState(State_Initial) {}
+#ifdef DEBUG
+DeleteFilesRunnable::~DeleteFilesRunnable() {
+ MOZ_ASSERT(!mDEBUGCountsAsPending);
+}
+#endif
+
void DeleteFilesRunnable::RunImmediately() {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mState == State_Initial);
@@ -12747,6 +13017,10 @@ void DeleteFilesRunnable::Open() {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mState == State_Initial);
+ MOZ_ASSERT(!mDEBUGCountsAsPending);
+ sPendingRunnables++;
+ DEBUGONLY(mDEBUGCountsAsPending = true);
+
QuotaManager* const quotaManager = QuotaManager::Get();
if (NS_WARN_IF(!quotaManager)) {
Finish();
@@ -12800,6 +13074,9 @@ void DeleteFilesRunnable::UnblockOpen() {
MOZ_ASSERT(mState == State_UnblockingOpen);
mDirectoryLock = nullptr;
+ MOZ_ASSERT(mDEBUGCountsAsPending);
+ sPendingRunnables--;
+ DEBUGONLY(mDEBUGCountsAsPending = false);
mState = State_Completed;
}
@@ -12892,6 +13169,11 @@ void Maintenance::UnregisterDatabaseMaintenance(
return;
}
+ for (const auto& completeCallback : mCompleteCallbacks) {
+ MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(completeCallback));
+ }
+ mCompleteCallbacks.Clear();
+
mState = State::Finishing;
Finish();
}
@@ -13289,6 +13571,10 @@ nsresult Maintenance::BeginDatabaseMaintenance() {
for (uint32_t index = gFactoryOps->Length(); index > 0; index--) {
CheckedUnsafePtr<FactoryOp>& existingOp = (*gFactoryOps)[index - 1];
+ if (existingOp->DatabaseNameRef().isNothing()) {
+ return false;
+ }
+
if (!existingOp->DatabaseFilePathIsKnown()) {
continue;
}
@@ -14448,14 +14734,17 @@ void DatabaseOperationBase::AutoSetProgressHandler::Unregister() {
FactoryOp::FactoryOp(SafeRefPtr<Factory> aFactory,
const Maybe<ContentParentId>& aContentParentId,
- const CommonFactoryRequestParams& aCommonParams,
- bool aDeleting)
+ const PersistenceType aPersistenceType,
+ const PrincipalInfo& aPrincipalInfo,
+ const Maybe<nsString>& aDatabaseName, bool aDeleting)
: DatabaseOperationBase(aFactory->GetLoggingInfo()->Id(),
aFactory->GetLoggingInfo()->NextRequestSN()),
mFactory(std::move(aFactory)),
mContentParentId(aContentParentId),
- mCommonParams(aCommonParams),
+ mPrincipalInfo(aPrincipalInfo),
+ mDatabaseName(aDatabaseName),
mDirectoryLockId(-1),
+ mPersistenceType(aPersistenceType),
mState(State::Initial),
mWaitingForPermissionRetry(false),
mEnforcingQuota(true),
@@ -14506,7 +14795,7 @@ void FactoryOp::NoteDatabaseClosed(Database* const aDatabase) {
}
DatabaseActorInfo* info;
- MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
+ MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info));
MOZ_ASSERT(info->mWaitingFactoryOp == this);
if (AreActorsAlive()) {
@@ -14547,6 +14836,14 @@ void FactoryOp::StringifyState(nsACString& aResult) const {
aResult.AppendLiteral("DirectoryOpenPending");
return;
+ case State::DirectoryWorkOpen:
+ aResult.AppendLiteral("DirectoryWorkOpen");
+ return;
+
+ case State::DirectoryWorkDone:
+ aResult.AppendLiteral("DirectoryWorkDone");
+ return;
+
case State::DatabaseOpenPending:
aResult.AppendLiteral("DatabaseOpenPending");
return;
@@ -14588,8 +14885,7 @@ void FactoryOp::Stringify(nsACString& aResult) const {
AssertIsOnOwningThread();
aResult.AppendLiteral("PersistenceType:");
- aResult.Append(
- PersistenceTypeToString(mCommonParams.metadata().persistenceType()));
+ aResult.Append(PersistenceTypeToString(mPersistenceType));
aResult.Append(kQuotaGenericDelimiter);
aResult.AppendLiteral("Origin:");
@@ -14617,32 +14913,25 @@ nsresult FactoryOp::Open() {
QuotaManager* const quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
- const DatabaseMetadata& metadata = mCommonParams.metadata();
-
- const PersistenceType persistenceType = metadata.persistenceType();
-
- const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
-
- QM_TRY_UNWRAP(auto principalMetadata,
- quotaManager->GetInfoFromValidatedPrincipalInfo(principalInfo));
+ QM_TRY_UNWRAP(
+ auto principalMetadata,
+ quotaManager->GetInfoFromValidatedPrincipalInfo(mPrincipalInfo));
- mOriginMetadata = {std::move(principalMetadata), persistenceType};
+ mOriginMetadata = {std::move(principalMetadata), mPersistenceType};
- if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
- MOZ_ASSERT(mCommonParams.metadata().persistenceType() ==
- PERSISTENCE_TYPE_PERSISTENT);
+ if (mPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
+ MOZ_ASSERT(mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
mEnforcingQuota = false;
- } else if (principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
+ } else if (mPrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
const ContentPrincipalInfo& contentPrincipalInfo =
- principalInfo.get_ContentPrincipalInfo();
+ mPrincipalInfo.get_ContentPrincipalInfo();
MOZ_ASSERT_IF(
QuotaManager::IsOriginInternal(contentPrincipalInfo.originNoSuffix()),
- mCommonParams.metadata().persistenceType() ==
- PERSISTENCE_TYPE_PERSISTENT);
+ mPersistenceType == PERSISTENCE_TYPE_PERSISTENT);
- mEnforcingQuota = persistenceType != PERSISTENCE_TYPE_PERSISTENT;
+ mEnforcingQuota = mPersistenceType != PERSISTENCE_TYPE_PERSISTENT;
if (mOriginMetadata.mIsPrivate) {
if (StaticPrefs::dom_indexedDB_privateBrowsing_enabled()) {
@@ -14663,31 +14952,39 @@ nsresult FactoryOp::Open() {
MOZ_ASSERT(false);
}
- QuotaManager::GetStorageId(persistenceType, mOriginMetadata.mOrigin,
- Client::IDB, mDatabaseId);
+ if (mDatabaseName.isSome()) {
+ nsCString databaseId;
- mDatabaseId.Append('*');
- mDatabaseId.Append(NS_ConvertUTF16toUTF8(metadata.name()));
+ QuotaManager::GetStorageId(mPersistenceType, mOriginMetadata.mOrigin,
+ Client::IDB, databaseId);
- // Need to get database file path before opening the directory.
- // XXX: For what reason?
- QM_TRY_UNWRAP(
- mDatabaseFilePath,
- ([this, metadata, quotaManager]() -> mozilla::Result<nsString, nsresult> {
- QM_TRY_INSPECT(const auto& dbFile,
- quotaManager->GetOriginDirectory(mOriginMetadata));
+ databaseId.Append('*');
+ databaseId.Append(NS_ConvertUTF16toUTF8(mDatabaseName.ref()));
- QM_TRY(MOZ_TO_RESULT(dbFile->Append(
- NS_LITERAL_STRING_FROM_CSTRING(IDB_DIRECTORY_NAME))));
+ mDatabaseId = Some(std::move(databaseId));
- QM_TRY(MOZ_TO_RESULT(
- dbFile->Append(GetDatabaseFilenameBase(metadata.name(),
- mOriginMetadata.mIsPrivate) +
- kSQLiteSuffix)));
+ // Need to get database file path before opening the directory.
+ // XXX: For what reason?
+ QM_TRY_UNWRAP(
+ auto databaseFilePath,
+ ([this, quotaManager]() -> mozilla::Result<nsString, nsresult> {
+ QM_TRY_INSPECT(const auto& dbFile,
+ quotaManager->GetOriginDirectory(mOriginMetadata));
- QM_TRY_RETURN(
- MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
- }()));
+ QM_TRY(MOZ_TO_RESULT(dbFile->Append(
+ NS_LITERAL_STRING_FROM_CSTRING(IDB_DIRECTORY_NAME))));
+
+ QM_TRY(MOZ_TO_RESULT(dbFile->Append(
+ GetDatabaseFilenameBase(mDatabaseName.ref(),
+ mOriginMetadata.mIsPrivate) +
+ kSQLiteSuffix)));
+
+ QM_TRY_RETURN(
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
+ }()));
+
+ mDatabaseFilePath = Some(std::move(databaseFilePath));
+ }
// Open directory
mState = State::DirectoryOpenPending;
@@ -14711,47 +15008,77 @@ nsresult FactoryOp::DirectoryOpen() {
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::DirectoryOpenPending);
MOZ_ASSERT(mDirectoryLock);
- MOZ_ASSERT(!mDatabaseFilePath.IsEmpty());
+
+ if (mDatabaseName.isNothing()) {
+ QuotaManager* const quotaManager = QuotaManager::Get();
+ MOZ_ASSERT(quotaManager);
+
+ // Must set this before dispatching otherwise we will race with the IO
+ // thread.
+ mState = State::DirectoryWorkOpen;
+
+ QM_TRY(MOZ_TO_RESULT(
+ quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL)),
+ NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, IDB_REPORT_INTERNAL_ERR_LAMBDA);
+
+ return NS_OK;
+ }
+
+ mState = State::DirectoryWorkDone;
+ MOZ_ALWAYS_SUCCEEDS(Run());
+
+ return NS_OK;
+}
+
+nsresult FactoryOp::DirectoryWorkDone() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mState == State::DirectoryWorkDone);
+ MOZ_ASSERT(mDirectoryLock);
MOZ_ASSERT(gFactoryOps);
// See if this FactoryOp needs to wait.
- const bool delayed =
- std::any_of(
- gFactoryOps->rbegin(), gFactoryOps->rend(),
- [foundThis = false, &self = *this](const auto& existingOp) mutable {
- if (existingOp == &self) {
- foundThis = true;
- return false;
- }
+ const bool blocked = [&self = *this] {
+ bool foundThis = false;
+ bool blocked = false;
- if (foundThis && self.MustWaitFor(*existingOp)) {
- // Only one op can be delayed.
- MOZ_ASSERT(!existingOp->mDelayedOp);
- existingOp->mDelayedOp = &self;
- return true;
- }
+ for (const auto& existingOp : Reversed(*gFactoryOps)) {
+ if (existingOp == &self) {
+ foundThis = true;
+ continue;
+ }
- return false;
- }) ||
- [&self = *this] {
- QuotaClient* quotaClient = QuotaClient::GetInstance();
- MOZ_ASSERT(quotaClient);
-
- if (RefPtr<Maintenance> currentMaintenance =
- quotaClient->GetCurrentMaintenance()) {
- if (RefPtr<DatabaseMaintenance> databaseMaintenance =
- currentMaintenance->GetDatabaseMaintenance(
- self.mDatabaseFilePath)) {
- databaseMaintenance->WaitForCompletion(&self);
- return true;
- }
+ if (foundThis && self.MustWaitFor(*existingOp)) {
+ existingOp->AddBlockingOp(self);
+ self.AddBlockedOnOp(*existingOp);
+ blocked = true;
+ }
+ }
+
+ return blocked;
+ }() || [&self = *this] {
+ QuotaClient* quotaClient = QuotaClient::GetInstance();
+ MOZ_ASSERT(quotaClient);
+
+ if (RefPtr<Maintenance> currentMaintenance =
+ quotaClient->GetCurrentMaintenance()) {
+ if (self.mDatabaseName.isSome()) {
+ if (RefPtr<DatabaseMaintenance> databaseMaintenance =
+ currentMaintenance->GetDatabaseMaintenance(
+ self.mDatabaseFilePath.ref())) {
+ databaseMaintenance->WaitForCompletion(&self);
+ return true;
}
+ } else if (currentMaintenance->HasDatabaseMaintenances()) {
+ currentMaintenance->WaitForCompletion(&self);
+ return true;
+ }
+ }
- return false;
- }();
+ return false;
+ }();
mState = State::DatabaseOpenPending;
- if (!delayed) {
+ if (!blocked) {
QM_TRY(MOZ_TO_RESULT(DatabaseOpen()));
}
@@ -14785,22 +15112,23 @@ void FactoryOp::WaitForTransactions() {
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::BeginVersionChange ||
mState == State::WaitingForOtherDatabasesToClose);
- MOZ_ASSERT(!mDatabaseId.IsEmpty());
+ MOZ_ASSERT(!mDatabaseId.ref().IsEmpty());
MOZ_ASSERT(!IsActorDestroyed());
mState = State::WaitingForTransactionsToComplete;
RefPtr<WaitForTransactionsHelper> helper =
- new WaitForTransactionsHelper(mDatabaseId, this);
+ new WaitForTransactionsHelper(mDatabaseId.ref(), this);
helper->WaitForTransactions();
}
void FactoryOp::CleanupMetadata() {
AssertIsOnOwningThread();
- if (mDelayedOp) {
- MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mDelayedOp.forget()));
+ for (const NotNull<RefPtr<FactoryOp>>& blockingOp : mBlocking) {
+ blockingOp->MaybeUnblock(*this);
}
+ mBlocking.Clear();
MOZ_ASSERT(gFactoryOps);
gFactoryOps->RemoveElement(this);
@@ -14868,12 +15196,23 @@ nsresult FactoryOp::SendVersionChangeMessages(
bool FactoryOp::MustWaitFor(const FactoryOp& aExistingOp) {
AssertIsOnOwningThread();
- // Things for the same persistence type, the same origin and the same
- // database must wait.
- return aExistingOp.mCommonParams.metadata().persistenceType() ==
- mCommonParams.metadata().persistenceType() &&
- aExistingOp.mOriginMetadata.mOrigin == mOriginMetadata.mOrigin &&
- aExistingOp.mDatabaseId == mDatabaseId;
+ // If the persistence types don't overlap, the op can proceed.
+ if (aExistingOp.mPersistenceType != mPersistenceType) {
+ return false;
+ }
+
+ // If the origins don't overlap, the op can proceed.
+ if (aExistingOp.mOriginMetadata.mOrigin != mOriginMetadata.mOrigin) {
+ return false;
+ }
+
+ // If the database ids don't overlap, the op can proceed.
+ if (!aExistingOp.mDatabaseId.isNothing() && !mDatabaseId.isNothing() &&
+ aExistingOp.mDatabaseId.ref() != mDatabaseId.ref()) {
+ return false;
+ }
+
+ return true;
}
// Run() assumes that the caller holds a strong reference to the object that
@@ -14905,6 +15244,14 @@ FactoryOp::Run() {
QM_WARNONLY_TRY(MOZ_TO_RESULT(Open()), handleError);
break;
+ case State::DirectoryWorkOpen:
+ QM_WARNONLY_TRY(MOZ_TO_RESULT(DoDirectoryWork()), handleError);
+ break;
+
+ case State::DirectoryWorkDone:
+ QM_WARNONLY_TRY(MOZ_TO_RESULT(DirectoryWorkDone()), handleError);
+ break;
+
case State::DatabaseOpenPending:
QM_WARNONLY_TRY(MOZ_TO_RESULT(DatabaseOpen()), handleError);
break;
@@ -14971,7 +15318,11 @@ void FactoryOp::DirectoryLockFailed() {
MOZ_ALWAYS_SUCCEEDS(Run());
}
-void FactoryOp::ActorDestroy(ActorDestroyReason aWhy) {
+nsresult FactoryRequestOp::DoDirectoryWork() {
+ MOZ_CRASH("Not implemented because this should be unreachable.");
+}
+
+void FactoryRequestOp::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnBackgroundThread();
NoteActorDestroyed();
@@ -14980,8 +15331,8 @@ void FactoryOp::ActorDestroy(ActorDestroyReason aWhy) {
OpenDatabaseOp::OpenDatabaseOp(SafeRefPtr<Factory> aFactory,
const Maybe<ContentParentId>& aContentParentId,
const CommonFactoryRequestParams& aParams)
- : FactoryOp(std::move(aFactory), aContentParentId, aParams,
- /* aDeleting */ false),
+ : FactoryRequestOp(std::move(aFactory), aContentParentId, aParams,
+ /* aDeleting */ false),
mMetadata(MakeSafeRefPtr<FullDatabaseMetadata>(aParams.metadata())),
mRequestedVersion(aParams.metadata().version()),
mVersionChangeOp(nullptr),
@@ -14990,7 +15341,7 @@ OpenDatabaseOp::OpenDatabaseOp(SafeRefPtr<Factory> aFactory,
void OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
- FactoryOp::ActorDestroy(aWhy);
+ FactoryRequestOp::ActorDestroy(aWhy);
if (mVersionChangeOp) {
mVersionChangeOp->NoteActorDestroyed();
@@ -15097,7 +15448,7 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
const auto& databaseFilePath,
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
- MOZ_ASSERT(databaseFilePath == mDatabaseFilePath);
+ MOZ_ASSERT(databaseFilePath == mDatabaseFilePath.ref());
}
#endif
@@ -15114,8 +15465,8 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
if (!fileManager) {
fileManager = MakeSafeRefPtr<DatabaseFileManager>(
- persistenceType, mOriginMetadata, databaseName, mDatabaseId,
- mEnforcingQuota, mInPrivateBrowsing);
+ persistenceType, mOriginMetadata, databaseName, mDatabaseId.ref(),
+ mDatabaseFilePath.ref(), mEnforcingQuota, mInPrivateBrowsing);
}
Maybe<const CipherKey> maybeKey =
@@ -15555,7 +15906,7 @@ nsresult OpenDatabaseOp::BeginVersionChange() {
MOZ_ASSERT(!mDatabase->IsClosed());
DatabaseActorInfo* info;
- MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
+ MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info));
MOZ_ASSERT(info->mLiveDatabases.Contains(mDatabase.unsafeGetRawPtr()));
MOZ_ASSERT(!info->mWaitingFactoryOp);
@@ -15699,9 +16050,9 @@ void OpenDatabaseOp::SendResults() {
MOZ_ASSERT_IF(!HasFailed(), !mVersionChangeTransaction);
DebugOnly<DatabaseActorInfo*> info = nullptr;
- MOZ_ASSERT_IF(
- gLiveDatabaseHashtable && gLiveDatabaseHashtable->Get(mDatabaseId, &info),
- !info->mWaitingFactoryOp);
+ MOZ_ASSERT_IF(mDatabaseId.isSome() && gLiveDatabaseHashtable &&
+ gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info),
+ !info->mWaitingFactoryOp);
if (mVersionChangeTransaction) {
MOZ_ASSERT(HasFailed());
@@ -15720,6 +16071,8 @@ void OpenDatabaseOp::SendResults() {
// need to update the version in our metadata.
mMetadata->mCommonMetadata.version() = mRequestedVersion;
+ mFileManager->UpdateDatabaseVersion(mRequestedVersion);
+
nsresult rv = EnsureDatabaseActorIsAlive();
if (NS_SUCCEEDED(rv)) {
// We successfully opened a database so use its actor as the success
@@ -15767,7 +16120,7 @@ void OpenDatabaseOp::SendResults() {
&OpenDatabaseOp::ConnectionClosedCallback);
RefPtr<WaitForTransactionsHelper> helper =
- new WaitForTransactionsHelper(mDatabaseId, callback);
+ new WaitForTransactionsHelper(mDatabaseId.ref(), callback);
helper->WaitForTransactions();
} else {
CleanupMetadata();
@@ -15792,7 +16145,7 @@ void OpenDatabaseOp::EnsureDatabaseActor() {
mState == State::DatabaseWorkVersionChange ||
mState == State::SendingResults);
MOZ_ASSERT(!HasFailed());
- MOZ_ASSERT(!mDatabaseFilePath.IsEmpty());
+ MOZ_ASSERT(mDatabaseFilePath.isSome());
MOZ_ASSERT(!IsActorDestroyed());
if (mDatabase) {
@@ -15800,13 +16153,13 @@ void OpenDatabaseOp::EnsureDatabaseActor() {
}
MOZ_ASSERT(mMetadata->mDatabaseId.IsEmpty());
- mMetadata->mDatabaseId = mDatabaseId;
+ mMetadata->mDatabaseId = mDatabaseId.ref();
MOZ_ASSERT(mMetadata->mFilePath.IsEmpty());
- mMetadata->mFilePath = mDatabaseFilePath;
+ mMetadata->mFilePath = mDatabaseFilePath.ref();
DatabaseActorInfo* info;
- if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
+ if (gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info)) {
AssertMetadataConsistency(*info->mMetadata);
mMetadata = info->mMetadata.clonePtr();
}
@@ -15833,7 +16186,7 @@ void OpenDatabaseOp::EnsureDatabaseActor() {
// XXX Maybe use LookupOrInsertWith above, to avoid a second lookup here?
info = gLiveDatabaseHashtable
->InsertOrUpdate(
- mDatabaseId,
+ mDatabaseId.ref(),
MakeUnique<DatabaseActorInfo>(
mMetadata.clonePtr(),
WrapNotNullUnchecked(mDatabase.unsafeGetRawPtr())))
@@ -16128,8 +16481,8 @@ void DeleteDatabaseOp::LoadPreviousVersion(nsIFile& aDatabaseFile) {
if (!fileManager) {
fileManager = MakeSafeRefPtr<DatabaseFileManager>(
- persistenceType, mOriginMetadata, databaseName, mDatabaseId,
- mEnforcingQuota, mInPrivateBrowsing);
+ persistenceType, mOriginMetadata, databaseName, mDatabaseId.ref(),
+ mDatabaseFilePath.ref(), mEnforcingQuota, mInPrivateBrowsing);
}
const auto maybeKey =
@@ -16237,7 +16590,7 @@ nsresult DeleteDatabaseOp::DoDatabaseWork() {
const auto& databaseFilePath,
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, dbFile, GetPath));
- MOZ_ASSERT(databaseFilePath == mDatabaseFilePath);
+ MOZ_ASSERT(databaseFilePath == mDatabaseFilePath.ref());
}
#endif
@@ -16271,7 +16624,7 @@ nsresult DeleteDatabaseOp::BeginVersionChange() {
}
DatabaseActorInfo* info;
- if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
+ if (gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info)) {
MOZ_ASSERT(!info->mWaitingFactoryOp);
nsresult rv =
@@ -16345,9 +16698,9 @@ void DeleteDatabaseOp::SendResults() {
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
DebugOnly<DatabaseActorInfo*> info = nullptr;
- MOZ_ASSERT_IF(
- gLiveDatabaseHashtable && gLiveDatabaseHashtable->Get(mDatabaseId, &info),
- !info->mWaitingFactoryOp);
+ MOZ_ASSERT_IF(mDatabaseId.isSome() && gLiveDatabaseHashtable &&
+ gLiveDatabaseHashtable->Get(mDatabaseId.ref(), &info),
+ !info->mWaitingFactoryOp);
if (!IsActorDestroyed()) {
FactoryRequestResponse response;
@@ -16428,7 +16781,7 @@ void DeleteDatabaseOp::VersionChangeOp::RunOnOwningThread() {
// Inform all the other databases that they are now invalidated. That
// should remove the previous metadata from our table.
- if (gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId, &info)) {
+ if (gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId.ref(), &info)) {
MOZ_ASSERT(!info->mLiveDatabases.IsEmpty());
MOZ_ASSERT(!info->mWaitingFactoryOp);
@@ -16454,7 +16807,7 @@ void DeleteDatabaseOp::VersionChangeOp::RunOnOwningThread() {
database->Invalidate();
}
- MOZ_ASSERT(!gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId));
+ MOZ_ASSERT(!gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId.ref()));
}
}
}
@@ -16491,21 +16844,257 @@ nsresult DeleteDatabaseOp::VersionChangeOp::Run() {
return NS_OK;
}
+nsresult GetDatabasesOp::DatabasesNotAvailable() {
+ AssertIsOnIOThread();
+ MOZ_ASSERT(mState == State::DatabaseWorkOpen);
+
+ mState = State::SendingResults;
+
+ QM_TRY(MOZ_TO_RESULT(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)));
+
+ return NS_OK;
+}
+
+nsresult GetDatabasesOp::DoDirectoryWork() {
+ AssertIsOnIOThread();
+ MOZ_ASSERT(mState == State::DirectoryWorkOpen);
+
+ // This state (DirectoryWorkOpen) runs immediately on the I/O thread, before
+ // waiting for existing factory operations to complete (at which point
+ // DoDatabaseWork will be invoked). To match the spec, we must snapshot the
+ // current state of any databases that are being created (version = 0) or
+ // upgraded (version >= 1) now. If we only sampled these values in
+ // DoDatabaseWork, we would only see their post-creation/post-upgrade
+ // versions, which would be incorrect.
+
+ IndexedDatabaseManager* const idm = IndexedDatabaseManager::Get();
+ MOZ_ASSERT(idm);
+
+ const auto& fileManagers =
+ idm->GetFileManagers(mPersistenceType, mOriginMetadata.mOrigin);
+
+ for (const auto& fileManager : fileManagers) {
+ auto& metadata =
+ mDatabaseMetadataTable.LookupOrInsert(fileManager->DatabaseFilePath());
+ metadata.name() = fileManager->DatabaseName();
+ metadata.version() = fileManager->DatabaseVersion();
+ }
+
+ // Must set this before dispatching otherwise we will race with the IO thread.
+ mState = State::DirectoryWorkDone;
+
+ QM_TRY(MOZ_TO_RESULT(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)));
+
+ return NS_OK;
+}
+
+nsresult GetDatabasesOp::DatabaseOpen() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mState == State::DatabaseOpenPending);
+
+ nsresult rv = SendToIOThread();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+nsresult GetDatabasesOp::DoDatabaseWork() {
+ AssertIsOnIOThread();
+ MOZ_ASSERT(mState == State::DatabaseWorkOpen);
+
+ AUTO_PROFILER_LABEL("GetDatabasesOp::DoDatabaseWork", DOM);
+
+ if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
+ !OperationMayProceed()) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ QuotaManager* const quotaManager = QuotaManager::Get();
+ MOZ_ASSERT(quotaManager);
+
+ if (mPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
+ QM_TRY(MOZ_TO_RESULT(
+ quotaManager->EnsureTemporaryStorageIsInitializedInternal()));
+ }
+
+ {
+ QM_TRY_INSPECT(const bool& exists,
+ quotaManager->DoesOriginDirectoryExist(mOriginMetadata));
+ if (!exists) {
+ return DatabasesNotAvailable();
+ }
+ }
+
+ QM_TRY(([&quotaManager, this]()
+ -> mozilla::Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult> {
+ if (mPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+ QM_TRY_RETURN(
+ quotaManager->EnsurePersistentOriginIsInitialized(mOriginMetadata));
+ }
+
+ QM_TRY_RETURN(quotaManager->EnsureTemporaryOriginIsInitialized(
+ mPersistenceType, mOriginMetadata));
+ }()
+ .map([](const auto& res) { return Ok{}; })));
+
+ {
+ QM_TRY_INSPECT(const bool& exists,
+ quotaManager->DoesClientDirectoryExist(
+ ClientMetadata{mOriginMetadata, Client::IDB}));
+ if (!exists) {
+ return DatabasesNotAvailable();
+ }
+ }
+
+ QM_TRY_INSPECT(
+ const auto& clientDirectory,
+ ([&quotaManager, this]()
+ -> mozilla::Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult> {
+ if (mPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
+ QM_TRY_RETURN(quotaManager->EnsurePersistentClientIsInitialized(
+ ClientMetadata{mOriginMetadata, Client::IDB}));
+ }
+
+ QM_TRY_RETURN(quotaManager->EnsureTemporaryClientIsInitialized(
+ ClientMetadata{mOriginMetadata, Client::IDB}));
+ }()
+ .map([](const auto& res) { return res.first; })));
+
+ QM_TRY_INSPECT(
+ (const auto& [subdirsToProcess, databaseFilenames]),
+ QuotaClient::GetDatabaseFilenames(*clientDirectory,
+ /* aCanceled */ Atomic<bool>{false}));
+
+ for (const auto& databaseFilename : databaseFilenames) {
+ QM_TRY_INSPECT(
+ const auto& databaseFile,
+ CloneFileAndAppend(*clientDirectory, databaseFilename + kSQLiteSuffix));
+
+ nsString path;
+ databaseFile->GetPath(path);
+
+ // Use the snapshotted values from DoDirectoryWork which correctly
+ // snapshotted the state of any pending creations/upgrades. This does mean
+ // that we need to skip reporting databases that had a version of 0 at that
+ // time because they were still being created. In the event that any other
+ // creation or upgrade requests are made after our operation is created,
+ // this operation will block those, so it's not possible for this set of
+ // data to get out of sync. The snapshotting (using cached database name
+ // and version in DatabaseFileManager) also guarantees that we are not
+ // touching the SQLite database here on the QuotaManager I/O thread which
+ // is already open on the connection thread.
+
+ auto metadata = mDatabaseMetadataTable.Lookup(path);
+ if (metadata) {
+ if (metadata->version() != 0) {
+ mDatabaseMetadataArray.AppendElement(DatabaseMetadata(
+ metadata->name(), metadata->version(), mPersistenceType));
+ }
+
+ continue;
+ }
+
+ // Since the database is not already open (there was no DatabaseFileManager
+ // for snapshotting in DoDirectoryWork which could provide us with the
+ // database name and version without needing to open the SQLite database),
+ // it is safe and necessary for us to open the database on this thread and
+ // retrieve its name and version. We do not need to worry about racing a
+ // database open because database opens can only be processed on this
+ // thread and we are performing the steps below synchronously.
+
+ QM_TRY_INSPECT(
+ const auto& fmDirectory,
+ CloneFileAndAppend(*clientDirectory,
+ databaseFilename + kFileManagerDirectoryNameSuffix));
+
+ QM_TRY_UNWRAP(
+ const NotNull<nsCOMPtr<mozIStorageConnection>> connection,
+ CreateStorageConnection(*databaseFile, *fmDirectory, VoidString(),
+ mOriginMetadata.mOrigin, mDirectoryLockId,
+ TelemetryIdForFile(databaseFile), Nothing{}));
+
+ {
+ // Load version information.
+ QM_TRY_INSPECT(const auto& stmt,
+ CreateAndExecuteSingleStepStatement<
+ SingleStepResult::ReturnNullIfNoResult>(
+ *connection, "SELECT name, version FROM database"_ns));
+
+ QM_TRY(OkIf(stmt), NS_ERROR_FILE_CORRUPTED);
+
+ QM_TRY_INSPECT(
+ const auto& databaseName,
+ MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsString, stmt, GetString, 0));
+
+ QM_TRY_INSPECT(const int64_t& version,
+ MOZ_TO_RESULT_INVOKE_MEMBER(stmt, GetInt64, 1));
+
+ mDatabaseMetadataArray.AppendElement(
+ DatabaseMetadata(databaseName, version, mPersistenceType));
+ }
+ }
+
+ mState = State::SendingResults;
+
+ QM_TRY(MOZ_TO_RESULT(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)));
+
+ return NS_OK;
+}
+
+nsresult GetDatabasesOp::BeginVersionChange() {
+ MOZ_CRASH("Not implemented because this should be unreachable.");
+}
+
+bool GetDatabasesOp::AreActorsAlive() {
+ MOZ_CRASH("Not implemented because this should be unreachable.");
+}
+
+void GetDatabasesOp::SendBlockedNotification() {
+ MOZ_CRASH("Not implemented because this should be unreachable.");
+}
+
+nsresult GetDatabasesOp::DispatchToWorkThread() {
+ MOZ_CRASH("Not implemented because this should be unreachable.");
+}
+
+void GetDatabasesOp::SendResults() {
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mState == State::SendingResults);
+
+#ifdef DEBUG
+ NoteActorDestroyed();
+#endif
+
+ mResolver(mDatabaseMetadataArray);
+
+ mDirectoryLock = nullptr;
+
+ CleanupMetadata();
+
+ FinishSendResults();
+}
+
TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
- SafeRefPtr<TransactionBase> aTransaction)
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId)
: DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
aTransaction->GetLoggingInfo()->NextRequestSN()),
mTransaction(WrapNotNull(std::move(aTransaction))),
+ mRequestId(aRequestId),
mTransactionIsAborted((*mTransaction)->IsAborted()),
mTransactionLoggingSerialNumber((*mTransaction)->LoggingSerialNumber()) {
MOZ_ASSERT(LoggingSerialNumber());
}
TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
- SafeRefPtr<TransactionBase> aTransaction, uint64_t aLoggingSerialNumber)
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
+ uint64_t aLoggingSerialNumber)
: DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
aLoggingSerialNumber),
mTransaction(WrapNotNull(std::move(aTransaction))),
+ mRequestId(aRequestId),
mTransactionIsAborted((*mTransaction)->IsAborted()),
mTransactionLoggingSerialNumber((*mTransaction)->LoggingSerialNumber()) {}
@@ -16729,7 +17318,7 @@ void TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
mWaitingForContinue = true;
} else {
if (mLoggingSerialNumber) {
- (*mTransaction)->NoteFinishedRequest(mLoggingSerialNumber, ResultCode());
+ (*mTransaction)->NoteFinishedRequest(mRequestId, ResultCode());
}
Cleanup();
@@ -18199,8 +18788,9 @@ mozilla::ipc::IPCResult NormalTransactionOp::RecvContinue(
}
ObjectStoreAddOrPutRequestOp::ObjectStoreAddOrPutRequestOp(
- SafeRefPtr<TransactionBase> aTransaction, RequestParams&& aParams)
- : NormalTransactionOp(std::move(aTransaction)),
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
+ RequestParams&& aParams)
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mParams(
std::move(aParams.type() == RequestParams::TObjectStoreAddParams
? aParams.get_ObjectStoreAddParams().commonParams()
@@ -18429,6 +19019,11 @@ nsresult ObjectStoreAddOrPutRequestOp::DoDatabaseWork(
}
QM_TRY(key.SetFromInteger(autoIncrementNum));
+
+ // Update index keys if primary key is preserved in child.
+ for (auto& updateInfo : mParams.indexUpdateInfos()) {
+ updateInfo.value().MaybeUpdateAutoIncrementKey(autoIncrementNum);
+ }
} else if (key.IsFloat()) {
double numericKey = key.ToFloat();
numericKey = std::min(numericKey, double(1LL << 53));
@@ -18715,9 +19310,9 @@ ObjectStoreAddOrPutRequestOp::SCInputStream::IsNonBlocking(bool* _retval) {
}
ObjectStoreGetRequestOp::ObjectStoreGetRequestOp(
- SafeRefPtr<TransactionBase> aTransaction, const RequestParams& aParams,
- bool aGetAll)
- : NormalTransactionOp(std::move(aTransaction)),
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
+ const RequestParams& aParams, bool aGetAll)
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mObjectStoreId(aGetAll
? aParams.get_ObjectStoreGetAllParams().objectStoreId()
: aParams.get_ObjectStoreGetParams().objectStoreId()),
@@ -18887,9 +19482,9 @@ void ObjectStoreGetRequestOp::GetResponse(RequestResponse& aResponse,
}
ObjectStoreGetKeyRequestOp::ObjectStoreGetKeyRequestOp(
- SafeRefPtr<TransactionBase> aTransaction, const RequestParams& aParams,
- bool aGetAll)
- : NormalTransactionOp(std::move(aTransaction)),
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
+ const RequestParams& aParams, bool aGetAll)
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mObjectStoreId(
aGetAll ? aParams.get_ObjectStoreGetAllKeysParams().objectStoreId()
: aParams.get_ObjectStoreGetKeyParams().objectStoreId()),
@@ -18975,9 +19570,9 @@ void ObjectStoreGetKeyRequestOp::GetResponse(RequestResponse& aResponse,
}
ObjectStoreDeleteRequestOp::ObjectStoreDeleteRequestOp(
- SafeRefPtr<TransactionBase> aTransaction,
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
const ObjectStoreDeleteParams& aParams)
- : NormalTransactionOp(std::move(aTransaction)),
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mParams(aParams),
mObjectStoreMayHaveIndexes(false) {
AssertIsOnBackgroundThread();
@@ -19036,9 +19631,9 @@ nsresult ObjectStoreDeleteRequestOp::DoDatabaseWork(
}
ObjectStoreClearRequestOp::ObjectStoreClearRequestOp(
- SafeRefPtr<TransactionBase> aTransaction,
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
const ObjectStoreClearParams& aParams)
- : NormalTransactionOp(std::move(aTransaction)),
+ : NormalTransactionOp(std::move(aTransaction), aRequestId),
mParams(aParams),
mObjectStoreMayHaveIndexes(false) {
AssertIsOnBackgroundThread();
@@ -19209,8 +19804,9 @@ SafeRefPtr<FullIndexMetadata> IndexRequestOpBase::IndexMetadataForParams(
}
IndexGetRequestOp::IndexGetRequestOp(SafeRefPtr<TransactionBase> aTransaction,
+ const int64_t aRequestId,
const RequestParams& aParams, bool aGetAll)
- : IndexRequestOpBase(std::move(aTransaction), aParams),
+ : IndexRequestOpBase(std::move(aTransaction), aRequestId, aParams),
mDatabase(Transaction().GetDatabasePtr()),
mOptionalKeyRange(aGetAll
? aParams.get_IndexGetAllParams().optionalKeyRange()
@@ -19339,9 +19935,9 @@ void IndexGetRequestOp::GetResponse(RequestResponse& aResponse,
}
IndexGetKeyRequestOp::IndexGetKeyRequestOp(
- SafeRefPtr<TransactionBase> aTransaction, const RequestParams& aParams,
- bool aGetAll)
- : IndexRequestOpBase(std::move(aTransaction), aParams),
+ SafeRefPtr<TransactionBase> aTransaction, const int64_t aRequestId,
+ const RequestParams& aParams, bool aGetAll)
+ : IndexRequestOpBase(std::move(aTransaction), aRequestId, aParams),
mOptionalKeyRange(
aGetAll ? aParams.get_IndexGetAllKeysParams().optionalKeyRange()
: Some(aParams.get_IndexGetKeyParams().keyRange())),