1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/IDBTransaction.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,501 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_dom_indexeddb_idbtransaction_h__ 1.11 +#define mozilla_dom_indexeddb_idbtransaction_h__ 1.12 + 1.13 +#include "mozilla/Attributes.h" 1.14 +#include "mozilla/dom/indexedDB/IndexedDatabase.h" 1.15 + 1.16 +#include "mozIStorageConnection.h" 1.17 +#include "mozIStorageStatement.h" 1.18 +#include "mozIStorageFunction.h" 1.19 +#include "mozilla/dom/DOMError.h" 1.20 +#include "nsIRunnable.h" 1.21 + 1.22 +#include "nsAutoPtr.h" 1.23 +#include "nsClassHashtable.h" 1.24 +#include "nsHashKeys.h" 1.25 +#include "nsInterfaceHashtable.h" 1.26 +#include "nsRefPtrHashtable.h" 1.27 + 1.28 +#include "mozilla/dom/IDBTransactionBinding.h" 1.29 +#include "mozilla/dom/indexedDB/IDBDatabase.h" 1.30 +#include "mozilla/dom/indexedDB/IDBWrapperCache.h" 1.31 +#include "mozilla/dom/indexedDB/FileInfo.h" 1.32 + 1.33 +class nsIThread; 1.34 +class nsPIDOMWindow; 1.35 + 1.36 +namespace mozilla { 1.37 +class EventChainPreVisitor; 1.38 +} // namespace mozilla 1.39 + 1.40 +BEGIN_INDEXEDDB_NAMESPACE 1.41 + 1.42 +class AsyncConnectionHelper; 1.43 +class CommitHelper; 1.44 +class IDBRequest; 1.45 +class IndexedDBDatabaseChild; 1.46 +class IndexedDBTransactionChild; 1.47 +class IndexedDBTransactionParent; 1.48 +struct ObjectStoreInfo; 1.49 +class TransactionThreadPool; 1.50 +class UpdateRefcountFunction; 1.51 + 1.52 +class IDBTransactionListener 1.53 +{ 1.54 +public: 1.55 + NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; 1.56 + NS_IMETHOD_(MozExternalRefCountType) Release() = 0; 1.57 + 1.58 + // Called just before dispatching the final events on the transaction. 1.59 + virtual nsresult NotifyTransactionPreComplete(IDBTransaction* aTransaction) = 0; 1.60 + // Called just after dispatching the final events on the transaction. 1.61 + virtual nsresult NotifyTransactionPostComplete(IDBTransaction* aTransaction) = 0; 1.62 +}; 1.63 + 1.64 +class IDBTransaction : public IDBWrapperCache, 1.65 + public nsIRunnable 1.66 +{ 1.67 + friend class AsyncConnectionHelper; 1.68 + friend class CommitHelper; 1.69 + friend class IndexedDBDatabaseChild; 1.70 + friend class ThreadObserver; 1.71 + friend class TransactionThreadPool; 1.72 + 1.73 +public: 1.74 + NS_DECL_ISUPPORTS_INHERITED 1.75 + NS_DECL_NSIRUNNABLE 1.76 + 1.77 + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache) 1.78 + 1.79 + enum Mode 1.80 + { 1.81 + READ_ONLY = 0, 1.82 + READ_WRITE, 1.83 + VERSION_CHANGE, 1.84 + 1.85 + // Only needed for IPC serialization helper, should never be used in code. 1.86 + MODE_INVALID 1.87 + }; 1.88 + 1.89 + enum ReadyState 1.90 + { 1.91 + INITIAL = 0, 1.92 + LOADING, 1.93 + COMMITTING, 1.94 + DONE 1.95 + }; 1.96 + 1.97 + static already_AddRefed<IDBTransaction> 1.98 + Create(IDBDatabase* aDatabase, 1.99 + const Sequence<nsString>& aObjectStoreNames, 1.100 + Mode aMode, 1.101 + bool aDispatchDelayed) 1.102 + { 1.103 + return CreateInternal(aDatabase, aObjectStoreNames, aMode, aDispatchDelayed, 1.104 + false); 1.105 + } 1.106 + 1.107 + // nsIDOMEventTarget 1.108 + virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE; 1.109 + 1.110 + void OnNewRequest(); 1.111 + void OnRequestFinished(); 1.112 + void OnRequestDisconnected(); 1.113 + 1.114 + void RemoveObjectStore(const nsAString& aName); 1.115 + 1.116 + void SetTransactionListener(IDBTransactionListener* aListener); 1.117 + 1.118 + bool StartSavepoint(); 1.119 + nsresult ReleaseSavepoint(); 1.120 + void RollbackSavepoint(); 1.121 + 1.122 + // Only meant to be called on mStorageThread! 1.123 + nsresult GetOrCreateConnection(mozIStorageConnection** aConnection); 1.124 + 1.125 + already_AddRefed<mozIStorageStatement> 1.126 + GetCachedStatement(const nsACString& aQuery); 1.127 + 1.128 + template<int N> 1.129 + already_AddRefed<mozIStorageStatement> 1.130 + GetCachedStatement(const char (&aQuery)[N]) 1.131 + { 1.132 + return GetCachedStatement(NS_LITERAL_CSTRING(aQuery)); 1.133 + } 1.134 + 1.135 + bool IsOpen() const; 1.136 + 1.137 + bool IsFinished() const 1.138 + { 1.139 + return mReadyState > LOADING; 1.140 + } 1.141 + 1.142 + bool IsWriteAllowed() const 1.143 + { 1.144 + return mMode == READ_WRITE || mMode == VERSION_CHANGE; 1.145 + } 1.146 + 1.147 + bool IsAborted() const 1.148 + { 1.149 + return NS_FAILED(mAbortCode); 1.150 + } 1.151 + 1.152 + // 'Get' prefix is to avoid name collisions with the enum 1.153 + Mode GetMode() 1.154 + { 1.155 + return mMode; 1.156 + } 1.157 + 1.158 + IDBDatabase* Database() 1.159 + { 1.160 + NS_ASSERTION(mDatabase, "This should never be null!"); 1.161 + return mDatabase; 1.162 + } 1.163 + 1.164 + DatabaseInfo* DBInfo() const 1.165 + { 1.166 + return mDatabaseInfo; 1.167 + } 1.168 + 1.169 + already_AddRefed<IDBObjectStore> 1.170 + GetOrCreateObjectStore(const nsAString& aName, 1.171 + ObjectStoreInfo* aObjectStoreInfo, 1.172 + bool aCreating); 1.173 + 1.174 + already_AddRefed<FileInfo> GetFileInfo(nsIDOMBlob* aBlob); 1.175 + void AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo); 1.176 + 1.177 + void ClearCreatedFileInfos(); 1.178 + 1.179 + void 1.180 + SetActor(IndexedDBTransactionChild* aActorChild) 1.181 + { 1.182 + NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!"); 1.183 + mActorChild = aActorChild; 1.184 + } 1.185 + 1.186 + void 1.187 + SetActor(IndexedDBTransactionParent* aActorParent) 1.188 + { 1.189 + NS_ASSERTION(!aActorParent || !mActorParent, 1.190 + "Shouldn't have more than one!"); 1.191 + mActorParent = aActorParent; 1.192 + } 1.193 + 1.194 + IndexedDBTransactionChild* 1.195 + GetActorChild() const 1.196 + { 1.197 + return mActorChild; 1.198 + } 1.199 + 1.200 + IndexedDBTransactionParent* 1.201 + GetActorParent() const 1.202 + { 1.203 + return mActorParent; 1.204 + } 1.205 + 1.206 + nsresult 1.207 + Abort(IDBRequest* aRequest); 1.208 + 1.209 + nsresult 1.210 + Abort(nsresult aAbortCode); 1.211 + 1.212 + nsresult 1.213 + GetAbortCode() const 1.214 + { 1.215 + return mAbortCode; 1.216 + } 1.217 + 1.218 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.219 + uint64_t 1.220 + GetSerialNumber() const 1.221 + { 1.222 + return mSerialNumber; 1.223 + } 1.224 +#endif 1.225 + 1.226 + // nsWrapperCache 1.227 + virtual JSObject* 1.228 + WrapObject(JSContext* aCx) MOZ_OVERRIDE; 1.229 + 1.230 + // WebIDL 1.231 + nsPIDOMWindow* 1.232 + GetParentObject() const 1.233 + { 1.234 + return GetOwner(); 1.235 + } 1.236 + 1.237 + IDBTransactionMode 1.238 + GetMode(ErrorResult& aRv) const; 1.239 + 1.240 + IDBDatabase* 1.241 + Db() const 1.242 + { 1.243 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.244 + return mDatabase; 1.245 + } 1.246 + 1.247 + DOMError* 1.248 + GetError(ErrorResult& aRv); 1.249 + 1.250 + already_AddRefed<IDBObjectStore> 1.251 + ObjectStore(const nsAString& aName, ErrorResult& aRv); 1.252 + 1.253 + void 1.254 + Abort(ErrorResult& aRv) 1.255 + { 1.256 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.257 + aRv = AbortInternal(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, nullptr); 1.258 + } 1.259 + 1.260 + IMPL_EVENT_HANDLER(abort) 1.261 + IMPL_EVENT_HANDLER(complete) 1.262 + IMPL_EVENT_HANDLER(error) 1.263 + 1.264 + already_AddRefed<DOMStringList> 1.265 + GetObjectStoreNames(ErrorResult& aRv); 1.266 + 1.267 +private: 1.268 + nsresult 1.269 + AbortInternal(nsresult aAbortCode, 1.270 + already_AddRefed<mozilla::dom::DOMError> aError); 1.271 + 1.272 + // Should only be called directly through IndexedDBDatabaseChild. 1.273 + static already_AddRefed<IDBTransaction> 1.274 + CreateInternal(IDBDatabase* aDatabase, 1.275 + const Sequence<nsString>& aObjectStoreNames, 1.276 + Mode aMode, 1.277 + bool aDispatchDelayed, 1.278 + bool aIsVersionChangeTransactionChild); 1.279 + 1.280 + IDBTransaction(IDBDatabase* aDatabase); 1.281 + ~IDBTransaction(); 1.282 + 1.283 + nsresult CommitOrRollback(); 1.284 + 1.285 + nsRefPtr<IDBDatabase> mDatabase; 1.286 + nsRefPtr<DatabaseInfo> mDatabaseInfo; 1.287 + nsRefPtr<DOMError> mError; 1.288 + nsTArray<nsString> mObjectStoreNames; 1.289 + ReadyState mReadyState; 1.290 + Mode mMode; 1.291 + uint32_t mPendingRequests; 1.292 + 1.293 + nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement> 1.294 + mCachedStatements; 1.295 + 1.296 + nsRefPtr<IDBTransactionListener> mListener; 1.297 + 1.298 + // Only touched on the database thread. 1.299 + nsCOMPtr<mozIStorageConnection> mConnection; 1.300 + 1.301 + // Only touched on the database thread. 1.302 + uint32_t mSavepointCount; 1.303 + 1.304 + nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores; 1.305 + nsTArray<nsRefPtr<IDBObjectStore> > mDeletedObjectStores; 1.306 + 1.307 + nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction; 1.308 + nsRefPtrHashtable<nsISupportsHashKey, FileInfo> mCreatedFileInfos; 1.309 + 1.310 + IndexedDBTransactionChild* mActorChild; 1.311 + IndexedDBTransactionParent* mActorParent; 1.312 + 1.313 + nsresult mAbortCode; 1.314 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.315 + uint64_t mSerialNumber; 1.316 +#endif 1.317 + bool mCreating; 1.318 + 1.319 +#ifdef DEBUG 1.320 + bool mFiredCompleteOrAbort; 1.321 +#endif 1.322 +}; 1.323 + 1.324 +class CommitHelper MOZ_FINAL : public nsIRunnable 1.325 +{ 1.326 +public: 1.327 + NS_DECL_THREADSAFE_ISUPPORTS 1.328 + NS_DECL_NSIRUNNABLE 1.329 + 1.330 + CommitHelper(IDBTransaction* aTransaction, 1.331 + IDBTransactionListener* aListener, 1.332 + const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores); 1.333 + CommitHelper(IDBTransaction* aTransaction, 1.334 + nsresult aAbortCode); 1.335 + ~CommitHelper(); 1.336 + 1.337 + template<class T> 1.338 + bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr) 1.339 + { 1.340 + if (aCOMPtr) { 1.341 + if (!mDoomedObjects.AppendElement(do_QueryInterface(aCOMPtr))) { 1.342 + NS_ERROR("Out of memory!"); 1.343 + return false; 1.344 + } 1.345 + aCOMPtr = nullptr; 1.346 + } 1.347 + return true; 1.348 + } 1.349 + 1.350 +private: 1.351 + // Writes new autoincrement counts to database 1.352 + nsresult WriteAutoIncrementCounts(); 1.353 + 1.354 + // Updates counts after a successful commit 1.355 + void CommitAutoIncrementCounts(); 1.356 + 1.357 + // Reverts counts when a transaction is aborted 1.358 + void RevertAutoIncrementCounts(); 1.359 + 1.360 + nsRefPtr<IDBTransaction> mTransaction; 1.361 + nsRefPtr<IDBTransactionListener> mListener; 1.362 + nsCOMPtr<mozIStorageConnection> mConnection; 1.363 + nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction; 1.364 + nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects; 1.365 + nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores; 1.366 + 1.367 + nsresult mAbortCode; 1.368 +}; 1.369 + 1.370 +class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction 1.371 +{ 1.372 +public: 1.373 + NS_DECL_THREADSAFE_ISUPPORTS 1.374 + NS_DECL_MOZISTORAGEFUNCTION 1.375 + 1.376 + UpdateRefcountFunction(FileManager* aFileManager) 1.377 + : mFileManager(aFileManager), mInSavepoint(false) 1.378 + { } 1.379 + 1.380 + ~UpdateRefcountFunction() 1.381 + { } 1.382 + 1.383 + void StartSavepoint() 1.384 + { 1.385 + MOZ_ASSERT(!mInSavepoint); 1.386 + MOZ_ASSERT(!mSavepointEntriesIndex.Count()); 1.387 + 1.388 + mInSavepoint = true; 1.389 + } 1.390 + 1.391 + void ReleaseSavepoint() 1.392 + { 1.393 + MOZ_ASSERT(mInSavepoint); 1.394 + 1.395 + mSavepointEntriesIndex.Clear(); 1.396 + 1.397 + mInSavepoint = false; 1.398 + } 1.399 + 1.400 + void RollbackSavepoint() 1.401 + { 1.402 + MOZ_ASSERT(mInSavepoint); 1.403 + 1.404 + mInSavepoint = false; 1.405 + 1.406 + mSavepointEntriesIndex.EnumerateRead(RollbackSavepointCallback, nullptr); 1.407 + 1.408 + mSavepointEntriesIndex.Clear(); 1.409 + } 1.410 + 1.411 + void ClearFileInfoEntries() 1.412 + { 1.413 + mFileInfoEntries.Clear(); 1.414 + } 1.415 + 1.416 + nsresult WillCommit(mozIStorageConnection* aConnection); 1.417 + void DidCommit(); 1.418 + void DidAbort(); 1.419 + 1.420 +private: 1.421 + class FileInfoEntry 1.422 + { 1.423 + public: 1.424 + FileInfoEntry(FileInfo* aFileInfo) 1.425 + : mFileInfo(aFileInfo), mDelta(0), mSavepointDelta(0) 1.426 + { } 1.427 + 1.428 + ~FileInfoEntry() 1.429 + { } 1.430 + 1.431 + nsRefPtr<FileInfo> mFileInfo; 1.432 + int32_t mDelta; 1.433 + int32_t mSavepointDelta; 1.434 + }; 1.435 + 1.436 + enum UpdateType { 1.437 + eIncrement, 1.438 + eDecrement 1.439 + }; 1.440 + 1.441 + class DatabaseUpdateFunction 1.442 + { 1.443 + public: 1.444 + DatabaseUpdateFunction(mozIStorageConnection* aConnection, 1.445 + UpdateRefcountFunction* aFunction) 1.446 + : mConnection(aConnection), mFunction(aFunction), mErrorCode(NS_OK) 1.447 + { } 1.448 + 1.449 + bool Update(int64_t aId, int32_t aDelta); 1.450 + nsresult ErrorCode() 1.451 + { 1.452 + return mErrorCode; 1.453 + } 1.454 + 1.455 + private: 1.456 + nsresult UpdateInternal(int64_t aId, int32_t aDelta); 1.457 + 1.458 + nsCOMPtr<mozIStorageConnection> mConnection; 1.459 + nsCOMPtr<mozIStorageStatement> mUpdateStatement; 1.460 + nsCOMPtr<mozIStorageStatement> mSelectStatement; 1.461 + nsCOMPtr<mozIStorageStatement> mInsertStatement; 1.462 + 1.463 + UpdateRefcountFunction* mFunction; 1.464 + 1.465 + nsresult mErrorCode; 1.466 + }; 1.467 + 1.468 + nsresult ProcessValue(mozIStorageValueArray* aValues, 1.469 + int32_t aIndex, 1.470 + UpdateType aUpdateType); 1.471 + 1.472 + nsresult CreateJournals(); 1.473 + 1.474 + nsresult RemoveJournals(const nsTArray<int64_t>& aJournals); 1.475 + 1.476 + static PLDHashOperator 1.477 + DatabaseUpdateCallback(const uint64_t& aKey, 1.478 + FileInfoEntry* aValue, 1.479 + void* aUserArg); 1.480 + 1.481 + static PLDHashOperator 1.482 + FileInfoUpdateCallback(const uint64_t& aKey, 1.483 + FileInfoEntry* aValue, 1.484 + void* aUserArg); 1.485 + 1.486 + static PLDHashOperator 1.487 + RollbackSavepointCallback(const uint64_t& aKey, 1.488 + FileInfoEntry* aValue, 1.489 + void* aUserArg); 1.490 + 1.491 + FileManager* mFileManager; 1.492 + nsClassHashtable<nsUint64HashKey, FileInfoEntry> mFileInfoEntries; 1.493 + nsDataHashtable<nsUint64HashKey, FileInfoEntry*> mSavepointEntriesIndex; 1.494 + 1.495 + nsTArray<int64_t> mJournalsToCreateBeforeCommit; 1.496 + nsTArray<int64_t> mJournalsToRemoveAfterCommit; 1.497 + nsTArray<int64_t> mJournalsToRemoveAfterAbort; 1.498 + 1.499 + bool mInSavepoint; 1.500 +}; 1.501 + 1.502 +END_INDEXEDDB_NAMESPACE 1.503 + 1.504 +#endif // mozilla_dom_indexeddb_idbtransaction_h__