Backout 26ac81280f33 (bug 692911) for Moth orange on all platforms & M2 orange on win opt
authorEd Morley <bmo@edmorley.co.uk>
Mon, 24 Oct 2011 23:49:59 +0100
changeset 79138 767693e248aa388febeb987291aece0ab7269c6e
parent 79137 26ac81280f33998ce7492691ecabc0e872d007a2
child 79172 03c236ba6ae0408b00c51a8899ac46989329bac6
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs692911
milestone10.0a1
backs out26ac81280f33998ce7492691ecabc0e872d007a2
Backout 26ac81280f33 (bug 692911) for Moth orange on all platforms & M2 orange on win opt
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/AsyncConnectionHelper.h
dom/indexedDB/DatabaseInfo.cpp
dom/indexedDB/DatabaseInfo.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBDatabase.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/IndexedDatabaseManager.h
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
dom/indexedDB/TransactionThreadPool.cpp
dom/indexedDB/TransactionThreadPool.h
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/event_propagation_iframe.html
dom/indexedDB/test/leaving_page_iframe.html
dom/indexedDB/test/test_autoIncrement_indexes.html
dom/indexedDB/test/test_clear.html
dom/indexedDB/test/test_create_index_with_integer_keys.html
dom/indexedDB/test/test_cursor_mutation.html
dom/indexedDB/test/test_getAll.html
dom/indexedDB/test/test_index_getAll.html
dom/indexedDB/test/test_index_getAllObjects.html
dom/indexedDB/test/test_index_object_cursors.html
dom/indexedDB/test/test_indexes.html
dom/indexedDB/test/test_indexes_bad_values.html
dom/indexedDB/test/test_object_identity.html
dom/indexedDB/test/test_odd_result_order.html
dom/indexedDB/test/test_open_objectStore.html
dom/indexedDB/test/test_overlapping_transactions.html
dom/indexedDB/test/test_readonly_transactions.html
dom/indexedDB/test/test_setVersion_exclusion.html
dom/indexedDB/test/test_success_events_after_abort.html
dom/indexedDB/test/test_transaction_abort.html
dom/indexedDB/test/test_transaction_lifetimes.html
dom/indexedDB/test/test_transaction_lifetimes_nested.html
dom/indexedDB/test/test_writer_starvation.html
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -555,18 +555,18 @@ NS_IMPL_QUERY_INTERFACE1(TransactionPool
 
 NS_IMETHODIMP
 TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable,
                                      PRUint32 aFlags)
 {
   NS_ASSERTION(aRunnable, "Null pointer!");
   NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!");
 
-  TransactionThreadPool* pool = TransactionThreadPool::Get();
-  NS_ASSERTION(pool, "This should never be null!");
+  TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
+  NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE);
 
   return pool->Dispatch(mTransaction, aRunnable, false, nsnull);
 }
 
 NS_IMETHODIMP
 TransactionPoolEventTarget::IsOnCurrentThread(bool* aResult)
 {
   *aResult = false;
--- a/dom/indexedDB/AsyncConnectionHelper.h
+++ b/dom/indexedDB/AsyncConnectionHelper.h
@@ -120,21 +120,16 @@ public:
   void SetError(nsresult aErrorCode)
   {
     NS_ASSERTION(NS_FAILED(aErrorCode), "Not a failure code!");
     mResultCode = aErrorCode;
   }
 
   static IDBTransaction* GetCurrentTransaction();
 
-  bool HasTransaction()
-  {
-    return mTransaction;
-  }
-
   nsISupports* GetSource()
   {
     return mRequest ? mRequest->Source() : nsnull;
   }
 
   nsresult GetResultCode()
   {
     return mResultCode;
--- a/dom/indexedDB/DatabaseInfo.cpp
+++ b/dom/indexedDB/DatabaseInfo.cpp
@@ -80,18 +80,17 @@ EnumerateObjectStoreNames(const nsAStrin
 }
 
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 DatabaseInfo::DatabaseInfo()
 : id(0),
   nextObjectStoreId(1),
-  nextIndexId(1),
-  runningVersionChange(false)
+  nextIndexId(1)
 {
   MOZ_COUNT_CTOR(DatabaseInfo);
 }
 
 DatabaseInfo::~DatabaseInfo()
 {
   MOZ_COUNT_DTOR(DatabaseInfo);
 }
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -49,18 +49,17 @@ BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   DatabaseInfo();
   ~DatabaseInfo();
 #else
   DatabaseInfo()
-  : id(0), nextObjectStoreId(1), nextIndexId(1), runningVersionChange(false)
-  { }
+  : id(0), nextObjectStoreId(1), nextIndexId(1) { }
 #endif
 
   static bool Get(PRUint32 aId,
                   DatabaseInfo** aInfo);
 
   static bool Put(DatabaseInfo* aInfo);
 
   static void Remove(PRUint32 aId);
@@ -69,17 +68,16 @@ struct DatabaseInfo
   bool ContainsStoreName(const nsAString& aName);
 
   nsString name;
   PRUint64 version;
   PRUint32 id;
   nsString filePath;
   PRInt64 nextObjectStoreId;
   PRInt64 nextIndexId;
-  bool runningVersionChange;
 
   nsAutoRefCnt referenceCount;
 };
 
 struct IndexInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   IndexInfo();
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -424,44 +424,16 @@ IDBDatabase::CloseInternal()
 bool
 IDBDatabase::IsClosed()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   return mClosed;
 }
 
 void
