summaryrefslogtreecommitdiffstats
path: root/dom/indexedDB/IDBTransaction.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/indexedDB/IDBTransaction.h')
-rw-r--r--dom/indexedDB/IDBTransaction.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h
new file mode 100644
index 0000000000..65fefddfe5
--- /dev/null
+++ b/dom/indexedDB/IDBTransaction.h
@@ -0,0 +1,366 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_idbtransaction_h__
+#define mozilla_dom_idbtransaction_h__
+
+#include "FlippedOnce.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/IDBTransactionBinding.h"
+#include "mozilla/dom/quota/CheckedUnsafePtr.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIRunnable.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "SafeRefPtr.h"
+
+namespace mozilla {
+
+class ErrorResult;
+class EventChainPreVisitor;
+
+namespace dom {
+
+class DOMException;
+class DOMStringList;
+class IDBCursor;
+class IDBDatabase;
+class IDBObjectStore;
+class IDBOpenDBRequest;
+class IDBRequest;
+class StrongWorkerRef;
+
+namespace indexedDB {
+class PBackgroundIDBCursorChild;
+class BackgroundRequestChild;
+class BackgroundTransactionChild;
+class BackgroundVersionChangeTransactionChild;
+class IndexMetadata;
+class ObjectStoreSpec;
+class OpenCursorParams;
+class RequestParams;
+} // namespace indexedDB
+
+class IDBTransaction final
+ : public DOMEventTargetHelper,
+ public nsIRunnable,
+ public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> {
+ friend class indexedDB::BackgroundRequestChild;
+
+ public:
+ enum struct Mode {
+ ReadOnly = 0,
+ ReadWrite,
+ ReadWriteFlush,
+ Cleanup,
+ VersionChange,
+
+ // Only needed for IPC serialization helper, should never be used in code.
+ Invalid
+ };
+
+ enum struct ReadyState { Active, Inactive, Committing, Finished };
+
+ private:
+ // TODO: Only non-const because of Bug 1575173.
+ RefPtr<IDBDatabase> mDatabase;
+ RefPtr<DOMException> mError;
+ const nsTArray<nsString> mObjectStoreNames;
+ nsTArray<RefPtr<IDBObjectStore>> mObjectStores;
+ nsTArray<RefPtr<IDBObjectStore>> mDeletedObjectStores;
+ RefPtr<StrongWorkerRef> mWorkerRef;
+ nsTArray<NotNull<IDBCursor*>> mCursors;
+
+ // Tagged with mMode. If mMode is Mode::VersionChange then mBackgroundActor
+ // will be a BackgroundVersionChangeTransactionChild. Otherwise it will be a
+ // BackgroundTransactionChild.
+ union {
+ indexedDB::BackgroundTransactionChild* mNormalBackgroundActor;
+ indexedDB::BackgroundVersionChangeTransactionChild*
+ mVersionChangeBackgroundActor;
+ } mBackgroundActor;
+
+ const int64_t mLoggingSerialNumber;
+
+ // Only used for Mode::VersionChange transactions.
+ int64_t mNextObjectStoreId;
+ int64_t mNextIndexId;
+
+ nsresult mAbortCode; ///< The result that caused the transaction to be
+ ///< aborted, or NS_OK if not aborted.
+ ///< NS_ERROR_DOM_INDEXEDDB_ABORT_ERR indicates that the
+ ///< user explicitly requested aborting. Should be
+ ///< renamed to mResult or so, because it is actually
+ ///< used to check if the transaction has been aborted.
+ uint32_t mPendingRequestCount; ///< Counted via OnNewRequest and
+ ///< OnRequestFinished, so that the
+ ///< transaction can auto-commit when the last
+ ///< pending request finished.
+
+ const nsString mFilename;
+ const uint32_t mLineNo;
+ const uint32_t mColumn;
+
+ ReadyState mReadyState = ReadyState::Active;
+ FlippedOnce<false> mStarted;
+ const Mode mMode;
+
+ bool mRegistered; ///< Whether mDatabase->RegisterTransaction() has been
+ ///< called (which may not be the case if construction was
+ ///< incomplete).
+ FlippedOnce<false> mAbortedByScript;
+ bool mNotedActiveTransaction;
+ FlippedOnce<false> mSentCommitOrAbort;
+
+#ifdef DEBUG
+ FlippedOnce<false> mFiredCompleteOrAbort;
+ FlippedOnce<false> mWasExplicitlyCommitted;
+#endif
+
+ public:
+ [[nodiscard]] static SafeRefPtr<IDBTransaction> CreateVersionChange(
+ IDBDatabase* aDatabase,
+ indexedDB::BackgroundVersionChangeTransactionChild* aActor,
+ NotNull<IDBOpenDBRequest*> aOpenRequest, int64_t aNextObjectStoreId,
+ int64_t aNextIndexId);
+
+ [[nodiscard]] static SafeRefPtr<IDBTransaction> Create(
+ JSContext* aCx, IDBDatabase* aDatabase,
+ const nsTArray<nsString>& aObjectStoreNames, Mode aMode);
+
+ static Maybe<IDBTransaction&> MaybeCurrent();
+
+ void AssertIsOnOwningThread() const
+#ifdef DEBUG
+ ;
+#else
+ {
+ }
+#endif
+
+ void SetBackgroundActor(
+ indexedDB::BackgroundTransactionChild* aBackgroundActor);
+
+ void ClearBackgroundActor() {
+ AssertIsOnOwningThread();
+
+ if (mMode == Mode::VersionChange) {
+ mBackgroundActor.mVersionChangeBackgroundActor = nullptr;
+ } else {
+ mBackgroundActor.mNormalBackgroundActor = nullptr;
+ }
+
+ // Note inactive transaction here if we didn't receive the Complete message
+ // from the parent.
+ MaybeNoteInactiveTransaction();
+ }
+
+ indexedDB::BackgroundRequestChild* StartRequest(
+ MovingNotNull<RefPtr<mozilla::dom::IDBRequest>> aRequest,
+ const indexedDB::RequestParams& aParams);
+
+ void OpenCursor(indexedDB::PBackgroundIDBCursorChild& aBackgroundActor,
+ const indexedDB::OpenCursorParams& aParams);
+
+ void RefreshSpec(bool aMayDelete);
+
+ bool IsCommittingOrFinished() const {
+ AssertIsOnOwningThread();
+
+ return mReadyState == ReadyState::Committing ||
+ mReadyState == ReadyState::Finished;
+ }
+
+ bool IsActive() const {
+ AssertIsOnOwningThread();
+
+ return mReadyState == ReadyState::Active;
+ }
+
+ bool IsInactive() const {
+ AssertIsOnOwningThread();
+
+ return mReadyState == ReadyState::Inactive;
+ }
+
+ bool IsFinished() const {
+ AssertIsOnOwningThread();
+
+ return mReadyState == ReadyState::Finished;
+ }
+
+ bool IsWriteAllowed() const {
+ AssertIsOnOwningThread();
+ return mMode == Mode::ReadWrite || mMode == Mode::ReadWriteFlush ||
+ mMode == Mode::Cleanup || mMode == Mode::VersionChange;
+ }
+
+ bool IsAborted() const {
+ AssertIsOnOwningThread();
+ return NS_FAILED(mAbortCode);
+ }
+
+#ifdef DEBUG
+ bool WasExplicitlyCommitted() const { return mWasExplicitlyCommitted; }
+#endif
+
+ void TransitionToActive() {
+ MOZ_ASSERT(mReadyState == ReadyState::Inactive);
+ mReadyState = ReadyState::Active;
+ }
+
+ void TransitionToInactive() {
+ MOZ_ASSERT(mReadyState == ReadyState::Active);
+ mReadyState = ReadyState::Inactive;
+ }
+
+ nsresult AbortCode() const {
+ AssertIsOnOwningThread();
+ return mAbortCode;
+ }
+
+ void GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
+ uint32_t* aColumn) const;
+
+ // 'Get' prefix is to avoid name collisions with the enum
+ Mode GetMode() const {
+ AssertIsOnOwningThread();
+ return mMode;
+ }
+
+ uint32_t GetPendingRequestCount() const { return mPendingRequestCount; }
+
+ IDBDatabase* Database() const {
+ AssertIsOnOwningThread();
+ return mDatabase;
+ }
+
+ // Only for use by ProfilerHelpers.h
+ const nsTArray<nsString>& ObjectStoreNamesInternal() const {
+ AssertIsOnOwningThread();
+ return mObjectStoreNames;
+ }
+
+ [[nodiscard]] RefPtr<IDBObjectStore> CreateObjectStore(
+ indexedDB::ObjectStoreSpec& aSpec);
+
+ void DeleteObjectStore(int64_t aObjectStoreId);
+
+ void RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName) const;
+
+ void CreateIndex(IDBObjectStore* aObjectStore,
+ const indexedDB::IndexMetadata& aMetadata) const;
+
+ void DeleteIndex(IDBObjectStore* aObjectStore, int64_t aIndexId) const;
+
+ void RenameIndex(IDBObjectStore* aObjectStore, int64_t aIndexId,
+ const nsAString& aName) const;
+
+ void Abort(IDBRequest* aRequest);
+
+ void Abort(nsresult aErrorCode);
+
+ int64_t LoggingSerialNumber() const {
+ AssertIsOnOwningThread();
+
+ return mLoggingSerialNumber;
+ }
+
+ nsIGlobalObject* GetParentObject() const;
+
+ void FireCompleteOrAbortEvents(nsresult aResult);
+
+ // Only for Mode::VersionChange transactions.
+ int64_t NextObjectStoreId();
+
+ // Only for Mode::VersionChange transactions.
+ int64_t NextIndexId();
+
+ void InvalidateCursorCaches();
+ void RegisterCursor(IDBCursor& aCursor);
+ void UnregisterCursor(IDBCursor& aCursor);
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, DOMEventTargetHelper)
+
+ void CommitIfNotStarted();
+
+ // nsWrapperCache
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ // Methods bound via WebIDL.
+ IDBDatabase* Db() const { return Database(); }
+
+ IDBTransactionMode GetMode(ErrorResult& aRv) const;
+
+ DOMException* GetError() const;
+
+ [[nodiscard]] RefPtr<IDBObjectStore> ObjectStore(const nsAString& aName,
+ ErrorResult& aRv);
+
+ void Commit(ErrorResult& aRv);
+
+ void Abort(ErrorResult& aRv);
+
+ IMPL_EVENT_HANDLER(abort)
+ IMPL_EVENT_HANDLER(complete)
+ IMPL_EVENT_HANDLER(error)
+
+ [[nodiscard]] RefPtr<DOMStringList> ObjectStoreNames() const;
+
+ // EventTarget
+ void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
+
+ private:
+ struct CreatedFromFactoryFunction {};
+
+ public:
+ IDBTransaction(IDBDatabase* aDatabase,
+ const nsTArray<nsString>& aObjectStoreNames, Mode aMode,
+ nsString aFilename, uint32_t aLineNo, uint32_t aColumn,
+ CreatedFromFactoryFunction aDummy);
+
+ private:
+ ~IDBTransaction();
+
+ void AbortInternal(nsresult aAbortCode, RefPtr<DOMException> aError);
+
+ void SendCommit(bool aAutoCommit);
+
+ void SendAbort(nsresult aResultCode);
+
+ void NoteActiveTransaction();
+
+ void MaybeNoteInactiveTransaction();
+
+ // TODO consider making private again, or move to the right place
+ public:
+ void OnNewRequest();
+
+ void OnRequestFinished(bool aRequestCompletedSuccessfully);
+
+ private:
+ template <typename Func>
+ auto DoWithTransactionChild(const Func& aFunc) const;
+
+ bool HasTransactionChild() const;
+};
+
+inline bool ReferenceEquals(const Maybe<IDBTransaction&>& aLHS,
+ const Maybe<IDBTransaction&>& aRHS) {
+ if (aLHS.isNothing() != aRHS.isNothing()) {
+ return false;
+ }
+ return aLHS.isNothing() || &aLHS.ref() == &aRHS.ref();
+}
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_idbtransaction_h__