Bug 1071360 - Fix async storage connection closing when open fails. r=asuth, a=sledru
authorBen Turner <bent.mozilla@gmail.com>
Fri, 27 Mar 2015 22:45:28 -0700
changeset 258273 0e9a4f42d12a
parent 258272 537b5f078296
child 258274 f8e17839eac9
push id4633
push userryanvm@gmail.com
push date2015-04-06 15:44 +0000
treeherdermozilla-beta@e749a39aaf5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, sledru
bugs1071360
milestone38.0
Bug 1071360 - Fix async storage connection closing when open fails. r=asuth, a=sledru
build/mozconfig.common
storage/src/mozStorageConnection.cpp
storage/src/mozStorageService.cpp
--- a/build/mozconfig.common
+++ b/build/mozconfig.common
@@ -5,15 +5,17 @@
 # Common mozconfig for official builds.
 #
 # Add options to this file that will be inherited by all in-tree mozconfigs.
 # This is useful for eg try builds with nondefault options that apply to all
 # architectures, though note that if you want to override options set in
 # another mozconfig file, you'll need to use mozconfig.common.override instead
 # of this file.
 
+MOZ_CRASHREPORTER_UPLOAD_FULL_SYMBOLS=1
+
 mk_add_options AUTOCLOBBER=1
 
 ac_add_options --enable-crashreporter
 
 ac_add_options --enable-release
 
 . "$topsrcdir/build/mozconfig.automation"
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -867,17 +867,18 @@ Connection::isClosed()
   MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
   return mConnectionClosed;
 }
 
 nsresult
 Connection::internalClose(sqlite3 *aNativeConnection)
 {
   // Sanity checks to make sure we are in the proper state before calling this.
-  MOZ_ASSERT(aNativeConnection, "Database connection is invalid!");
+  // aNativeConnection can be null if OpenAsyncDatabase failed and is now just
+  // cleaning up the async thread.
   MOZ_ASSERT(!isClosed());
 
 #ifdef DEBUG
   { // Make sure we have marked our async thread as shutting down.
     MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
     NS_ASSERTION(mAsyncExecutionThreadShuttingDown,
                  "Did not call setClosedState!");
   }
@@ -896,16 +897,21 @@ Connection::internalClose(sqlite3 *aNati
   // always disconnect any virtual tables and cleanly finalize their
   // internal statements. Once this is done, closing may fail due to
   // unfinalized client statements, in which case we need to finalize
   // these statements and close again.
   {
     MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
     mConnectionClosed = true;
   }
+
+  // Nothing else needs to be done if we don't have a connection here.
+  if (!aNativeConnection)
+    return NS_OK;
+
   int srv = sqlite3_close(aNativeConnection);
 
   if (srv == SQLITE_BUSY) {
     // We still have non-finalized statements. Finalize them.
 
     sqlite3_stmt *stmt = nullptr;
     while ((stmt = ::sqlite3_next_stmt(aNativeConnection, stmt))) {
       PR_LOG(gStorageLog, PR_LOG_NOTICE,
@@ -1143,21 +1149,24 @@ Connection::Close()
 }
 
 NS_IMETHODIMP
 Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
 {
   if (!NS_IsMainThread()) {
     return NS_ERROR_NOT_SAME_THREAD;
   }
-  if (!mDBConn)
-    return NS_ERROR_NOT_INITIALIZED;
 
+  // It's possible to get here with a null mDBConn but a non-null async
+  // execution target if OpenAsyncDatabase failed somehow, so don't exit early
+  // in that case.
   nsIEventTarget *asyncThread = getAsyncExecutionTarget();
-  NS_ENSURE_TRUE(asyncThread, NS_ERROR_NOT_INITIALIZED);
+
+  if (!mDBConn && !asyncThread)
+    return NS_ERROR_NOT_INITIALIZED;
 
   // setClosedState nullifies our connection pointer, so we take a raw pointer
   // off it, to pass it through the close procedure.
   sqlite3 *nativeConn = mDBConn;
   nsresult rv = setClosedState();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create our callback event if we were given a callback.
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -679,16 +679,24 @@ public:
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     nsresult rv = mStorageFile ? mConnection->initialize(mStorageFile)
                                : mConnection->initialize();
     if (NS_FAILED(rv)) {
+      nsCOMPtr<nsIRunnable> closeRunnable =
+        NS_NewRunnableMethodWithArg<mozIStorageCompletionCallback*>(
+          mConnection.get(),
+          &Connection::AsyncClose,
+          nullptr);
+      MOZ_ASSERT(closeRunnable);
+      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(closeRunnable)));
+
       return DispatchResult(rv, nullptr);
     }
 
     if (mGrowthIncrement >= 0) {
       // Ignore errors. In the future, we might wish to log them.
       (void)mConnection->SetGrowthIncrement(mGrowthIncrement, EmptyCString());
     }