-IDBDatabase::EnterSetVersionTransaction()
-{
-  DatabaseInfo* dbInfo;
-  if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
-    NS_ERROR("This should never fail!");
-  }
-
-  NS_ASSERTION(!dbInfo->runningVersionChange, "How did that happen?");
-  dbInfo->runningVersionChange = true;
-}
-
-void
-IDBDatabase::ExitSetVersionTransaction()
-{
-  DatabaseInfo* dbInfo;
-  if (!DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
-    NS_ERROR("This should never fail!");
-  }
-
-  NS_ASSERTION(dbInfo->runningVersionChange, "How did that happen?");
-  dbInfo->runningVersionChange = false;
-
-  IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
-  NS_ASSERTION(manager, "We should always have a manager here");
-  manager->UnblockSetVersionRunnable(this);
-}
-
-void
 IDBDatabase::OnUnlink()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mOwner, "Should have been cleared already!");
 
   // We've been unlinked, at the very least we should be able to prevent further
   // transactions from starting and unblock any other SetVersion callers.
   Close();
@@ -733,20 +705,16 @@ IDBDatabase::Transaction(nsIVariant* aSt
   nsresult rv = aStoreNames->GetDataType(&type);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   DatabaseInfo* info;
   if (!DatabaseInfo::Get(mDatabaseId, &info)) {
     NS_ERROR("This should never fail!");
   }
 
-  if (info->runningVersionChange) {
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
-  }
-
   nsTArray<nsString> storesToOpen;
 
   switch (type) {
     case nsIDataType::VTYPE_VOID:
     case nsIDataType::VTYPE_EMPTY:
     case nsIDataType::VTYPE_EMPTY_ARRAY: {
       // Empty, request all object stores
       if (!info->GetObjectStoreNames(storesToOpen)) {
--- a/dom/indexedDB/IDBDatabase.h
+++ b/dom/indexedDB/IDBDatabase.h
@@ -130,19 +130,16 @@ public:
   // transactions for this database will be allowed to run.
   bool IsInvalidated();
 
   void CloseInternal();
 
   // Whether or not the database has had Close called on it.
   bool IsClosed();
 
-  void EnterSetVersionTransaction();
-  void ExitSetVersionTransaction();
-
 private:
   IDBDatabase();
   ~IDBDatabase();
 
   void OnUnlink();
 
   PRUint32 mDatabaseId;
   nsString mName;
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -688,64 +688,47 @@ IndexedDatabaseManager::OnDatabaseClosed
       // for other databases the mDatabases array may be empty.
       if (!runnable->mDatabases.IsEmpty() &&
           !runnable->mDatabases.RemoveElement(aDatabase)) {
         NS_ERROR("Didn't have this database in our list!");
       }
 
       // Now run the helper if there are no more live databases.
       if (runnable->mHelper && runnable->mDatabases.IsEmpty()) {
-        // At this point, all databases are closed, so no new transactions can
-        // be started.  There may, however, still be outstanding transactions
-        // that have not completed.  We need to wait for those before we
-        // dispatch the helper.
+        // Don't hold the callback alive longer than necessary.
+        nsRefPtr<AsyncConnectionHelper> helper;
+        helper.swap(runnable->mHelper);
 
-        TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
+        if (NS_FAILED(helper->DispatchToTransactionPool())) {
+          NS_WARNING("Failed to dispatch to thread pool!");
+        }
 
-        nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
-          new WaitForTransactionsToFinishRunnable(runnable);
+        // Now wait for the transaction to complete. Completing the transaction
+        // will be our cue to remove the SetVersionRunnable from our list and
+        // therefore allow other SetVersion requests to begin.
+        TransactionThreadPool* pool = TransactionThreadPool::Get();
+        NS_ASSERTION(pool, "This should never be null!");
 
         // All other databases should be closed, so we only need to wait on this
         // one.
         nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
         if (!array.AppendElement(aDatabase)) {
           NS_ERROR("This should never fail!");
         }
 
-        // Use the WaitForTransactionsToFinishRunnable as the callback.
-        if (!pool->WaitForAllDatabasesToComplete(array, waitRunnable)) {
+        // Use the SetVersionRunnable as the callback.
+        if (!pool->WaitForAllDatabasesToComplete(array, runnable)) {
           NS_WARNING("Failed to wait for transaction to complete!");
         }
       }
       break;
     }
   }
 }
 
-void
-IndexedDatabaseManager::UnblockSetVersionRunnable(IDBDatabase* aDatabase)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aDatabase, "Null pointer!");
-
-  // Check through the list of SetVersionRunnables to find the one we're seeking.
-  for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
-    nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
-
-    if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
-      NS_ASSERTION(!runnable->mHelper,
-                 "Why are we unblocking a runnable if the helper didn't run?");
-      NS_DispatchToCurrentThread(runnable);
-      return;
-    }
-  }
-
-  NS_NOTREACHED("How did we get here!");
-}
-
 // static
 bool
 IndexedDatabaseManager::SetCurrentDatabase(IDBDatabase* aDatabase)
 {
   NS_ASSERTION(gCurrentDatabaseIndex != BAD_TLS_INDEX,
                "This should have been set already!");
 
 #ifdef DEBUG
@@ -1295,44 +1278,8 @@ IndexedDatabaseManager::SetVersionRunnab
   NS_ASSERTION(mgr, "This should never be null!");
 
   // Let the IndexedDatabaseManager know that the SetVersion transaction has
   // completed.
   mgr->OnSetVersionRunnableComplete(this);
 
   return NS_OK;
 }
