/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=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_indexeddb_transactionthreadpool_h__ #define mozilla_dom_indexeddb_transactionthreadpool_h__ // Only meant to be included in IndexedDB source files, not exported. #include "IndexedDatabase.h" #include "nsIObserver.h" #include "nsIRunnable.h" #include "mozilla/Monitor.h" #include "nsClassHashtable.h" #include "nsHashKeys.h" #include "nsRefPtrHashtable.h" #include "IDBTransaction.h" class nsIThreadPool; BEGIN_INDEXEDDB_NAMESPACE class FinishTransactionRunnable; class QueuedDispatchInfo; class TransactionThreadPool { friend class nsAutoPtr; friend class FinishTransactionRunnable; public: // returns a non-owning ref! static TransactionThreadPool* GetOrCreate(); // returns a non-owning ref! static TransactionThreadPool* Get(); static void Shutdown(); nsresult Dispatch(IDBTransaction* aTransaction, nsIRunnable* aRunnable, bool aFinish, nsIRunnable* aFinishRunnable); bool WaitForAllDatabasesToComplete(nsTArray& aDatabases, nsIRunnable* aCallback); // Abort all transactions, unless they are already in the process of being // committed, for aDatabase. void AbortTransactionsForDatabase(IDBDatabase* aDatabase); // Returns true if there are running or pending transactions for aDatabase. bool HasTransactionsForDatabase(IDBDatabase* aDatabase); protected: class TransactionQueue MOZ_FINAL : public nsIRunnable { public: NS_DECL_ISUPPORTS NS_DECL_NSIRUNNABLE TransactionQueue(IDBTransaction* aTransaction); void Unblock(); void Dispatch(nsIRunnable* aRunnable); void Finish(nsIRunnable* aFinishRunnable); private: mozilla::Monitor mMonitor; IDBTransaction* mTransaction; nsAutoTArray, 10> mQueue; nsCOMPtr mFinishRunnable; bool mShouldFinish; }; friend class TransactionQueue; struct TransactionInfo { TransactionInfo(IDBTransaction* aTransaction, const nsTArray& aObjectStoreNames) { MOZ_COUNT_CTOR(TransactionInfo); blockedOn.Init(); blocking.Init(); transaction = aTransaction; queue = new TransactionQueue(aTransaction); objectStoreNames.AppendElements(aObjectStoreNames); } ~TransactionInfo() { MOZ_COUNT_DTOR(TransactionInfo); } nsRefPtr transaction; nsRefPtr queue; nsTArray objectStoreNames; nsTHashtable > blockedOn; nsTHashtable > blocking; }; struct TransactionInfoPair { TransactionInfoPair() : lastBlockingReads(nullptr) { MOZ_COUNT_CTOR(TransactionInfoPair); } ~TransactionInfoPair() { MOZ_COUNT_DTOR(TransactionInfoPair); } // Multiple reading transactions can block future writes. nsTArray lastBlockingWrites; // But only a single writing transaction can block future reads. TransactionInfo* lastBlockingReads; }; struct DatabaseTransactionInfo { DatabaseTransactionInfo() { MOZ_COUNT_CTOR(DatabaseTransactionInfo); transactions.Init(); blockingTransactions.Init(); } ~DatabaseTransactionInfo() { MOZ_COUNT_DTOR(DatabaseTransactionInfo); } typedef nsClassHashtable, TransactionInfo > TransactionHashtable; TransactionHashtable transactions; nsClassHashtable blockingTransactions; }; static PLDHashOperator CollectTransactions(IDBTransaction* aKey, TransactionInfo* aValue, void* aUserArg); static PLDHashOperator FindTransaction(IDBTransaction* aKey, TransactionInfo* aValue, void* aUserArg); static PLDHashOperator MaybeUnblockTransaction(nsPtrHashKey* aKey, void* aUserArg); struct DatabasesCompleteCallback { nsTArray mDatabases; nsCOMPtr mCallback; }; TransactionThreadPool(); ~TransactionThreadPool(); nsresult Init(); nsresult Cleanup(); void FinishTransaction(IDBTransaction* aTransaction); TransactionQueue& GetQueueForTransaction(IDBTransaction* aTransaction); bool MaybeFireCallback(DatabasesCompleteCallback& aCallback); nsCOMPtr mThreadPool; nsClassHashtable mTransactionsInProgress; nsTArray mCompleteCallbacks; }; END_INDEXEDDB_NAMESPACE #endif // mozilla_dom_indexeddb_transactionthreadpool_h__