Bug 1156063 - Intermittent application crashed [@ mozilla::dom::indexedDB::::ConnectionPool::Start] in various tests. r=janv, a=lizzard
☠☠ backed out by 5822851d2911 ☠ ☠
authorDoug Turner <doug.turner@gmail.com>
Mon, 04 May 2015 14:10:00 -0400
changeset 265880 57fa7552c3c3691ea47fd8a65d99f12139d25069
parent 265879 5de0834fe8a9a2d81867a26c497da9c4fa29ba6c
child 265881 d6d584d072bb8875370ac4dc19c1ef1da4207b88
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv, lizzard
bugs1156063
milestone39.0a2
Bug 1156063 - Intermittent application crashed [@ mozilla::dom::indexedDB::::ConnectionPool::Start] in various tests. r=janv, a=lizzard
dom/indexedDB/ActorsParent.cpp
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -4127,26 +4127,32 @@ private:
 
   void
   EnsureDatabaseActor();
 
   nsresult
   EnsureDatabaseActorIsAlive();
 
   void
+  CleanupBackgroundThreadObjects(bool aInvalidate);
+
+  void
   MetadataToSpec(DatabaseSpec& aSpec);
 
   void
   AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
 #ifdef DEBUG
   ;
 #else
   { }
 #endif
 
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
   virtual nsresult
   QuotaManagerOpen() override;
 
   virtual nsresult
   DoDatabaseWork() override;
 
   virtual nsresult
   BeginVersionChange() override;
@@ -5177,17 +5183,17 @@ public:
   }
 
   static bool
   IsShuttingDownOnMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (sInstance) {
-      return sInstance->mShutdownRequested;
+      return sInstance->IsShuttingDown();
     }
 
     return QuotaManager::IsShuttingDown();
   }
 
   static bool
   IsShuttingDownOnNonMainThread()
   {
@@ -5258,23 +5264,21 @@ private:
                                UsageInfo* aUsageInfo,
                                bool aDatabaseFiles);
 };
 
 class QuotaClient::ShutdownTransactionThreadPoolRunnable final
   : public nsRunnable
 {
   nsRefPtr<QuotaClient> mQuotaClient;
-  bool mHasRequestedShutDown;
 
 public:
 
   explicit ShutdownTransactionThreadPoolRunnable(QuotaClient* aQuotaClient)
     : mQuotaClient(aQuotaClient)
-    , mHasRequestedShutDown(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aQuotaClient);
     MOZ_ASSERT(QuotaClient::GetInstance() == aQuotaClient);
     MOZ_ASSERT(aQuotaClient->mShutdownRequested);
   }
 
   NS_DECL_ISUPPORTS_INHERITED
@@ -9856,38 +9860,32 @@ WaitForTransactionsRunnable::Run()
 NS_IMPL_ISUPPORTS_INHERITED0(QuotaClient::ShutdownTransactionThreadPoolRunnable,
                              nsRunnable)
 
 NS_IMETHODIMP
 QuotaClient::
 ShutdownTransactionThreadPoolRunnable::Run()
 {
   if (NS_IsMainThread()) {
-    MOZ_ASSERT(mHasRequestedShutDown);
     MOZ_ASSERT(QuotaClient::GetInstance() == mQuotaClient);
     MOZ_ASSERT(mQuotaClient->mShutdownRunnable == this);
 
     mQuotaClient->mShutdownRunnable = nullptr;
     mQuotaClient = nullptr;
 
     return NS_OK;
   }
 
   AssertIsOnBackgroundThread();
 
-  if (!mHasRequestedShutDown) {
-    mHasRequestedShutDown = true;
-
-    nsRefPtr<TransactionThreadPool> threadPool = gTransactionThreadPool.get();
-    if (threadPool) {
-      threadPool->Shutdown();
-
-      gTransactionThreadPool = nullptr;
-    }
-
+  nsRefPtr<TransactionThreadPool> threadPool = gTransactionThreadPool.get();
+  if (threadPool) {
+    threadPool->Shutdown();
+
+    gTransactionThreadPool = nullptr;
   }
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this)));
 
   return NS_OK;
 }
 
 /*******************************************************************************
@@ -11209,16 +11207,28 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* 
     // This is a little scary but it looks safe to call this off the main thread
     // for now.
     optionalContentParentId = mContentParent->ChildID();
   } else {
     optionalContentParentId = void_t();
   }
 }
 
+void
+OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
+{
+  AssertIsOnOwningThread();
+
+  FactoryOp::ActorDestroy(aWhy);
+
+  if (aWhy != Deletion) {
+    CleanupBackgroundThreadObjects(/* aInvalidate */ true);
+  }
+}
+
 nsresult
 OpenDatabaseOp::QuotaManagerOpen()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == State_OpenPending);
   MOZ_ASSERT(!mOfflineStorage);
 
   QuotaClient* quotaClient = QuotaClient::GetInstance();
