Bug 1256049: Add some diagnostic code for an IDB crash. r=janv
authorKyle Huey <khuey@kylehuey.com>
Fri, 18 Mar 2016 14:15:45 -0700
changeset 289413 3bfa5a8fd0157c3109e39c0c49045aca9fac9d30
parent 289412 2da6cf4f1870ed7b69896ba8373c97559f2dad2c
child 289414 a5b20cd884fe2ae58ddd9ecf1a52bd067bbdcd4e
push id30102
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:23:17 +0000
treeherdermozilla-central@720fb3d55e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv
bugs1256049
milestone48.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 1256049: Add some diagnostic code for an IDB crash. r=janv
dom/indexedDB/ActorsParent.cpp
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ActorsParent.h"
 
 #include <algorithm>
@@ -4987,17 +4987,17 @@ public:
 
     return CheckpointInternal(CheckpointMode::Full);
   }
 
   void
   DoIdleProcessing(bool aNeedsCheckpoint);
 
   void
-  Close();
+  Close(uintptr_t aCallsite = 0);
 
   nsresult
   DisableQuotaChecks();
 
   void
   EnableQuotaChecks();
 
 private:
@@ -5355,17 +5355,17 @@ private:
 
   bool
   MaybeFireCallback(DatabasesCompleteCallback* aCallback);
 
   void
   PerformIdleDatabaseMaintenance(DatabaseInfo* aDatabaseInfo);
 
   void
-  CloseDatabase(DatabaseInfo* aDatabaseInfo);
+  CloseDatabase(DatabaseInfo* aDatabaseInfo, uintptr_t aCallsite);
 
   bool
   CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId);
 };
 
 class ConnectionPool::ConnectionRunnable
   : public nsRunnable
 {
@@ -5401,27 +5401,31 @@ private:
   NS_DECL_NSIRUNNABLE
 };
 
 class ConnectionPool::CloseConnectionRunnable final
   : public ConnectionRunnable
 {
 public:
   explicit
-  CloseConnectionRunnable(DatabaseInfo* aDatabaseInfo)
-    : ConnectionRunnable(aDatabaseInfo)
+  CloseConnectionRunnable(DatabaseInfo* aDatabaseInfo,
+                          uintptr_t aCallsite)
+    : ConnectionRunnable(aDatabaseInfo),
+      mCallsite(aCallsite)
   { }
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   ~CloseConnectionRunnable()
   { }
 
   NS_DECL_NSIRUNNABLE
+
+  uintptr_t mCallsite;
 };
 
 struct ConnectionPool::ThreadInfo
 {
   nsCOMPtr<nsIThread> mThread;
   RefPtr<ThreadRunnable> mRunnable;
 
   ThreadInfo();
@@ -10447,22 +10451,26 @@ DatabaseConnection::GetFreelistCount(Cac
 
   MOZ_ASSERT(freelistCount >= 0);
 
   *aFreelistCount = uint32_t(freelistCount);
   return NS_OK;
 }
 
 void
-DatabaseConnection::Close()
+DatabaseConnection::Close(uintptr_t aCallsite)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(!mDEBUGSavepointCount);
-  MOZ_RELEASE_ASSERT(!mInWriteTransaction);
+  if (mInWriteTransaction) {
+    uint32_t* crashPtr = (uint32_t*)aCallsite;
+    *crashPtr = 42;
+    MOZ_RELEASE_ASSERT(!mInWriteTransaction);
+  }
 
   PROFILER_LABEL("IndexedDB",
                  "DatabaseConnection::Close",
                  js::ProfileEntry::Category::STORAGE);
 
   if (mUpdateRefcountFunction) {
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
       mStorageConnection->RemoveFunction(
@@ -11360,17 +11368,17 @@ ConnectionPool::IdleTimerCallback(nsITim
 
   for (uint32_t count = self->mIdleDatabases.Length(); index < count; index++) {
     IdleDatabaseInfo& info = self->mIdleDatabases[index];
 
     if (now >= info.mIdleTime) {
       if (info.mDatabaseInfo->mIdle) {
         self->PerformIdleDatabaseMaintenance(info.mDatabaseInfo);
       } else {
-        self->CloseDatabase(info.mDatabaseInfo);
+        self->CloseDatabase(info.mDatabaseInfo, 1);
       }
     } else {
       break;
     }
   }
 
   if (index) {
     self->mIdleDatabases.RemoveElementsAt(0, index);
@@ -11838,25 +11846,25 @@ ConnectionPool::CloseIdleDatabases()
   MOZ_ASSERT(mShutdownRequested);
 
   PROFILER_LABEL("IndexedDB",
                  "ConnectionPool::CloseIdleDatabases",
                  js::ProfileEntry::Category::STORAGE);
 
   if (!mIdleDatabases.IsEmpty()) {
     for (IdleDatabaseInfo& idleInfo : mIdleDatabases) {
-      CloseDatabase(idleInfo.mDatabaseInfo);
+      CloseDatabase(idleInfo.mDatabaseInfo, 2);
     }
     mIdleDatabases.Clear();
   }
 
   if (!mDatabasesPerformingIdleMaintenance.IsEmpty()) {
     for (DatabaseInfo* dbInfo : mDatabasesPerformingIdleMaintenance) {
       MOZ_ASSERT(dbInfo);
-      CloseDatabase(dbInfo);
+      CloseDatabase(dbInfo, 3);
     }
     mDatabasesPerformingIdleMaintenance.Clear();
   }
 }
 
 void
 ConnectionPool::ShutdownIdleThreads()
 {
@@ -12152,17 +12160,17 @@ ConnectionPool::NoteIdleDatabase(Databas
 
   const bool otherDatabasesWaiting = !mQueuedTransactions.IsEmpty();
 
   if (mShutdownRequested ||
       otherDatabasesWaiting ||
       aDatabaseInfo->mCloseOnIdle) {
     // Make sure we close the connection if we're shutting down or giving the
     // thread to another database.
-    CloseDatabase(aDatabaseInfo);
+    CloseDatabase(aDatabaseInfo, 4);
 
     if (otherDatabasesWaiting) {
       // Let another database use this thread.
       ScheduleQueuedTransactions(aDatabaseInfo->mThreadInfo);
     } else if (mShutdownRequested) {
       // If there are no other databases that need to run then we can shut this
       // thread down immediately instead of going through the idle thread
       // mechanism.
@@ -12333,30 +12341,32 @@ ConnectionPool::PerformIdleDatabaseMaint
   mDatabasesPerformingIdleMaintenance.AppendElement(aDatabaseInfo);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable,
                                                  NS_DISPATCH_NORMAL)));
 }
 
 void
-ConnectionPool::CloseDatabase(DatabaseInfo* aDatabaseInfo)
+ConnectionPool::CloseDatabase(DatabaseInfo* aDatabaseInfo,
+                              uintptr_t aCallsite)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aDatabaseInfo);
   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   MOZ_ASSERT(!aDatabaseInfo->mClosing);
 
   aDatabaseInfo->mIdle = false;
   aDatabaseInfo->mNeedsCheckpoint = false;
   aDatabaseInfo->mClosing = true;
 
-  nsCOMPtr<nsIRunnable> runnable = new CloseConnectionRunnable(aDatabaseInfo);
+  nsCOMPtr<nsIRunnable> runnable = new CloseConnectionRunnable(aDatabaseInfo,
+                                                               aCallsite);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable,
                                                  NS_DISPATCH_NORMAL)));
 }
 
 bool
 ConnectionPool::CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId)