-
-NS_IMPL_THREADSAFE_ISUPPORTS1(IndexedDatabaseManager::WaitForTransactionsToFinishRunnable,
-                              nsIRunnable)
-
-NS_IMETHODIMP
-IndexedDatabaseManager::WaitForTransactionsToFinishRunnable::Run()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  // Don't hold the callback alive longer than necessary.
-  nsRefPtr<AsyncConnectionHelper> helper;
-  helper.swap(mRunnable->mHelper);
-
-  nsRefPtr<SetVersionRunnable> runnable;
-  runnable.swap(mRunnable);
-
-  // If the helper has a transaction, dispatch it to the transaction
-  // threadpool.
-  if (helper->HasTransaction()) {
-    if (NS_FAILED(helper->DispatchToTransactionPool())) {
-      NS_WARNING("Failed to dispatch to thread pool!");
-    }
-  }
-  // Otherwise, dispatch it to the IO thread.
-  else {
-    IndexedDatabaseManager* manager = IndexedDatabaseManager::Get();
-    NS_ASSERTION(manager, "We should definitely have a manager here");
-
-    helper->Dispatch(manager->IOThread());
-  }
-
-  // The helper is responsible for calling
-  // IndexedDatabaseManager::UnblockSetVersionRunnable.
-
-  return NS_OK;
-}
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -199,18 +199,16 @@ private:
     nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
     PRUint64 mUsage;
     PRInt32 mCanceled;
   };
 
   // Called when AsyncUsageRunnable has finished its Run() method.
   inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
 
-  void UnblockSetVersionRunnable(IDBDatabase* aDatabase);
-
   // Responsible for waiting until all databases have been closed before running
   // the version change transaction. Created when
   // IndexedDatabaseManager::SetDatabaseVersion is called. Runs only once on the
   // main thread when the version change transaction has completed.
   class SetVersionRunnable : public nsIRunnable
   {
   public:
     NS_DECL_ISUPPORTS
@@ -224,36 +222,16 @@ private:
     nsTArray<nsRefPtr<IDBDatabase> > mDatabases;
     nsRefPtr<AsyncConnectionHelper> mHelper;
     nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
   };
 
   // Called when SetVersionRunnable has finished its Run() method.
   inline void OnSetVersionRunnableComplete(SetVersionRunnable* aRunnable);
 
