michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_indexeddb_transactionthreadpool_h__ michael@0: #define mozilla_dom_indexeddb_transactionthreadpool_h__ michael@0: michael@0: // Only meant to be included in IndexedDB source files, not exported. michael@0: #include "IndexedDatabase.h" michael@0: michael@0: #include "nsIObserver.h" michael@0: #include "nsIRunnable.h" michael@0: michael@0: #include "mozilla/Monitor.h" michael@0: #include "nsClassHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: michael@0: #include "IDBTransaction.h" michael@0: michael@0: class nsIThreadPool; michael@0: michael@0: BEGIN_INDEXEDDB_NAMESPACE michael@0: michael@0: class FinishTransactionRunnable; michael@0: class QueuedDispatchInfo; michael@0: michael@0: class TransactionThreadPool michael@0: { michael@0: friend class nsAutoPtr; michael@0: friend class FinishTransactionRunnable; michael@0: michael@0: public: michael@0: // returns a non-owning ref! michael@0: static TransactionThreadPool* GetOrCreate(); michael@0: michael@0: // returns a non-owning ref! michael@0: static TransactionThreadPool* Get(); michael@0: michael@0: static void Shutdown(); michael@0: michael@0: nsresult Dispatch(IDBTransaction* aTransaction, michael@0: nsIRunnable* aRunnable, michael@0: bool aFinish, michael@0: nsIRunnable* aFinishRunnable); michael@0: michael@0: void WaitForDatabasesToComplete(nsTArray >& aDatabases, michael@0: nsIRunnable* aCallback); michael@0: michael@0: // Abort all transactions, unless they are already in the process of being michael@0: // committed, for aDatabase. michael@0: void AbortTransactionsForDatabase(IDBDatabase* aDatabase); michael@0: michael@0: // Returns true if there are running or pending transactions for aDatabase. michael@0: bool HasTransactionsForDatabase(IDBDatabase* aDatabase); michael@0: michael@0: protected: michael@0: class TransactionQueue MOZ_FINAL : public nsIRunnable michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: TransactionQueue(IDBTransaction* aTransaction); michael@0: michael@0: void Unblock(); michael@0: michael@0: void Dispatch(nsIRunnable* aRunnable); michael@0: michael@0: void Finish(nsIRunnable* aFinishRunnable); michael@0: michael@0: private: michael@0: mozilla::Monitor mMonitor; michael@0: IDBTransaction* mTransaction; michael@0: nsAutoTArray, 10> mQueue; michael@0: nsCOMPtr mFinishRunnable; michael@0: bool mShouldFinish; michael@0: }; michael@0: michael@0: friend class TransactionQueue; michael@0: michael@0: struct TransactionInfo michael@0: { michael@0: TransactionInfo(IDBTransaction* aTransaction) michael@0: { michael@0: MOZ_COUNT_CTOR(TransactionInfo); michael@0: michael@0: transaction = aTransaction; michael@0: queue = new TransactionQueue(aTransaction); michael@0: } michael@0: michael@0: ~TransactionInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(TransactionInfo); michael@0: } michael@0: michael@0: nsRefPtr transaction; michael@0: nsRefPtr queue; michael@0: nsTHashtable > blockedOn; michael@0: nsTHashtable > blocking; michael@0: }; michael@0: michael@0: struct TransactionInfoPair michael@0: { michael@0: TransactionInfoPair() michael@0: : lastBlockingReads(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(TransactionInfoPair); michael@0: } michael@0: michael@0: ~TransactionInfoPair() michael@0: { michael@0: MOZ_COUNT_DTOR(TransactionInfoPair); michael@0: } michael@0: // Multiple reading transactions can block future writes. michael@0: nsTArray lastBlockingWrites; michael@0: // But only a single writing transaction can block future reads. michael@0: TransactionInfo* lastBlockingReads; michael@0: }; michael@0: michael@0: struct DatabaseTransactionInfo michael@0: { michael@0: DatabaseTransactionInfo() michael@0: { michael@0: MOZ_COUNT_CTOR(DatabaseTransactionInfo); michael@0: } michael@0: michael@0: ~DatabaseTransactionInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(DatabaseTransactionInfo); michael@0: } michael@0: michael@0: typedef nsClassHashtable, TransactionInfo > michael@0: TransactionHashtable; michael@0: TransactionHashtable transactions; michael@0: nsClassHashtable blockingTransactions; michael@0: }; michael@0: michael@0: static PLDHashOperator michael@0: CollectTransactions(IDBTransaction* aKey, michael@0: TransactionInfo* aValue, michael@0: void* aUserArg); michael@0: michael@0: static PLDHashOperator michael@0: FindTransaction(IDBTransaction* aKey, michael@0: TransactionInfo* aValue, michael@0: void* aUserArg); michael@0: michael@0: static PLDHashOperator michael@0: MaybeUnblockTransaction(nsPtrHashKey* aKey, michael@0: void* aUserArg); michael@0: michael@0: struct DatabasesCompleteCallback michael@0: { michael@0: nsTArray > mDatabases; michael@0: nsCOMPtr mCallback; michael@0: }; michael@0: michael@0: TransactionThreadPool(); michael@0: ~TransactionThreadPool(); michael@0: michael@0: nsresult Init(); michael@0: nsresult Cleanup(); michael@0: michael@0: void FinishTransaction(IDBTransaction* aTransaction); michael@0: michael@0: TransactionQueue& GetQueueForTransaction(IDBTransaction* aTransaction); michael@0: michael@0: bool MaybeFireCallback(DatabasesCompleteCallback aCallback); michael@0: michael@0: nsCOMPtr mThreadPool; michael@0: michael@0: nsClassHashtable michael@0: mTransactionsInProgress; michael@0: michael@0: nsTArray mCompleteCallbacks; michael@0: }; michael@0: michael@0: END_INDEXEDDB_NAMESPACE michael@0: michael@0: #endif // mozilla_dom_indexeddb_transactionthreadpool_h__