LCOV - app.info - dom/indexedDB/TransactionThreadPool.cpp

LCOV - code coverage report
| Current view: | directory - dom/indexedDB - TransactionThreadPool.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 311 | 245 | 78.8 %
| Date: | 2012-07-07 | Functions: | 28 | 25 | 89.3 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* vim: set ts=2 et sw=2 tw=80: */
           3                 : /* ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is Indexed Database.
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  * The Mozilla Foundation.
          20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Ben Turner <bent.mozilla@gmail.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include "TransactionThreadPool.h"
          41                 :
          42                 : #include "nsIObserverService.h"
          43                 : #include "nsIThreadPool.h"
          44                 :
          45                 : #include "nsComponentManagerUtils.h"
          46                 : #include "nsThreadUtils.h"
          47                 : #include "nsServiceManagerUtils.h"
          48                 : #include "nsXPCOMCIDInternal.h"
          49                 :
          50                 : using mozilla::MonitorAutoLock;
          51                 :
          52                 : USING_INDEXEDDB_NAMESPACE
          53                 :
          54                 : namespace {
          55                 :
          56                 : const PRUint32 kThreadLimit = 20;
          57                 : const PRUint32 kIdleThreadLimit = 5;
          58                 : const PRUint32 kIdleThreadTimeoutMs = 30000;
          59                 :
          60                 : TransactionThreadPool* gInstance = nsnull;
          61                 : bool gShutdown = false;
          62                 :
          63                 : inline
          64                 : nsresult
          65            2911 : CheckOverlapAndMergeObjectStores(nsTArray<nsString>& aLockedStores,
          66                 :                                  const nsTArray<nsString>& aObjectStores,
          67                 :                                  bool aShouldMerge,
          68                 :                                  bool* aStoresOverlap)
          69                 : {
          70            2911 :   PRUint32 length = aObjectStores.Length();
          71                 :
          72            2911 :   bool overlap = false;
          73                 :
          74            6822 :   for (PRUint32 index = 0; index < length; index++) {
          75            3911 :     const nsString& storeName = aObjectStores[index];
          76            3911 :     if (aLockedStores.Contains(storeName)) {
          77            1964 :       overlap = true;
          78                 :     }
          79            1947 :     else if (aShouldMerge && !aLockedStores.AppendElement(storeName)) {
          80               0 :       NS_WARNING("Out of memory!");
          81               0 :       return NS_ERROR_OUT_OF_MEMORY;
          82                 :     }
          83                 :   }
          84                 :
          85            2911 :   *aStoresOverlap = overlap;
          86            2911 :   return NS_OK;
          87                 : }
          88                 :
          89                 : } // anonymous namespace
          90                 :
          91                 : BEGIN_INDEXEDDB_NAMESPACE
          92                 :
          93                 : class FinishTransactionRunnable : public nsIRunnable
          94             539 : {
          95                 : public:
          96                 :   NS_DECL_ISUPPORTS
          97                 :   NS_DECL_NSIRUNNABLE
          98                 :
          99                 :   inline FinishTransactionRunnable(IDBTransaction* aTransaction,
         100                 :                                    nsCOMPtr<nsIRunnable>& aFinishRunnable);
         101                 :
         102                 : private:
         103                 :   IDBTransaction* mTransaction;
         104                 :   nsCOMPtr<nsIRunnable> mFinishRunnable;
         105                 : };
         106                 :
         107                 : END_INDEXEDDB_NAMESPACE
         108                 :
         109              50 : TransactionThreadPool::TransactionThreadPool()
         110                 : {
         111              50 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         112              50 :   NS_ASSERTION(!gInstance, "More than one instance!");
         113              50 : }
         114                 :
         115             100 : TransactionThreadPool::~TransactionThreadPool()
         116                 : {
         117              50 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         118              50 :   NS_ASSERTION(gInstance == this, "Different instances!");
         119              50 :   gInstance = nsnull;
         120              50 : }
         121                 :
         122                 : // static
         123                 : TransactionThreadPool*
         124            5678 : TransactionThreadPool::GetOrCreate()
         125                 : {
         126            5678 :   if (!gInstance && !gShutdown) {
         127              50 :     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         128             100 :     nsAutoPtr<TransactionThreadPool> pool(new TransactionThreadPool());
         129                 :
         130              50 :     nsresult rv = pool->Init();
         131              50 :     NS_ENSURE_SUCCESS(rv, nsnull);
         132                 :
         133             100 :     gInstance = pool.forget();
         134                 :   }
         135            5678 :   return gInstance;
         136                 : }
         137                 :
         138                 : // static
         139                 : TransactionThreadPool*
         140               0 : TransactionThreadPool::Get()
         141                 : {
         142               0 :   return gInstance;
         143                 : }
         144                 :
         145                 : // static
         146                 : void
         147              54 : TransactionThreadPool::Shutdown()
         148                 : {
         149              54 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         150                 :
         151              54 :   gShutdown = true;
         152                 :
         153              54 :   if (gInstance) {
         154              50 :     if (NS_FAILED(gInstance->Cleanup())) {
         155               0 :       NS_WARNING("Failed to shutdown thread pool!");
         156                 :     }
         157              50 :     delete gInstance;
         158              50 :     gInstance = nsnull;
         159                 :   }
         160              54 : }
         161                 :
         162                 : nsresult
         163              50 : TransactionThreadPool::Init()
         164                 : {
         165              50 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         166                 :
         167              50 :   if (!mTransactionsInProgress.Init()) {
         168               0 :     NS_WARNING("Failed to init hash!");
         169               0 :     return NS_ERROR_FAILURE;
         170                 :   }
         171                 :
         172                 :   nsresult rv;
         173              50 :   mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
         174              50 :   NS_ENSURE_SUCCESS(rv, rv);
         175                 :
         176              50 :   rv = mThreadPool->SetThreadLimit(kThreadLimit);
         177              50 :   NS_ENSURE_SUCCESS(rv, rv);
         178                 :
         179              50 :   rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
         180              50 :   NS_ENSURE_SUCCESS(rv, rv);
         181                 :
         182              50 :   rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
         183              50 :   NS_ENSURE_SUCCESS(rv, rv);
         184                 :
         185              50 :   return NS_OK;
         186                 : }
         187                 :
         188                 : nsresult
         189              50 : TransactionThreadPool::Cleanup()
         190                 : {
         191              50 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         192                 :
         193              50 :   nsresult rv = mThreadPool->Shutdown();
         194              50 :   NS_ENSURE_SUCCESS(rv, rv);
         195                 :
         196                 :   // Make sure the pool is still accessible while any callbacks generated from
         197                 :   // the other threads are processed.
         198              50 :   rv = NS_ProcessPendingEvents(nsnull);
         199              50 :   NS_ENSURE_SUCCESS(rv, rv);
         200                 :
         201              50 :   if (!mCompleteCallbacks.IsEmpty()) {
         202                 :     // Run all callbacks manually now.
         203               0 :     for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
         204               0 :       mCompleteCallbacks[index].mCallback->Run();
         205                 :     }
         206               0 :     mCompleteCallbacks.Clear();
         207                 :
         208                 :     // And make sure they get processed.
         209               0 :     rv = NS_ProcessPendingEvents(nsnull);
         210               0 :     NS_ENSURE_SUCCESS(rv, rv);
         211                 :   }
         212                 :
         213              50 :   return NS_OK;
         214                 : }
         215                 :
         216                 : void
         217             539 : TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
         218                 : {
         219             539 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         220             539 :   NS_ASSERTION(aTransaction, "Null pointer!");
         221                 :
         222                 :   // AddRef here because removing from the hash will call Release.
         223            1078 :   nsRefPtr<IDBTransaction> transaction(aTransaction);
         224                 :
         225             539 :   nsIAtom* databaseId = aTransaction->mDatabase->Id();
         226                 :
         227                 :   DatabaseTransactionInfo* dbTransactionInfo;
         228             539 :   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
         229               0 :     NS_ERROR("We don't know anyting about this database?!");
         230                 :     return;
         231                 :   }
         232                 :
         233                 :   nsTArray<TransactionInfo>& transactionsInProgress =
         234             539 :     dbTransactionInfo->transactions;
         235                 :
         236             539 :   PRUint32 transactionCount = transactionsInProgress.Length();
         237                 :
         238                 : #ifdef DEBUG
         239             539 :   if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
         240              71 :     NS_ASSERTION(transactionCount == 1,
         241                 :                  "More transactions running than should be!");
         242                 :   }
         243                 : #endif
         244                 :
         245             539 :   if (transactionCount == 1) {
         246                 : #ifdef DEBUG
         247                 :     {
         248             404 :       TransactionInfo& info = transactionsInProgress[0];
         249             404 :       NS_ASSERTION(info.transaction == aTransaction, "Transaction mismatch!");
         250                 :     }
         251                 : #endif
         252             404 :     mTransactionsInProgress.Remove(databaseId);
         253                 :
         254                 :     // See if we need to fire any complete callbacks.
         255             404 :     for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) {
         256               0 :       MaybeFireCallback(index);
         257                 :     }
         258                 :   }
         259                 :   else {
         260                 :     // We need to rebuild the locked object store list.
         261             270 :     nsTArray<nsString> storesWriting, storesReading;
         262                 :
         263             657 :     for (PRUint32 index = 0, count = transactionCount; index < count; index++) {
         264             522 :       IDBTransaction* transaction = transactionsInProgress[index].transaction;
         265             522 :       if (transaction == aTransaction) {
         266             135 :         NS_ASSERTION(count == transactionCount, "More than one match?!");
         267                 :
         268             135 :         transactionsInProgress.RemoveElementAt(index);
         269             135 :         index--;
         270             135 :         count--;
         271                 :
         272             135 :         continue;
         273                 :       }
         274                 :
         275             387 :       const nsTArray<nsString>& objectStores = transaction->mObjectStoreNames;
         276                 :
         277                 :       bool dummy;
         278             387 :       if (transaction->mMode == IDBTransaction::READ_WRITE) {
         279               3 :         if (NS_FAILED(CheckOverlapAndMergeObjectStores(storesWriting,
         280                 :                                                        objectStores,
         281                 :                                                        true, &dummy))) {
         282               0 :           NS_WARNING("Out of memory!");
         283                 :         }
         284                 :       }
         285             384 :       else if (transaction->mMode == IDBTransaction::READ_ONLY) {
         286             384 :         if (NS_FAILED(CheckOverlapAndMergeObjectStores(storesReading,
         287                 :                                                        objectStores,
         288                 :                                                        true, &dummy))) {
         289               0 :           NS_WARNING("Out of memory!");
         290                 :         }
         291                 :       }
         292                 :       else {
         293               0 :         NS_NOTREACHED("Unknown mode!");
         294                 :       }
         295                 :     }
         296                 :
         297             135 :     NS_ASSERTION(transactionsInProgress.Length() == transactionCount - 1,
         298                 :                  "Didn't find the transaction we were looking for!");
         299                 :
         300             135 :     dbTransactionInfo->storesWriting.SwapElements(storesWriting);
         301             135 :     dbTransactionInfo->storesReading.SwapElements(storesReading);
         302                 :   }
         303                 :
         304                 :   // Try to dispatch all the queued transactions again.
         305            1078 :   nsTArray<QueuedDispatchInfo> queuedDispatch;
         306             539 :   queuedDispatch.SwapElements(mDelayedDispatchQueue);
         307                 :
         308             539 :   transactionCount = queuedDispatch.Length();
         309            1666 :   for (PRUint32 index = 0; index < transactionCount; index++) {
         310            1127 :     if (NS_FAILED(Dispatch(queuedDispatch[index]))) {
         311               0 :       NS_WARNING("Dispatch failed!");
         312                 :     }
         313                 :   }
         314                 : }
         315                 :
         316                 : nsresult
         317            6802 : TransactionThreadPool::TransactionCanRun(IDBTransaction* aTransaction,
         318                 :                                          bool* aCanRun,
         319                 :                                          TransactionQueue** aExistingQueue)
         320                 : {
         321            6802 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         322            6802 :   NS_ASSERTION(aTransaction, "Null pointer!");
         323            6802 :   NS_ASSERTION(aCanRun, "Null pointer!");
         324            6802 :   NS_ASSERTION(aExistingQueue, "Null pointer!");
         325                 :
         326            6802 :   nsIAtom* databaseId = aTransaction->mDatabase->Id();
         327            6802 :   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
         328            6802 :   const PRUint16 mode = aTransaction->mMode;
         329                 :
         330                 :   // See if we can run this transaction now.
         331                 :   DatabaseTransactionInfo* dbTransactionInfo;
         332            6802 :   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
         333                 :     // First transaction for this database, fine to run.
         334             404 :     *aCanRun = true;
         335             404 :     *aExistingQueue = nsnull;
         336             404 :     return NS_OK;
         337                 :   }
         338                 :
         339                 :   nsTArray<TransactionInfo>& transactionsInProgress =
         340            6398 :     dbTransactionInfo->transactions;
         341                 :
         342            6398 :   PRUint32 transactionCount = transactionsInProgress.Length();
         343            6398 :   NS_ASSERTION(transactionCount, "Should never be 0!");
         344                 :
         345            8562 :   for (PRUint32 index = 0; index < transactionCount; index++) {
         346                 :     // See if this transaction is in out list of current transactions.
         347            7300 :     const TransactionInfo& info = transactionsInProgress[index];
         348            7300 :     if (info.transaction == aTransaction) {
         349            5136 :       *aCanRun = true;
         350            5136 :       *aExistingQueue = info.queue;
         351            5136 :       return NS_OK;
         352                 :     }
         353                 :   }
         354                 :
         355            1262 :   NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?");
         356                 :
         357                 :   bool writeOverlap;
         358                 :   nsresult rv =
         359                 :     CheckOverlapAndMergeObjectStores(dbTransactionInfo->storesWriting,
         360                 :                                      objectStoreNames,
         361                 :                                      mode == IDBTransaction::READ_WRITE,
         362            1262 :                                      &writeOverlap);
         363            1262 :   NS_ENSURE_SUCCESS(rv, rv);
         364                 :
         365                 :   bool readOverlap;
         366                 :   rv = CheckOverlapAndMergeObjectStores(dbTransactionInfo->storesReading,
         367                 :                                         objectStoreNames,
         368                 :                                         mode == IDBTransaction::READ_ONLY,
         369            1262 :                                         &readOverlap);
         370            1262 :   NS_ENSURE_SUCCESS(rv, rv);
         371                 :
         372            1262 :   if (writeOverlap ||
         373                 :       (readOverlap && mode == IDBTransaction::READ_WRITE)) {
         374            1127 :     *aCanRun = false;
         375            1127 :     *aExistingQueue = nsnull;
         376            1127 :     return NS_OK;
         377                 :   }
         378                 :
         379             135 :   *aCanRun = true;
         380             135 :   *aExistingQueue = nsnull;
         381             135 :   return NS_OK;
         382                 : }
         383                 :
         384                 : nsresult
         385            6802 : TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
         386                 :                                 nsIRunnable* aRunnable,
         387                 :                                 bool aFinish,
         388                 :                                 nsIRunnable* aFinishRunnable)
         389                 : {
         390            6802 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         391            6802 :   NS_ASSERTION(aTransaction, "Null pointer!");
         392            6802 :   NS_ASSERTION(aRunnable, "Null pointer!");
         393                 :
         394            6802 :   if (aTransaction->mDatabase->IsInvalidated() && !aFinish) {
         395               0 :     return NS_ERROR_NOT_AVAILABLE;
         396                 :   }
         397                 :
         398                 :   bool canRun;
         399                 :   TransactionQueue* existingQueue;
         400            6802 :   nsresult rv = TransactionCanRun(aTransaction, &canRun, &existingQueue);
         401            6802 :   NS_ENSURE_SUCCESS(rv, rv);
         402                 :
         403            6802 :   if (!canRun) {
         404            1127 :     QueuedDispatchInfo* info = mDelayedDispatchQueue.AppendElement();
         405            1127 :     NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
         406                 :
         407            1127 :     info->transaction = aTransaction;
         408            1127 :     info->runnable = aRunnable;
         409            1127 :     info->finish = aFinish;
         410            1127 :     info->finishRunnable = aFinishRunnable;
         411                 :
         412            1127 :     return NS_OK;
         413                 :   }
         414                 :
         415            5675 :   if (existingQueue) {
         416            5136 :     existingQueue->Dispatch(aRunnable);
         417            5136 :     if (aFinish) {
         418             539 :       existingQueue->Finish(aFinishRunnable);
         419                 :     }
         420            5136 :     return NS_OK;
         421                 :   }
         422                 :
         423             539 :   nsIAtom* databaseId = aTransaction->mDatabase->Id();
         424                 :
         425                 : #ifdef DEBUG
         426             539 :   if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
         427              71 :     NS_ASSERTION(!mTransactionsInProgress.Get(databaseId, nsnull),
         428                 :                  "Shouldn't have anything in progress!");
         429                 :   }
         430                 : #endif
         431                 :
         432                 :   DatabaseTransactionInfo* dbTransactionInfo;
         433            1078 :   nsAutoPtr<DatabaseTransactionInfo> autoDBTransactionInfo;
         434                 :
         435             539 :   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
         436                 :     // Make a new struct for this transaction.
         437             404 :     autoDBTransactionInfo = new DatabaseTransactionInfo();
         438             404 :     dbTransactionInfo = autoDBTransactionInfo;
         439                 :   }
         440                 :
         441             539 :   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
         442                 :
         443                 :   nsTArray<nsString>& storesInUse =
         444                 :     aTransaction->mMode == IDBTransaction::READ_WRITE ?
         445                 :     dbTransactionInfo->storesWriting :
         446             539 :     dbTransactionInfo->storesReading;
         447                 :
         448             539 :   if (!storesInUse.AppendElements(objectStoreNames)) {
         449               0 :     NS_WARNING("Out of memory!");
         450               0 :     return NS_ERROR_OUT_OF_MEMORY;
         451                 :   }
         452                 :
         453                 :   nsTArray<TransactionInfo>& transactionInfoArray =
         454             539 :     dbTransactionInfo->transactions;
         455                 :
         456             539 :   TransactionInfo* transactionInfo = transactionInfoArray.AppendElement();
         457             539 :   NS_ENSURE_TRUE(transactionInfo, NS_ERROR_OUT_OF_MEMORY);
         458                 :
         459             539 :   transactionInfo->transaction = aTransaction;
         460             539 :   transactionInfo->queue = new TransactionQueue(aTransaction, aRunnable);
         461             539 :   if (aFinish) {
         462               0 :     transactionInfo->queue->Finish(aFinishRunnable);
         463                 :   }
         464                 :
         465             539 :   if (!transactionInfo->objectStoreNames.AppendElements(objectStoreNames)) {
         466               0 :     NS_WARNING("Out of memory!");
         467               0 :     return NS_ERROR_OUT_OF_MEMORY;
         468                 :   }
         469                 :
         470             539 :   if (autoDBTransactionInfo) {
         471             404 :     if (!mTransactionsInProgress.Put(databaseId, autoDBTransactionInfo)) {
         472               0 :       NS_WARNING("Failed to put!");
         473               0 :       return NS_ERROR_OUT_OF_MEMORY;
         474                 :     }
         475             404 :     autoDBTransactionInfo.forget();
         476                 :   }
         477                 :
         478             539 :   return mThreadPool->Dispatch(transactionInfo->queue, NS_DISPATCH_NORMAL);
         479                 : }
         480                 :
         481                 : bool
         482               3 : TransactionThreadPool::WaitForAllDatabasesToComplete(
         483                 :                                    nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
         484                 :                                    nsIRunnable* aCallback)
         485                 : {
         486               3 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         487               3 :   NS_ASSERTION(!aDatabases.IsEmpty(), "No databases to wait on!");
         488               3 :   NS_ASSERTION(aCallback, "Null pointer!");
         489                 :
         490               3 :   DatabasesCompleteCallback* callback = mCompleteCallbacks.AppendElement();
         491               3 :   if (!callback) {
         492               0 :     NS_WARNING("Out of memory!");
         493               0 :     return false;
         494                 :   }
         495                 :
         496               3 :   callback->mCallback = aCallback;
         497               3 :   if (!callback->mDatabases.SwapElements(aDatabases)) {
         498               0 :     NS_ERROR("This should never fail!");
         499                 :   }
         500                 :
         501               3 :   MaybeFireCallback(mCompleteCallbacks.Length() - 1);
         502               3 :   return true;
         503                 : }
         504                 :
         505                 : void
         506               0 : TransactionThreadPool::AbortTransactionsForDatabase(IDBDatabase* aDatabase)
         507                 : {
         508               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         509               0 :   NS_ASSERTION(aDatabase, "Null pointer!");
         510                 :
         511                 :   // Get list of transactions for this database id
         512                 :   DatabaseTransactionInfo* dbTransactionInfo;
         513               0 :   if (!mTransactionsInProgress.Get(aDatabase->Id(), &dbTransactionInfo)) {
         514                 :     // If there are no running transactions, there can't be any pending ones
         515               0 :     return;
         516                 :   }
         517                 :
         518               0 :   nsAutoTArray<nsRefPtr<IDBTransaction>, 50> transactions;
         519                 :
         520                 :   // Collect any running transactions
         521                 :   nsTArray<TransactionInfo>& transactionsInProgress =
         522               0 :     dbTransactionInfo->transactions;
         523                 :
         524               0 :   PRUint32 transactionCount = transactionsInProgress.Length();
         525               0 :   NS_ASSERTION(transactionCount, "Should never be 0!");
         526                 :
         527               0 :   for (PRUint32 index = 0; index < transactionCount; index++) {
         528                 :     // See if any transaction belongs to this IDBDatabase instance
         529               0 :     IDBTransaction* transaction = transactionsInProgress[index].transaction;
         530               0 :     if (transaction->Database() == aDatabase) {
         531               0 :       transactions.AppendElement(transaction);
         532                 :     }
         533                 :   }
         534                 :
         535                 :   // Collect any pending transactions.
         536               0 :   for (PRUint32 index = 0; index < mDelayedDispatchQueue.Length(); index++) {
         537                 :     // See if any transaction belongs to this IDBDatabase instance
         538               0 :     IDBTransaction* transaction = mDelayedDispatchQueue[index].transaction;
         539               0 :     if (transaction->Database() == aDatabase) {
         540               0 :       transactions.AppendElement(transaction);
         541                 :     }
         542                 :   }
         543                 :
         544                 :   // Abort transactions. Do this after collecting the transactions in case
         545                 :   // calling Abort() modifies the data structures we're iterating above.
         546               0 :   for (PRUint32 index = 0; index < transactions.Length(); index++) {
         547                 :     // This can fail, for example if the transaction is in the process of
         548                 :     // being comitted. That is expected and fine, so we ignore any returned
         549                 :     // errors.
         550               0 :     transactions[index]->Abort();
         551                 :   }
         552                 : }
         553                 :
         554                 : bool
         555               0 : TransactionThreadPool::HasTransactionsForDatabase(IDBDatabase* aDatabase)
         556                 : {
         557               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         558               0 :   NS_ASSERTION(aDatabase, "Null pointer!");
         559                 :
         560                 :   // Get list of transactions for this database id
         561                 :   DatabaseTransactionInfo* dbTransactionInfo;
         562               0 :   if (!mTransactionsInProgress.Get(aDatabase->Id(), &dbTransactionInfo)) {
         563               0 :     return false;
         564                 :   }
         565                 :
         566                 :   nsTArray<TransactionInfo>& transactionsInProgress =
         567               0 :     dbTransactionInfo->transactions;
         568                 :
         569               0 :   PRUint32 transactionCount = transactionsInProgress.Length();
         570               0 :   NS_ASSERTION(transactionCount, "Should never be 0!");
         571                 :
         572               0 :   for (PRUint32 index = 0; index < transactionCount; index++) {
         573                 :     // See if any transaction belongs to this IDBDatabase instance
         574               0 :     if (transactionsInProgress[index].transaction->Database() == aDatabase) {
         575               0 :       return true;
         576                 :     }
         577                 :   }
         578                 :
         579               0 :   return false;
         580                 : }
         581                 :
         582                 : void
         583               3 : TransactionThreadPool::MaybeFireCallback(PRUint32 aCallbackIndex)
         584                 : {
         585               3 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         586                 :
         587               3 :   DatabasesCompleteCallback& callback = mCompleteCallbacks[aCallbackIndex];
         588                 :
         589               3 :   bool freeToRun = true;
         590               6 :   for (PRUint32 index = 0; index < callback.mDatabases.Length(); index++) {
         591               3 :     if (mTransactionsInProgress.Get(callback.mDatabases[index]->Id(), nsnull)) {
         592               0 :       freeToRun = false;
         593               0 :       break;
         594                 :     }
         595                 :   }
         596                 :
         597               3 :   if (freeToRun) {
         598               3 :     callback.mCallback->Run();
         599               3 :     mCompleteCallbacks.RemoveElementAt(aCallbackIndex);
         600                 :   }
         601               3 : }
         602                 :
         603             539 : TransactionThreadPool::
         604                 : TransactionQueue::TransactionQueue(IDBTransaction* aTransaction,
         605                 :                                    nsIRunnable* aRunnable)
         606                 : : mMonitor("TransactionQueue::mMonitor"),
         607                 :   mTransaction(aTransaction),
         608             539 :   mShouldFinish(false)
         609                 : {
         610             539 :   NS_ASSERTION(aTransaction, "Null pointer!");
         611             539 :   NS_ASSERTION(aRunnable, "Null pointer!");
         612             539 :   mQueue.AppendElement(aRunnable);
         613             539 : }
         614                 :
         615                 : void
         616            5136 : TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable)
         617                 : {
         618           10272 :   MonitorAutoLock lock(mMonitor);
         619                 :
         620            5136 :   NS_ASSERTION(!mShouldFinish, "Dispatch called after Finish!");
         621                 :
         622            5136 :   mQueue.AppendElement(aRunnable);
         623                 :
         624            5136 :   mMonitor.Notify();
         625            5136 : }
         626                 :
         627                 : void
         628             539 : TransactionThreadPool::TransactionQueue::Finish(nsIRunnable* aFinishRunnable)
         629                 : {
         630            1078 :   MonitorAutoLock lock(mMonitor);
         631                 :
         632             539 :   NS_ASSERTION(!mShouldFinish, "Finish called more than once!");
         633                 :
         634             539 :   mShouldFinish = true;
         635             539 :   mFinishRunnable = aFinishRunnable;
         636                 :
         637             539 :   mMonitor.Notify();
         638             539 : }
         639                 :
         640            4312 : NS_IMPL_THREADSAFE_ISUPPORTS1(TransactionThreadPool::TransactionQueue,
         641                 :                               nsIRunnable)
         642                 :
         643                 : NS_IMETHODIMP
         644             539 : TransactionThreadPool::TransactionQueue::Run()
         645                 : {
         646            1078 :   nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
         647            1078 :   nsCOMPtr<nsIRunnable> finishRunnable;
         648             539 :   bool shouldFinish = false;
         649                 :
         650            5402 :   while(!shouldFinish) {
         651            4324 :     NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
         652                 :
         653                 :     {
         654            8645 :       MonitorAutoLock lock(mMonitor);
         655           12099 :       while (!mShouldFinish && mQueue.IsEmpty()) {
         656            3451 :         if (NS_FAILED(mMonitor.Wait())) {
         657               0 :           NS_ERROR("Failed to wait!");
         658                 :         }
         659                 :       }
         660                 :
         661            4324 :       mQueue.SwapElements(queue);
         662            4321 :       if (mShouldFinish) {
         663             539 :         mFinishRunnable.swap(finishRunnable);
         664             539 :         shouldFinish = true;
         665                 :       }
         666                 :     }
         667                 :
         668            4324 :     PRUint32 count = queue.Length();
         669            9999 :     for (PRUint32 index = 0; index < count; index++) {
         670            5675 :       nsCOMPtr<nsIRunnable>& runnable = queue[index];
         671            5675 :       runnable->Run();
         672            5675 :       runnable = nsnull;
         673                 :     }
         674                 :
         675            4324 :     if (count) {
         676            4267 :       queue.Clear();
         677                 :     }
         678                 :   }
         679                 :
         680                 :   nsCOMPtr<nsIRunnable> finishTransactionRunnable =
         681            1078 :     new FinishTransactionRunnable(mTransaction, finishRunnable);
         682             539 :   if (NS_FAILED(NS_DispatchToMainThread(finishTransactionRunnable,
         683                 :                                         NS_DISPATCH_NORMAL))) {
         684               0 :     NS_WARNING("Failed to dispatch finishTransactionRunnable!");
         685                 :   }
         686                 :
         687             539 :   return NS_OK;
         688                 : }
         689                 :
         690             539 : FinishTransactionRunnable::FinishTransactionRunnable(
         691                 :                                          IDBTransaction* aTransaction,
         692                 :                                          nsCOMPtr<nsIRunnable>& aFinishRunnable)
         693             539 : : mTransaction(aTransaction)
         694                 : {
         695             539 :   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
         696             539 :   NS_ASSERTION(aTransaction, "Null pointer!");
         697             539 :   mFinishRunnable.swap(aFinishRunnable);
         698             539 : }
         699                 :
         700            5929 : NS_IMPL_THREADSAFE_ISUPPORTS1(FinishTransactionRunnable, nsIRunnable)
         701                 :
         702                 : NS_IMETHODIMP
         703             539 : FinishTransactionRunnable::Run()
         704                 : {
         705             539 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
         706             539 :   if (!gInstance) {
         707               0 :     NS_ERROR("Running after shutdown!");
         708               0 :     return NS_ERROR_FAILURE;
         709                 :   }
         710                 :
         711             539 :   gInstance->FinishTransaction(mTransaction);
         712                 :
         713             539 :   if (mFinishRunnable) {
         714             539 :     mFinishRunnable->Run();
         715             539 :     mFinishRunnable = nsnull;
         716                 :   }
         717                 :
         718             539 :   return NS_OK;
         719                 : }

Generated by: LCOV version 1.7