-
-  // A callback runnable used by the TransactionPool when it's safe to proceed
-  // with a SetVersion/DeleteDatabase/etc.
-  class WaitForTransactionsToFinishRunnable : public nsIRunnable
-  {
-  public:
-    WaitForTransactionsToFinishRunnable(SetVersionRunnable* aRunnable)
-    : mRunnable(aRunnable)
-    {
-      NS_ASSERTION(mRunnable, "Why don't we have a runnable?");
-      NS_ASSERTION(mRunnable->mDatabases.IsEmpty(), "We're here too early!");
-    }
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIRUNNABLE
-
-  private:
-    nsRefPtr<SetVersionRunnable> mRunnable;
-  };
-
   // Maintains a list of live databases per origin.
   nsClassHashtable<nsCStringHashKey, nsTArray<IDBDatabase*> > mLiveDatabases;
 
   // Maintains a list of origins that are currently being cleared.
   nsAutoTArray<nsRefPtr<OriginClearRunnable>, 1> mOriginClearRunnables;
 
   // Maintains a list of origins that we're currently enumerating to gather
   // usage statistics.
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -490,23 +490,20 @@ public:
     mRequestedVersion(aRequestedVersion),
     mCurrentVersion(aCurrentVersion)
   {
     mTransaction->SetTransactionListener(this);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
+  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   nsresult GetSuccessResult(JSContext* aCx,
                             jsval* aVal);
 
-protected:
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult Init();
-
   // SetVersionHelper never fires an error event at the request.  It hands that
   // responsibility back to the OpenDatabaseHelper
   void OnError() { }
 
   // Need an upgradeneeded event here.
   already_AddRefed<nsDOMEvent> CreateSuccessEvent();
 
   nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
@@ -682,17 +679,16 @@ OpenDatabaseHelper::StartSetVersion()
 
   rv = mgr->SetDatabaseVersion(mDatabase, mOpenDBRequest, mCurrentVersion,
                                mRequestedVersion, helper);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // The SetVersionHelper is responsible for dispatching us back to the
   // main thread again and changing the state to eSetVersionCompleted.
   mState = eSetVersionPending;
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 OpenDatabaseHelper::Run()
 {
   NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
 
@@ -710,22 +706,16 @@ OpenDatabaseHelper::Run()
     }
 
     // We've done whatever work we need to do on the DB thread, and any
     // SetVersion stuff is done by now.
     NS_ASSERTION(mState == eFiringEvents ||
                  mState == eSetVersionCompleted, "Why are we here?");
 
     if (mState == eSetVersionCompleted) {
-      // Allow transaction creation/other version change transactions to proceed
-      // before we fire events.  Other version changes will be postd to the end
-      // of the event loop, and will be behind whatever the page does in
-      // its error/success event handlers.
-      mDatabase->ExitSetVersionTransaction();
-
       mState = eFiringEvents;
     } else {
       // Notify the request that we're done, but only if we didn't just finish
       // a SetVersionHelper.  In the SetVersionHelper case, that helper tells
       // the request that it is done, and we avoid calling NotifyHandlerCompleted
       // twice.
 
       nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
@@ -871,25 +861,16 @@ OpenDatabaseHelper::NotifySetVersionFini
 
   mState = eSetVersionCompleted;
   
   // Dispatch ourself back to the main thread
   return NS_DispatchToCurrentThread(this);
 }
 
 void
-OpenDatabaseHelper::BlockDatabase()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(mDatabase, "This is going bad fast.");
-
-  mDatabase->EnterSetVersionTransaction();
-}
-
-void
 OpenDatabaseHelper::DispatchSuccessEvent()
 {
   NS_ASSERTION(mDatabase, "Doesn't seem very successful to me.");
 
   nsRefPtr<nsDOMEvent> event =
     CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
   if (!event) {
     NS_ERROR("Failed to create event!");
@@ -931,25 +912,16 @@ OpenDatabaseHelper::ReleaseMainThreadObj
   mDatabase = nsnull;
 
   HelperBase::ReleaseMainThreadObjects();
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
 
 nsresult
-SetVersionHelper::Init()
-{
-  // Block transaction creation until we are done.
-  mOpenHelper->BlockDatabase();
-
-  return NS_OK;
-}
-
-nsresult
 SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passing a null connection!");
 
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE database "
     "SET version = :version"
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -77,17 +77,16 @@ public:
   }
 
   nsresult GetResultCode()
   {
     return mResultCode;
   }
 
   nsresult NotifySetVersionFinished();
-  void BlockDatabase();
 
 protected:
   // Methods only called on the main thread
   nsresult EnsureSuccessResult();
   nsresult StartSetVersion();
   nsresult GetSuccessResult(JSContext* aCx,
                           jsval* aVal);
   void DispatchSuccessEvent();
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -233,16 +233,17 @@ TransactionThreadPool::FinishTransaction
 
   nsTArray<TransactionInfo>& transactionsInProgress =
     dbTransactionInfo->transactions;
 
   PRUint32 transactionCount = transactionsInProgress.Length();
 
 #ifdef DEBUG
   if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
+    NS_ASSERTION(dbTransactionInfo->locked, "Should be locked!");
     NS_ASSERTION(transactionCount == 1,
                  "More transactions running than should be!");
   }
 #endif
 
   if (transactionCount == 1) {
 #ifdef DEBUG
     {
@@ -338,27 +339,35 @@ TransactionThreadPool::TransactionCanRun
   }
 
   nsTArray<TransactionInfo>& transactionsInProgress =
     dbTransactionInfo->transactions;
 
   PRUint32 transactionCount = transactionsInProgress.Length();
   NS_ASSERTION(transactionCount, "Should never be 0!");
 
+  if (mode == IDBTransaction::VERSION_CHANGE) {
+    dbTransactionInfo->lockPending = true;
+  }
+
   for (PRUint32 index = 0; index < transactionCount; index++) {
     // See if this transaction is in out list of current transactions.
     const TransactionInfo& info = transactionsInProgress[index];
     if (info.transaction == aTransaction) {
       *aCanRun = true;
       *aExistingQueue = info.queue;
       return NS_OK;
     }
   }
 
-  NS_ASSERTION(mode != IDBTransaction::VERSION_CHANGE, "How did we get here?");
+  if (dbTransactionInfo->locked || dbTransactionInfo->lockPending) {
+    *aCanRun = false;
+    *aExistingQueue = nsnull;
+    return NS_OK;
+  }
 
   bool writeOverlap;
   nsresult rv =
     CheckOverlapAndMergeObjectStores(dbTransactionInfo->storesWriting,
                                      objectStoreNames,
                                      mode == nsIIDBTransaction::READ_WRITE,
                                      &writeOverlap);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -434,16 +443,21 @@ TransactionThreadPool::Dispatch(IDBTrans
   nsAutoPtr<DatabaseTransactionInfo> autoDBTransactionInfo;
 
   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
     // Make a new struct for this transaction.
     autoDBTransactionInfo = new DatabaseTransactionInfo();
     dbTransactionInfo = autoDBTransactionInfo;
   }
 
+  if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
+    NS_ASSERTION(!dbTransactionInfo->locked, "Already locked?!");
+    dbTransactionInfo->locked = true;
+  }
+
   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
 
   nsTArray<nsString>& storesInUse =
     aTransaction->mMode == nsIIDBTransaction::READ_WRITE ?
     dbTransactionInfo->storesWriting :
     dbTransactionInfo->storesReading;
 
   if (!storesInUse.AppendElements(objectStoreNames)) {
--- a/dom/indexedDB/TransactionThreadPool.h
+++ b/dom/indexedDB/TransactionThreadPool.h
@@ -118,16 +118,22 @@ protected:
   {
     nsRefPtr<IDBTransaction> transaction;
     nsRefPtr<TransactionQueue> queue;
     nsTArray<nsString> objectStoreNames;
   };
 
   struct DatabaseTransactionInfo
   {
+    DatabaseTransactionInfo()
+    : locked(false), lockPending(false)
+    { }
+
+    bool locked;
+    bool lockPending;
     nsTArray<TransactionInfo> transactions;
     nsTArray<nsString> storesReading;
     nsTArray<nsString> storesWriting;
   };
 
   struct QueuedDispatchInfo
   {
     QueuedDispatchInfo()
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -93,17 +93,16 @@ TEST_FILES = \
   test_success_events_after_abort.html \
   test_third_party.html \
   test_transaction_abort.html \
   test_transaction_lifetimes.html \
   test_transaction_lifetimes_nested.html \
   test_setVersion.html \
   test_setVersion_abort.html \
   test_setVersion_events.html \
-  test_setVersion_exclusion.html \
   test_writer_starvation.html \
   third_party_iframe1.html \
   third_party_iframe2.html \
   $(NULL)
 
 ifeq (browser,$(MOZ_BUILD_APP))
 BROWSER_TEST_FILES = \
   browser_forgetThisSite.js \
--- a/dom/indexedDB/test/event_propagation_iframe.html
+++ b/dom/indexedDB/test/event_propagation_iframe.html
@@ -99,17 +99,17 @@
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorEventCounter;
       db.addEventListener("error", errorEventCounter, true);
 
-      event.target.onsuccess = grabEventAndContinueHandler;
+      event.target.transaction.oncomplete = grabEventAndContinueHandler;
 
       db.createObjectStore("foo", { autoIncrement: true });
       yield;
 
       let transaction = db.transaction("foo", IDBTransaction.READ_WRITE);
       transaction.addEventListener("error", errorEventCounter, false);
       transaction.addEventListener("error", errorEventCounter, true);
 
--- a/dom/indexedDB/test/leaving_page_iframe.html
+++ b/dom/indexedDB/test/leaving_page_iframe.html
@@ -7,17 +7,17 @@ function startDBWork() {
   mozIndexedDB.open(parent.location, 1).onupgradeneeded = function(e) {
     db = e.target.result;
     var trans = e.target.transaction;
     if (db.objectStoreNames.contains("mystore")) {
       db.deleteObjectStore("mystore");
     }
     var store = db.createObjectStore("mystore");
     store.add({ hello: "world" }, 42);
-    e.target.onsuccess = madeMod;
+    trans.oncomplete = madeMod;
   };
 }
 
 function madeMod() {
   var trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
   var store = trans.
               objectStore("mystore");
   trans.oncomplete = function() {
--- a/dom/indexedDB/test/test_autoIncrement_indexes.html
+++ b/dom/indexedDB/test/test_autoIncrement_indexes.html
@@ -28,19 +28,16 @@
 
       let data = { first: "foo", second: "foo", third: "foo" };
 
       objectStore.add(data).onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       let key = event.target.result;
       ok(key, "Added entry");
-      request.onsuccess = grabEventAndContinueHandler;
-
-      event = yield;
 
       let objectStore = db.transaction("foo").objectStore("foo");
       let first = objectStore.index("first");
       let second = objectStore.index("second");
       let third = objectStore.index("third");
 
       first.get("foo").onsuccess = grabEventAndContinueHandler;
       event = yield;
--- a/dom/indexedDB/test/test_clear.html
+++ b/dom/indexedDB/test/test_clear.html
@@ -20,17 +20,17 @@
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = request.result;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       let firstKey;
       for (let i = 0; i < entryCount; i++) {
         request = objectStore.add({});
         request.onerror = errorHandler;
         if (!i) {
--- a/dom/indexedDB/test/test_create_index_with_integer_keys.html
+++ b/dom/indexedDB/test/test_create_index_with_integer_keys.html
@@ -18,33 +18,33 @@
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       // Make object store, add data.
       let objectStore = db.createObjectStore("foo", { keyPath: "id" });
       objectStore.add(data);
       yield;
       db.close();
 
       let request = mozIndexedDB.open(window.location.pathname, 2);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db2 = event.target.result;
       db2.onerror = errorHandler;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       // Create index.
       event.target.transaction.objectStore("foo").createIndex("foo", "num");
       yield;
 
       // Make sure our object made it into the index.
       let seenCount = 0;
 
--- a/dom/indexedDB/test/test_cursor_mutation.html
+++ b/dom/indexedDB/test/test_cursor_mutation.html
@@ -30,17 +30,17 @@
       const objectStoreDataNameSort = [ 1, 4, 5, 2, 3 ];
 
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
       objectStore.createIndex("name", "name", { unique: true });
 
       for (let i = 0; i < objectStoreData.length - 1; i++) {
         objectStore.add(objectStoreData[i]);
       }
       yield;
--- a/dom/indexedDB/test/test_getAll.html
+++ b/dom/indexedDB/test/test_getAll.html
@@ -21,17 +21,16 @@
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
-      request.onsuccess = grabEventAndContinueHandler;
       request = objectStore.getAll();
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       is(event.target.result instanceof Array, true, "Got an array object");
       is(event.target.result.length, 0, "No elements");
 
@@ -42,17 +41,16 @@
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
           if (++addedCount == values.length) {
             SimpleTest.executeSoon(function() { testGenerator.next(); });
           }
         }
       }
       yield;
-      yield;
 
       request = db.transaction("foo").objectStore("foo").getAll();
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       is(event.target.result instanceof Array, true, "Got an array object");
       is(event.target.result.length, values.length, "Same length");
--- a/dom/indexedDB/test/test_index_getAll.html
+++ b/dom/indexedDB/test/test_index_getAll.html
@@ -55,17 +55,16 @@
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let objectStore = db.createObjectStore(objectStoreName);
 
       // First, add all our data to the object store.
       let addedData = 0;
@@ -74,26 +73,27 @@
                                   objectStoreData[i].key);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
           if (++addedData == objectStoreData.length) {
             testGenerator.send(event);
           }
         }
       }
-      yield;
+      event = yield;
       ok(true, "1");
 
       // Now create the indexes.
       for (let i in indexData) {
         objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
                                 indexData[i].options);
       }
 
       is(objectStore.indexNames.length, indexData.length, "Good index count");
