IDBTransaction.h (11091B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_idbtransaction_h__ 8 #define mozilla_dom_idbtransaction_h__ 9 10 #include "FlippedOnce.h" 11 #include "SafeRefPtr.h" 12 #include "mozilla/DOMEventTargetHelper.h" 13 #include "mozilla/SourceLocation.h" 14 #include "mozilla/dom/IDBTransactionBinding.h" 15 #include "mozilla/dom/quota/CheckedUnsafePtr.h" 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsIRunnable.h" 18 #include "nsString.h" 19 #include "nsTArray.h" 20 21 namespace mozilla { 22 23 class ErrorResult; 24 class EventChainPreVisitor; 25 26 namespace dom { 27 28 class DOMException; 29 class DOMStringList; 30 class IDBCursor; 31 class IDBDatabase; 32 class IDBObjectStore; 33 class IDBOpenDBRequest; 34 class IDBRequest; 35 class StrongWorkerRef; 36 37 namespace indexedDB { 38 class PBackgroundIDBCursorChild; 39 class BackgroundRequestChild; 40 class BackgroundTransactionChild; 41 class BackgroundVersionChangeTransactionChild; 42 class IndexMetadata; 43 class ObjectStoreSpec; 44 class OpenCursorParams; 45 class RequestParams; 46 } // namespace indexedDB 47 48 class IDBTransaction final 49 : public DOMEventTargetHelper, 50 public nsIRunnable, 51 public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> { 52 friend class indexedDB::BackgroundRequestChild; 53 54 public: 55 enum struct Mode { 56 ReadOnly = 0, 57 ReadWrite, 58 ReadWriteFlush, 59 Cleanup, 60 VersionChange, 61 62 // Only needed for IPC serialization helper, should never be used in code. 63 Invalid 64 }; 65 66 enum struct Durability { 67 Default = 0, 68 Strict, 69 Relaxed, 70 71 // Only needed for IPC serialization helper, should never be used in code. 72 Invalid 73 }; 74 75 enum struct ReadyState { Active, Inactive, Committing, Finished }; 76 77 private: 78 // TODO: Only non-const because of Bug 1575173. 79 RefPtr<IDBDatabase> mDatabase; 80 RefPtr<DOMException> mError; 81 const nsTArray<nsString> mObjectStoreNames; 82 nsTArray<RefPtr<IDBObjectStore>> mObjectStores; 83 nsTArray<RefPtr<IDBObjectStore>> mDeletedObjectStores; 84 RefPtr<StrongWorkerRef> mWorkerRef; 85 nsTArray<NotNull<IDBCursor*>> mCursors; 86 87 // Tagged with mMode. If mMode is Mode::VersionChange then mBackgroundActor 88 // will be a BackgroundVersionChangeTransactionChild. Otherwise it will be a 89 // BackgroundTransactionChild. 90 union { 91 indexedDB::BackgroundTransactionChild* mNormalBackgroundActor; 92 indexedDB::BackgroundVersionChangeTransactionChild* 93 mVersionChangeBackgroundActor; 94 } mBackgroundActor; 95 96 const int64_t mLoggingSerialNumber; 97 98 // Only used for Mode::VersionChange transactions. 99 int64_t mNextObjectStoreId; 100 int64_t mNextIndexId; 101 102 // Request ids are issued starting from 0 and incremented by one as we send 103 // actor creation messages to the parent process. Used to support the 104 // explicit commit() request. 105 int64_t mNextRequestId; 106 107 nsresult mAbortCode; ///< The result that caused the transaction to be 108 ///< aborted, or NS_OK if not aborted. 109 ///< NS_ERROR_DOM_INDEXEDDB_ABORT_ERR indicates that the 110 ///< user explicitly requested aborting. Should be 111 ///< renamed to mResult or so, because it is actually 112 ///< used to check if the transaction has been aborted. 113 uint32_t mPendingRequestCount; ///< Counted via OnNewRequest and 114 ///< OnRequestFinished, so that the 115 ///< transaction can auto-commit when the last 116 ///< pending request finished. 117 118 const JSCallingLocation mCallerLocation; 119 120 ReadyState mReadyState = ReadyState::Active; 121 FlippedOnce<false> mStarted; 122 const Mode mMode; 123 const Durability mDurability; 124 125 bool mRegistered; ///< Whether mDatabase->RegisterTransaction() has been 126 ///< called (which may not be the case if construction was 127 ///< incomplete). 128 FlippedOnce<false> mAbortedByScript; 129 bool mNotedActiveTransaction; 130 FlippedOnce<false> mSentCommitOrAbort; 131 132 #ifdef DEBUG 133 FlippedOnce<false> mFiredCompleteOrAbort; 134 FlippedOnce<false> mWasExplicitlyCommitted; 135 #endif 136 137 public: 138 [[nodiscard]] static SafeRefPtr<IDBTransaction> CreateVersionChange( 139 IDBDatabase* aDatabase, 140 indexedDB::BackgroundVersionChangeTransactionChild* aActor, 141 NotNull<IDBOpenDBRequest*> aOpenRequest, int64_t aNextObjectStoreId, 142 int64_t aNextIndexId); 143 144 [[nodiscard]] static SafeRefPtr<IDBTransaction> Create( 145 JSContext* aCx, IDBDatabase* aDatabase, 146 const nsTArray<nsString>& aObjectStoreNames, Mode aMode, 147 Durability aDurability); 148 149 static Maybe<IDBTransaction&> MaybeCurrent(); 150 151 void AssertIsOnOwningThread() const 152 #ifdef DEBUG 153 ; 154 #else 155 { 156 } 157 #endif 158 159 void SetBackgroundActor( 160 indexedDB::BackgroundTransactionChild* aBackgroundActor); 161 162 void ClearBackgroundActor() { 163 AssertIsOnOwningThread(); 164 165 if (mMode == Mode::VersionChange) { 166 mBackgroundActor.mVersionChangeBackgroundActor = nullptr; 167 } else { 168 mBackgroundActor.mNormalBackgroundActor = nullptr; 169 } 170 171 // Note inactive transaction here if we didn't receive the Complete message 172 // from the parent. 173 MaybeNoteInactiveTransaction(); 174 } 175 176 indexedDB::BackgroundRequestChild* StartRequest( 177 MovingNotNull<RefPtr<mozilla::dom::IDBRequest>> aRequest, 178 const indexedDB::RequestParams& aParams); 179 180 void OpenCursor(indexedDB::PBackgroundIDBCursorChild& aBackgroundActor, 181 const indexedDB::OpenCursorParams& aParams); 182 183 void RefreshSpec(bool aMayDelete); 184 185 bool IsCommittingOrFinished() const { 186 AssertIsOnOwningThread(); 187 188 return mReadyState == ReadyState::Committing || 189 mReadyState == ReadyState::Finished; 190 } 191 192 bool IsActive() const { 193 AssertIsOnOwningThread(); 194 195 return mReadyState == ReadyState::Active; 196 } 197 198 bool IsInactive() const { 199 AssertIsOnOwningThread(); 200 201 return mReadyState == ReadyState::Inactive; 202 } 203 204 bool IsFinished() const { 205 AssertIsOnOwningThread(); 206 207 return mReadyState == ReadyState::Finished; 208 } 209 210 bool IsWriteAllowed() const { 211 AssertIsOnOwningThread(); 212 return mMode == Mode::ReadWrite || mMode == Mode::ReadWriteFlush || 213 mMode == Mode::Cleanup || mMode == Mode::VersionChange; 214 } 215 216 bool IsAborted() const { 217 AssertIsOnOwningThread(); 218 return NS_FAILED(mAbortCode); 219 } 220 221 #ifdef DEBUG 222 bool WasExplicitlyCommitted() const { return mWasExplicitlyCommitted; } 223 #endif 224 225 void TransitionToActive() { 226 MOZ_ASSERT(mReadyState == ReadyState::Inactive); 227 mReadyState = ReadyState::Active; 228 } 229 230 void TransitionToInactive() { 231 MOZ_ASSERT(mReadyState == ReadyState::Active); 232 mReadyState = ReadyState::Inactive; 233 } 234 235 nsresult AbortCode() const { 236 AssertIsOnOwningThread(); 237 return mAbortCode; 238 } 239 240 const JSCallingLocation& GetCallerLocation() const { 241 AssertIsOnOwningThread(); 242 return mCallerLocation; 243 } 244 245 // 'Get' prefix is to avoid name collisions with the enum 246 Mode GetMode() const { 247 AssertIsOnOwningThread(); 248 return mMode; 249 } 250 251 Durability GetDurability() const { 252 AssertIsOnOwningThread(); 253 return mDurability; 254 } 255 256 uint32_t GetPendingRequestCount() const { return mPendingRequestCount; } 257 258 IDBDatabase* Database() const { 259 AssertIsOnOwningThread(); 260 return mDatabase; 261 } 262 263 // Only for use by ProfilerHelpers.h 264 const nsTArray<nsString>& ObjectStoreNamesInternal() const { 265 AssertIsOnOwningThread(); 266 return mObjectStoreNames; 267 } 268 269 [[nodiscard]] RefPtr<IDBObjectStore> CreateObjectStore( 270 indexedDB::ObjectStoreSpec& aSpec); 271 272 void DeleteObjectStore(int64_t aObjectStoreId); 273 274 void RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName) const; 275 276 void CreateIndex(IDBObjectStore* aObjectStore, 277 const indexedDB::IndexMetadata& aMetadata) const; 278 279 void DeleteIndex(IDBObjectStore* aObjectStore, int64_t aIndexId) const; 280 281 void RenameIndex(IDBObjectStore* aObjectStore, int64_t aIndexId, 282 const nsAString& aName) const; 283 284 void Abort(IDBRequest* aRequest); 285 286 void Abort(nsresult aErrorCode); 287 288 int64_t LoggingSerialNumber() const { 289 AssertIsOnOwningThread(); 290 291 return mLoggingSerialNumber; 292 } 293 294 nsIGlobalObject* GetParentObject() const; 295 296 void FireCompleteOrAbortEvents(nsresult aResult); 297 298 // Only for Mode::VersionChange transactions. 299 int64_t NextObjectStoreId(); 300 301 // Only for Mode::VersionChange transactions. 302 int64_t NextIndexId(); 303 304 // See the comment for mNextRequestId. 305 int64_t NextRequestId(); 306 307 void InvalidateCursorCaches(); 308 void RegisterCursor(IDBCursor& aCursor); 309 void UnregisterCursor(IDBCursor& aCursor); 310 311 NS_DECL_ISUPPORTS_INHERITED 312 NS_DECL_NSIRUNNABLE 313 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, DOMEventTargetHelper) 314 315 void CommitIfNotStarted(); 316 317 // nsWrapperCache 318 JSObject* WrapObject(JSContext* aCx, 319 JS::Handle<JSObject*> aGivenProto) override; 320 321 // Methods bound via WebIDL. 322 IDBDatabase* Db() const { return Database(); } 323 324 IDBTransactionMode GetMode(ErrorResult& aRv) const; 325 326 IDBTransactionDurability GetDurability(ErrorResult& aRv) const; 327 328 DOMException* GetError() const; 329 330 [[nodiscard]] RefPtr<IDBObjectStore> ObjectStore(const nsAString& aName, 331 ErrorResult& aRv); 332 333 void Commit(ErrorResult& aRv); 334 335 void Abort(ErrorResult& aRv); 336 337 IMPL_EVENT_HANDLER(abort) 338 IMPL_EVENT_HANDLER(complete) 339 IMPL_EVENT_HANDLER(error) 340 341 [[nodiscard]] RefPtr<DOMStringList> ObjectStoreNames() const; 342 343 // EventTarget 344 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; 345 346 private: 347 struct CreatedFromFactoryFunction {}; 348 349 public: 350 IDBTransaction(IDBDatabase* aDatabase, 351 const nsTArray<nsString>& aObjectStoreNames, Mode aMode, 352 Durability aDurability, JSCallingLocation&& aCallerLocation, 353 CreatedFromFactoryFunction aDummy); 354 355 private: 356 ~IDBTransaction(); 357 358 void AbortInternal(nsresult aAbortCode, RefPtr<DOMException> aError); 359 360 void SendCommit(bool aAutoCommit); 361 362 void SendAbort(nsresult aResultCode); 363 364 void NoteActiveTransaction(); 365 366 void MaybeNoteInactiveTransaction(); 367 368 // TODO consider making private again, or move to the right place 369 public: 370 void OnNewRequest(); 371 372 void OnRequestFinished(bool aRequestCompletedSuccessfully); 373 374 private: 375 template <typename Func> 376 auto DoWithTransactionChild(const Func& aFunc) const; 377 378 bool HasTransactionChild() const; 379 }; 380 381 inline bool ReferenceEquals(const Maybe<IDBTransaction&>& aLHS, 382 const Maybe<IDBTransaction&>& aRHS) { 383 if (aLHS.isNothing() != aRHS.isNothing()) { 384 return false; 385 } 386 return aLHS.isNothing() || &aLHS.ref() == &aRHS.ref(); 387 } 388 389 } // namespace dom 390 } // namespace mozilla 391 392 #endif // mozilla_dom_idbtransaction_h__