@@ -11719,17 +11729,16 @@ OpenDatabaseOp::BeginVersionChange()
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_BeginVersionChange);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   MOZ_ASSERT(mMetadata->mCommonMetadata.version() <= mRequestedVersion);
   MOZ_ASSERT(!mDatabase);
   MOZ_ASSERT(!mVersionChangeTransaction);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
-      !OperationMayProceed() ||
       IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   EnsureDatabaseActor();
 
   if (mDatabase->IsInvalidated()) {
@@ -11837,17 +11846,18 @@ OpenDatabaseOp::DispatchToWorkThread()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
   MOZ_ASSERT(mVersionChangeTransaction);
   MOZ_ASSERT(mVersionChangeTransaction->GetMode() ==
                IDBTransaction::VERSION_CHANGE);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
 
-  if (IsActorDestroyed()) {
+  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
+      IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   mState = State_DatabaseWorkVersionChange;
 
   // Intentionally empty.
   nsTArray<nsString> objectStoreNames;
@@ -11884,17 +11894,16 @@ OpenDatabaseOp::SendUpgradeNeeded()
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_DatabaseWorkVersionChange);
   MOZ_ASSERT(mVersionChangeTransaction);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   MOZ_ASSERT_IF(!IsActorDestroyed(), mDatabase);
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
-      !OperationMayProceed() ||
       IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsRefPtr<VersionChangeTransaction> transaction;
   mVersionChangeTransaction.swap(transaction);
 
@@ -11945,17 +11954,21 @@ OpenDatabaseOp::SendResults()
 
   if (mVersionChangeTransaction) {
     MOZ_ASSERT(NS_FAILED(mResultCode));
 
     mVersionChangeTransaction->Abort(mResultCode, /* aForce */ true);
     mVersionChangeTransaction = nullptr;
   }
 
-  if (!IsActorDestroyed()) {
+  if (IsActorDestroyed()) {
+    if (NS_SUCCEEDED(mResultCode)) {
+      mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+  } else {
     FactoryRequestResponse response;
 
     if (NS_SUCCEEDED(mResultCode)) {
       // If we just successfully completed a versionchange operation then we
       // need to update the version in our metadata.
       mMetadata->mCommonMetadata.version() = mRequestedVersion;
 
       nsresult rv = EnsureDatabaseActorIsAlive();
@@ -11980,24 +11993,17 @@ OpenDatabaseOp::SendResults()
 #endif
       response = ClampResultCode(mResultCode);
     }
 
     unused <<
       PBackgroundIDBFactoryRequestParent::Send__delete__(this, response);
   }
 
-  if (NS_FAILED(mResultCode) && mOfflineStorage) {
-    mOfflineStorage->CloseOnOwningThread();
-    DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
-  }
-
-  // Make sure to release the database on this thread.
-  nsRefPtr<Database> database;
-  mDatabase.swap(database);
+  CleanupBackgroundThreadObjects(NS_FAILED(mResultCode));
 
   FinishSendResults();
 }
 
 void
 OpenDatabaseOp::EnsureDatabaseActor()
 {
   AssertIsOnOwningThread();
@@ -12070,16 +12076,37 @@ OpenDatabaseOp::EnsureDatabaseActorIsAli
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   return NS_OK;
 }
 
 void
+OpenDatabaseOp::CleanupBackgroundThreadObjects(bool aInvalidate)
+{
+  AssertIsOnOwningThread();
+  MOZ_ASSERT(IsActorDestroyed());
+
+  if (mDatabase) {
+    MOZ_ASSERT(!mOfflineStorage);
+
+    if (aInvalidate) {
+      mDatabase->Invalidate();
+    }
+
+    // Make sure to release the database on this thread.
+    mDatabase = nullptr;
+  } else if (mOfflineStorage) {
+    mOfflineStorage->CloseOnOwningThread();
+    DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
+  }
+}
+
+void
 OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mMetadata);
 
   class MOZ_STACK_CLASS Helper final
   {
     DatabaseSpec& mSpec;
@@ -12582,17 +12609,16 @@ DeleteDatabaseOp::DoDatabaseWork()
 nsresult
 DeleteDatabaseOp::BeginVersionChange()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_BeginVersionChange);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
-      !OperationMayProceed() ||
       IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   DatabaseActorInfo* info;
   if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
     MOZ_ASSERT(!info->mWaitingFactoryOp);
@@ -12622,17 +12648,16 @@ DeleteDatabaseOp::BeginVersionChange()
 nsresult
 DeleteDatabaseOp::DispatchToWorkThread()
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
-      !OperationMayProceed() ||
       IsActorDestroyed()) {
     IDB_REPORT_INTERNAL_ERR();
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   mState = State_DatabaseWorkVersionChange;
 
   nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);