+      continueToNextStep();
       yield;
 
       ok(true, "2");
       objectStore = db.transaction(objectStoreName)
                       .objectStore(objectStoreName);
 
       request = objectStore.index("height").getAllKeys(65);
       request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_index_getAllObjects.html
+++ b/dom/indexedDB/test/test_index_getAllObjects.html
@@ -55,17 +55,16 @@
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let objectStore = db.createObjectStore(objectStoreName, {});
 
       // First, add all our data to the object store.
       let addedData = 0;
@@ -83,16 +82,17 @@
 
       // Now create the indexes.
       for (let i in indexData) {
         objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
                                 indexData[i].options);
       }
 
       is(objectStore.indexNames.length, indexData.length, "Good index count");
+      continueToNextStep();
       yield;
 
       objectStore = db.transaction(objectStoreName)
                       .objectStore(objectStoreName);
 
       request = objectStore.index("height").getAll(65);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/test_index_object_cursors.html
+++ b/dom/indexedDB/test/test_index_object_cursors.html
@@ -32,17 +32,17 @@
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       for (let objectStoreIndex in objectStoreData) {
         const objectStoreInfo = objectStoreData[objectStoreIndex];
         let objectStore = db.createObjectStore(objectStoreInfo.name,
                                                objectStoreInfo.options);
         for (let indexIndex in indexData) {
           const indexInfo = indexData[indexIndex];
           let index = objectStore.createIndex(indexInfo.name,
--- a/dom/indexedDB/test/test_indexes.html
+++ b/dom/indexedDB/test/test_indexes.html
@@ -66,17 +66,16 @@
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let objectStore = db.createObjectStore(objectStoreName, { keyPath: "" });
 
       // First, add all our data to the object store.
       let addedData = 0;
@@ -93,16 +92,17 @@
       event = yield;
 
       // Now create the indexes.
       for (let i in indexData) {
         objectStore.createIndex(indexData[i].name, indexData[i].keyPath,
                                 indexData[i].options);
       }
       is(objectStore.indexNames.length, indexData.length, "Good index count");
+      continueToNextStep();
       yield;
 
       objectStore = db.transaction(objectStoreName)
                       .objectStore(objectStoreName);
 
       // Check global properties to make sure they are correct.
       is(objectStore.indexNames.length, indexData.length, "Good index count");
       for (let i in indexData) {
--- a/dom/indexedDB/test/test_indexes_bad_values.html
+++ b/dom/indexedDB/test/test_indexes_bad_values.html
@@ -46,17 +46,16 @@
         { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let objectStore = db.createObjectStore(objectStoreName, { } );
 
       let addedData = 0;
       for (let i in objectStoreData) {
@@ -83,17 +82,16 @@
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
           if (++addedData == badObjectStoreData.length) {
             SimpleTest.executeSoon(function() { testGenerator.next() });
           }
         }
       }
       yield;
-      yield;
 
       objectStore = db.transaction(objectStoreName)
                       .objectStore(objectStoreName);
 
       let keyIndex = 0;
 
       request = objectStore.index("weight").openKeyCursor();
       request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_object_identity.html
+++ b/dom/indexedDB/test/test_object_identity.html
@@ -23,17 +23,17 @@
       let objectStore1 = db.createObjectStore("foo");
       let objectStore2 = transaction.objectStore("foo");
       ok(objectStore1 === objectStore2, "Got same objectStores");
 
       let index1 = objectStore1.createIndex("bar", "key");
       let index2 = objectStore2.index("bar");
       ok(index1 === index2, "Got same indexes");
 
-      request.onsuccess = continueToNextStep;
+      transaction.oncomplete = continueToNextStep;
       yield;
 
       transaction = db.transaction("foo");
 
       let objectStore3 = transaction.objectStore("foo");
       let objectStore4 = transaction.objectStore("foo");
       ok(objectStore3 === objectStore4, "Got same objectStores");
 
--- a/dom/indexedDB/test/test_odd_result_order.html
+++ b/dom/indexedDB/test/test_odd_result_order.html
@@ -24,17 +24,17 @@
       ok(db instanceof IDBDatabase, "Got a real database");
 
       db.onerror = errorHandler;
 
       let objectStore = db.createObjectStore("foo", { keyPath: "key",
                                                       autoIncrement: true });
       let index = objectStore.createIndex("foo", "index");
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
       yield;
 
       objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
                       .objectStore("foo");
       request = objectStore.add(data);
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
--- a/dom/indexedDB/test/test_open_objectStore.html
+++ b/dom/indexedDB/test/test_open_objectStore.html
@@ -15,28 +15,28 @@
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Bad objectStores list");
 
       let objectStore = db.createObjectStore(objectStoreName,
                                              { keyPath: "foo" });
 
       is(db.objectStoreNames.length, 1, "Bad objectStores list");
       is(db.objectStoreNames.item(0), objectStoreName, "Bad name");
 
+      continueToNextStep();
       yield;
 
       objectStore = db.transaction(objectStoreName).objectStore(objectStoreName);
 
       is(objectStore.name, objectStoreName, "Bad name");
       is(objectStore.keyPath, "foo", "Bad keyPath");
       if(objectStore.indexNames.length, 0, "Bad indexNames");
 
--- a/dom/indexedDB/test/test_overlapping_transactions.html
+++ b/dom/indexedDB/test/test_overlapping_transactions.html
@@ -21,17 +21,17 @@
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
-      event.target.onsuccess = grabEventAndContinueHandler;
+      event.target.transaction.oncomplete = grabEventAndContinueHandler;
       for (let i in objectStores) {
         db.createObjectStore(objectStores[i], { autoIncrement: true });
       }
       let event = yield;
 
       is(db.objectStoreNames.length, objectStores.length,
          "Correct objectStoreNames list");
 
--- a/dom/indexedDB/test/test_readonly_transactions.html
+++ b/dom/indexedDB/test/test_readonly_transactions.html
@@ -17,26 +17,23 @@
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const osName = "foo";
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
       db.createObjectStore(osName, { autoIncrement: "true" });
 
-      yield;
-
       let key1, key2;
 
       request = db.transaction([osName], READ_WRITE)
                   .objectStore(osName)
                   .add({});
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
         is(event.target.transaction.mode, READ_WRITE, "Correct mode");
deleted file mode 100644
--- a/dom/indexedDB/test/test_setVersion_exclusion.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
-  <script type="text/javascript;version=1.7">
-    function testSteps()
-    {
-      const name = window.location.pathname;
-
-      let request = mozIndexedDB.open(name, 1);
-      request.onerror = errorHandler;
-      request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = unexpectedSuccessHandler;
-
-      let request2 = mozIndexedDB.open(name, 2);
-      request2.onerror = errorHandler;
-      request2.onupgradeneeded = unexpectedSuccessHandler;
-
-      let event = yield;
-      is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
-      is(event.target, request, "Event should be fired on the request");
-      ok(event.target.result instanceof IDBDatabase, "Expect a database here");
-
-      let db = event.target.result;
-      is(db.version, 1, "Database has correct version");
-
-      db.onupgradeneeded = function() {
-        ok(false, "our ongoing VERSION_CHANGE transaction should exclude any others!");
-      }
-
-      db.createObjectStore("foo");
-
-      try {
-        db.transaction("foo");
-        ok(false, "Transactions should be disallowed now!");
-      } catch (e) {
-        ok(e instanceof IDBDatabaseException, "Expect an IDBException");
-        is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
-      }
-
-      request.transaction.oncomplete = grabEventAndContinueHandler;
-
-      yield;
-
-      // The database is still not fully open here.
-      try {
-        db.transaction("foo");
-        ok(false, "Transactions should be disallowed now!");
-      } catch (e) {
-        ok(e instanceof IDBDatabaseException, "Expect an IDBException");
-        is(e.code, IDBDatabaseException.NOT_ALLOWED_ERR, "Expect a NOT_ALLOWED_ERR");
-      }
-
-      request.onsuccess = grabEventAndContinueHandler;
-
-      yield;
-
-      db.onversionchange = function() {
-        ok(true, "next setVersion was unblocked appropriately");
-        db.close();
-      }
-
-      try {
-        db.transaction("foo");
-        ok(true, "Transactions should be allowed now!");
-      } catch (e) {
-        ok(false, "Transactions should be allowed now!");
-      }
-
-      request2.onupgradeneeded = null;
-
-      finishTest();
-      yield;
-    }
-
-  </script>
-  <script type="text/javascript;version=1.7" src="helpers.js"></script>
-
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
--- a/dom/indexedDB/test/test_success_events_after_abort.html
+++ b/dom/indexedDB/test/test_success_events_after_abort.html
@@ -14,17 +14,17 @@
     {
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo");
       objectStore.add({}, 1).onerror = errorHandler;
 
       yield;
 
       objectStore = db.transaction("foo").objectStore("foo");
 
--- a/dom/indexedDB/test/test_transaction_abort.html
+++ b/dom/indexedDB/test/test_transaction_abort.html
@@ -24,17 +24,16 @@
 
       const name = window.location.pathname;
       const description = "My Test Database";
 
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let transaction;
       let objectStore;
 
       transaction = event.target.transaction;
@@ -153,18 +152,16 @@
       try {
         objectStore.deleteIndex("bar");
         ok(false, "Should have thrown");
       }
       catch (e) {
         ok(true, "RemoveIndex threw");
       }
 
-      yield;
-
       request = db.transaction("foo", READ_WRITE).objectStore("foo").add({});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       event.target.transaction.onabort = function(event) {
         ok(false, "Shouldn't see an abort event!");
       };
--- a/dom/indexedDB/test/test_transaction_lifetimes.html
+++ b/dom/indexedDB/test/test_transaction_lifetimes.html
@@ -15,17 +15,17 @@
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       db.createObjectStore("foo", { autoIncrement: true });
       yield;
 
       let transaction = db.transaction("foo");
       continueToNextStep();
       yield;
 
--- a/dom/indexedDB/test/test_transaction_lifetimes_nested.html
+++ b/dom/indexedDB/test/test_transaction_lifetimes_nested.html
@@ -15,17 +15,17 @@
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      event.target.onsuccess = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
       db.createObjectStore("foo");
       yield;
 
       let transaction1 = db.transaction("foo");
       is(transaction1.readyState, IDBTransaction.INITIAL, "Correct readyState");
 
       let transaction2;
 
--- a/dom/indexedDB/test/test_writer_starvation.html
+++ b/dom/indexedDB/test/test_writer_starvation.html
@@ -18,33 +18,33 @@
         Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
 
       const name = window.location.pathname;
       const description = "My Test Database";
 
       let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
-      request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
 
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       request = objectStore.add({});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       let key = event.target.result;
       ok(key, "Got a key");
 
+      SimpleTest.executeSoon(function() { testGenerator.next(); });
       yield;
 
       let continueReading = true;
       let readerCount = 0;
       let callbackCount = 0;
       let finalCallbackCount = 0;
 
       // Generate a bunch of reads right away without returning to the event