Bug 1411908 - Part 1: Wait for all live database objects to finish when shutting down; r=asuth
authorJan Varga <jan.varga@gmail.com>
Fri, 04 May 2018 06:32:11 +0200
changeset 470458 1a0c61c2cf60a2c0e4bf7035effd467dd6185f65
parent 470457 693b1b3389fb013086aa57b2ef6e230e8c4b39d5
child 470459 f579a28444855e4ccbf45c8c82f9bb78ebbe822b
push id9182
push usernerli@mozilla.com
push dateFri, 04 May 2018 15:39:56 +0000
treeherdermozilla-beta@01ab1ea4c55a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1411908
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1411908 - Part 1: Wait for all live database objects to finish when shutting down; r=asuth
dom/indexedDB/ActorsParent.cpp
dom/indexedDB/test/unit/test_storageOption_pref.js
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -6344,17 +6344,16 @@ private:
   const uint32_t mTelemetryId;
   const PersistenceType mPersistenceType;
   const bool mFileHandleDisabled;
   const bool mChromeWriteAccessAllowed;
   bool mClosed;
   bool mInvalidated;
   bool mActorWasAlive;
   bool mActorDestroyed;
-  bool mMetadataCleanedUp;
 #ifdef DEBUG
   bool mAllBlobsUnmapped;
 #endif
 
 public:
   // Created by OpenDatabaseOp.
   Database(Factory* aFactory,
            const PrincipalInfo& aPrincipalInfo,
@@ -13863,17 +13862,16 @@ Database::Database(Factory* aFactory,
   , mTelemetryId(aTelemetryId)
   , mPersistenceType(aMetadata->mCommonMetadata.persistenceType())
   , mFileHandleDisabled(aFileHandleDisabled)
   , mChromeWriteAccessAllowed(aChromeWriteAccessAllowed)
   , mClosed(false)
   , mInvalidated(false)
   , mActorWasAlive(false)
   , mActorDestroyed(false)
-  , mMetadataCleanedUp(false)
 #ifdef DEBUG
   , mAllBlobsUnmapped(false)
 #endif
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aFactory);
   MOZ_ASSERT(aMetadata);
   MOZ_ASSERT(aFileManager);
@@ -13976,18 +13974,16 @@ Database::Invalidate()
     NS_WARNING("Failed to abort all transactions!");
   }
 
   if (!Helper::InvalidateMutableFiles(mMutableFiles)) {
     NS_WARNING("Failed to abort all mutable files!");
   }
 
   MOZ_ALWAYS_TRUE(CloseInternal());
-
-  CleanupMetadata();
 }
 
 nsresult
 Database::EnsureConnection()
 {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!IsOnBackgroundThread());
 
@@ -14243,32 +14239,28 @@ Database::ConnectionClosedCallback()
   }
 }
 
 void
 Database::CleanupMetadata()
 {
   AssertIsOnBackgroundThread();
 
-  if (!mMetadataCleanedUp) {
-    mMetadataCleanedUp = true;
-
-    DatabaseActorInfo* info;
-    MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(Id(), &info));
-    MOZ_ALWAYS_TRUE(info->mLiveDatabases.RemoveElement(this));
-
-    if (info->mLiveDatabases.IsEmpty()) {
-      MOZ_ASSERT(!info->mWaitingFactoryOp ||
-                 !info->mWaitingFactoryOp->HasBlockedDatabases());
-      gLiveDatabaseHashtable->Remove(Id());
-    }
-
-    // Match the IncreaseBusyCount in OpenDatabaseOp::EnsureDatabaseActor().
-    DecreaseBusyCount();
-  }
+  DatabaseActorInfo* info;
+  MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(Id(), &info));
+  MOZ_ALWAYS_TRUE(info->mLiveDatabases.RemoveElement(this));
+
+  if (info->mLiveDatabases.IsEmpty()) {
+    MOZ_ASSERT(!info->mWaitingFactoryOp ||
+               !info->mWaitingFactoryOp->HasBlockedDatabases());
+    gLiveDatabaseHashtable->Remove(Id());
+  }
+
+  // Match the IncreaseBusyCount in OpenDatabaseOp::EnsureDatabaseActor().
+  DecreaseBusyCount();
 }
 
 bool
 Database::VerifyRequestParams(const DatabaseRequestParams& aParams) const
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aParams.type() != DatabaseRequestParams::T__None);
 
@@ -17883,46 +17875,44 @@ QuotaClient::StopIdleMaintenance()
 void
 QuotaClient::ShutdownWorkThreads()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mShutdownRequested);
 
   mShutdownRequested = true;
 
-  // Shutdown maintenance thread pool (this spins the event loop until all
-  // threads are gone). This should release any maintenance related quota
-  // objects.
-  if (mMaintenanceThreadPool) {
-    mMaintenanceThreadPool->Shutdown();
-    mMaintenanceThreadPool = nullptr;
-  }
-
-  // Let any runnables dispatched from dying maintenance threads to be
-  // processed. This should release any maintenance related directory locks.
-  if (mCurrentMaintenance) {
-    MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() {
-      return !mCurrentMaintenance;
-    }));
-  }
-
+  AbortOperations(VoidCString());
+
+  // This should release any IDB related quota objects or directory locks.
+  MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() {
+    return (!gLiveDatabaseHashtable || !gLiveDatabaseHashtable->Count()) &&
+           !mCurrentMaintenance;
+  }));
+
+  // And finally, shutdown all threads.
   RefPtr<ConnectionPool> connectionPool = gConnectionPool.get();
   if (connectionPool) {
     connectionPool->Shutdown();
 
     gConnectionPool = nullptr;
   }
 
   RefPtr<FileHandleThreadPool> fileHandleThreadPool =
     gFileHandleThreadPool.get();
   if (fileHandleThreadPool) {
     fileHandleThreadPool->Shutdown();
 
     gFileHandleThreadPool = nullptr;
   }
+
+  if (mMaintenanceThreadPool) {
+    mMaintenanceThreadPool->Shutdown();
+    mMaintenanceThreadPool = nullptr;
+  }
 }
 
 void
 QuotaClient::DidInitialize(QuotaManager* aQuotaManager)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get()) {
--- a/dom/indexedDB/test/unit/test_storageOption_pref.js
+++ b/dom/indexedDB/test/unit/test_storageOption_pref.js
@@ -79,20 +79,24 @@ function* testSteps()
   request = indexedDB.openForPrincipal(principal, name,
     { version, storage: "persistent" });
 
   request.onerror = errorHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield undefined;
 
+  is(event.type, "upgradeneeded", "Got correct event type");
+
   db = event.target.result;
   db.onerror = errorHandler;
 
-  is(event.type, "upgradeneeded", "Got correct event type");
+  event = yield undefined;
+
+  is(event.type, "success", "Got correct event type");
 
   is(db.name, name, "Correct name");
   is(db.version, version, "Correct version");
   is(db.storage, "persistent", "Correct persistence type");
 
   // A new database was created (because it changed persistence type).
   is(db.objectStoreNames.length, 0, "Got no data");