@@ -12366,17 +12376,17 @@ ConnectionPool::CloseDatabaseWhenIdleInt
 
   PROFILER_LABEL("IndexedDB",
                  "ConnectionPool::CloseDatabaseWhenIdleInternal",
                  js::ProfileEntry::Category::STORAGE);
 
   if (DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId)) {
     if (mIdleDatabases.RemoveElement(dbInfo) ||
         mDatabasesPerformingIdleMaintenance.RemoveElement(dbInfo)) {
-      CloseDatabase(dbInfo);
+      CloseDatabase(dbInfo, 5);
       AdjustIdleTimer();
     } else {
       dbInfo->mCloseOnIdle = true;
     }
 
     return true;
   }
 
@@ -12454,17 +12464,17 @@ CloseConnectionRunnable::Run()
     MOZ_ASSERT(mDatabaseInfo->mClosing);
 
     nsCOMPtr<nsIEventTarget> owningThread;
     mOwningThread.swap(owningThread);
 
     if (mDatabaseInfo->mConnection) {
       mDatabaseInfo->AssertIsOnConnectionThread();
 
-      mDatabaseInfo->mConnection->Close();
+      mDatabaseInfo->mConnection->Close(mCallsite);
 
       IDB_DEBUG_LOG(("ConnectionPool closed connection 0x%p",
                      mDatabaseInfo->mConnection.get()));
 
       mDatabaseInfo->mConnection = nullptr;
 
 #ifdef DEBUG
       mDatabaseInfo->mDEBUGConnectionThread = nullptr;