Finalize cached statements on the connection thread
authorBen Turner <bent.mozilla@gmail.com>
Thu, 06 May 2010 22:17:14 -0700
changeset 43980 4fc61aed70cd948eb796ecde82c41092e107eee9
parent 43979 a016bd48d084243bca556a5461d6887d6fd451ad
child 43981 2bd807167653d399d781b0305171da7d94113124
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone1.9.3a5pre
Finalize cached statements on the connection thread
dom/indexedDB/IDBDatabaseRequest.cpp
dom/indexedDB/IDBDatabaseRequest.h
--- a/dom/indexedDB/IDBDatabaseRequest.cpp
+++ b/dom/indexedDB/IDBDatabaseRequest.cpp
@@ -66,44 +66,55 @@ const PRUint32 kDefaultThreadTimeoutMS =
 inline
 nsISupports*
 isupports_cast(IDBDatabaseRequest* aClassPtr)
 {
   return static_cast<nsISupports*>(
     static_cast<IDBRequest::Generator*>(aClassPtr));
 }
 
+template<class T1, class T2>
+inline
+void
+SwapCOMPtrs(nsCOMPtr<T1>& a1,
+            nsCOMPtr<T2>& a2)
+{
+  nsCOMPtr<T1> temp1;
+  temp1.swap(a1);
+
+  nsCOMPtr<T2> temp2;
+  temp2.swap(a2);
+
+  a1 = do_QueryInterface(temp2);
+  if (temp2) {
+    NS_ASSERTION(a1, "QI failed!");
+  }
+
+  a2 = do_QueryInterface(temp1);
+  if (temp1) {
+    NS_ASSERTION(a2, "QI failed!");
+  }
+}
+
 class CloseConnectionRunnable : public nsRunnable
 {
 public:
-  CloseConnectionRunnable(nsIThread* aThread,
-                          nsCOMPtr<mozIStorageConnection>& aConnection)
-  : mThread(aThread)
+  CloseConnectionRunnable(nsTArray<nsCOMPtr<nsISupports> >& aDoomedObjects)
   {
-    NS_ASSERTION(mThread, "No thread!");
-    mConnection.swap(aConnection);
+    mDoomedObjects.SwapElements(aDoomedObjects);
   }
 
   NS_IMETHOD Run()
   {
-    nsresult rv = mConnection->Close();
-    NS_ENSURE_SUCCESS(rv, rv);
+    mDoomedObjects.Clear();
     return NS_OK;
   }
 
-  void Dispatch()
-  {
-    if (mConnection && NS_FAILED(mThread->Dispatch(this, NS_DISPATCH_NORMAL))) {
-      NS_WARNING("Dispatch failed!");
-    }
-  }
-
 private:
-  nsCOMPtr<nsIThread> mThread;
-  nsCOMPtr<mozIStorageConnection> mConnection;
+  nsTArray<nsCOMPtr<nsISupports> > mDoomedObjects;
 };
 
 class CreateObjectStoreHelper : public AsyncConnectionHelper
 {
 public:
   CreateObjectStoreHelper(IDBDatabaseRequest* aDatabase,
                           nsIDOMEventTarget* aTarget,
                           const nsAString& aName,
@@ -502,67 +513,94 @@ IDBDatabaseRequest::EnsureConnection()
   return NS_OK;
 }
 
 already_AddRefed<mozIStorageStatement>
 IDBDatabaseRequest::PutStatement(bool aOverwrite,
                                  bool aAutoIncrement)
 {
   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
-  (void)EnsureConnection();
+  nsresult rv = EnsureConnection();
+  NS_ENSURE_SUCCESS(rv, nsnull);
+
+  nsCOMPtr<mozIStorageStatement> result;
 
   if (aOverwrite) {
     if (aAutoIncrement) {
       if (!mPutOverwriteAutoIncrementStmt) {
-        nsresult rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+        rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
           "INSERT OR REPLACE INTO ai_object_data (object_store_id, id, data) "
           "VALUES (:osid, :key_value, :data)"
         ), getter_AddRefs(mPutOverwriteAutoIncrementStmt));
         NS_ENSURE_SUCCESS(rv, nsnull);
       }
-      return mPutOverwriteAutoIncrementStmt;
+      result = mPutOverwriteAutoIncrementStmt;
+    }
+    else {
+      if (!mPutOverwriteStmt) {
+        rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+          "INSERT OR REPLACE INTO object_data (object_store_id, key_value, "
+                                              "data) "
+          "VALUES (:osid, :key_value, :data)"
+        ), getter_AddRefs(mPutOverwriteStmt));
+        NS_ENSURE_SUCCESS(rv, nsnull);
+      }
+      result = mPutOverwriteStmt;
     }
-
-    if (!mPutOverwriteStmt) {
-      nsresult rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
-        "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data) "
-        "VALUES (:osid, :key_value, :data)"
-      ), getter_AddRefs(mPutOverwriteStmt));
-      NS_ENSURE_SUCCESS(rv, nsnull);
+  }
+  else {
+    if (aAutoIncrement) {
+      if (!mPutAutoIncrementStmt) {
+        rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+          "INSERT INTO ai_object_data (object_store_id, data) "
+          "VALUES (:osid, :data)"
+        ), getter_AddRefs(mPutAutoIncrementStmt));
+        NS_ENSURE_SUCCESS(rv, nsnull);
+      }
+      result = mPutAutoIncrementStmt;
     }
-    return mPutOverwriteStmt;
+    else {
+      if (!mPutStmt) {
+        rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+          "INSERT INTO object_data (object_store_id, key_value, data) "
+          "VALUES (:osid, :key_value, :data)"
+        ), getter_AddRefs(mPutStmt));
+        NS_ENSURE_SUCCESS(rv, nsnull);
+      }
+      result = mPutStmt;
+    }
   }
 
-  if (aAutoIncrement) {
-    if (!mPutAutoIncrementStmt) {
-      nsresult rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
-        "INSERT INTO ai_object_data (object_store_id, data) "
-        "VALUES (:osid, :data)"
-      ), getter_AddRefs(mPutAutoIncrementStmt));
-      NS_ENSURE_SUCCESS(rv, nsnull);
-    }
-    return mPutAutoIncrementStmt;
-  }
-
-  if (!mPutStmt) {
-    nsresult rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
-      "INSERT INTO object_data (object_store_id, key_value, data) "
-      "VALUES (:osid, :key_value, :data)"
-    ), getter_AddRefs(mPutStmt));
-    NS_ENSURE_SUCCESS(rv, nsnull);
-  }
-  return mPutStmt;
+  return result.forget();
 }
 
 void
 IDBDatabaseRequest::FireCloseConnectionRunnable()
 {
-  nsRefPtr<CloseConnectionRunnable> runnable =
-    new CloseConnectionRunnable(mConnectionThread, mConnection);
-  runnable->Dispatch();
+  // Keep this in sync with the number of nsCOMPtrs we destroy!
+  static const PRUint32 kDoomedObjectCount = 5;
+  PRUint32 index = 0;
+
+  nsTArray<nsCOMPtr<nsISupports> > doomedObjects;
+  if (!doomedObjects.SetLength(kDoomedObjectCount)) {
+    NS_ERROR("OOM!");
+  }
+
+  SwapCOMPtrs(doomedObjects[index++], mConnection);
+  SwapCOMPtrs(doomedObjects[index++], mPutStmt);
+  SwapCOMPtrs(doomedObjects[index++], mPutAutoIncrementStmt);
+  SwapCOMPtrs(doomedObjects[index++], mPutOverwriteStmt);
+  SwapCOMPtrs(doomedObjects[index++], mPutOverwriteAutoIncrementStmt);
+
+  NS_ASSERTION(index == kDoomedObjectCount, "Fix this!");
+
+  mConnectionThread->Dispatch(new CloseConnectionRunnable(doomedObjects),
+                              NS_DISPATCH_NORMAL);
+
+  NS_ASSERTION(doomedObjects.Length() == 0, "Should have swapped!");
 }
 
 void
 IDBDatabaseRequest::OnObjectStoreCreated(const nsAString& aName)
 {
   NS_ASSERTION(!mObjectStoreNames.Contains(aName),
                "Already got this object store in the list!");
   if (!mObjectStoreNames.AppendElement(aName)) {
--- a/dom/indexedDB/IDBDatabaseRequest.h
+++ b/dom/indexedDB/IDBDatabaseRequest.h
@@ -115,17 +115,18 @@ private:
 
   nsTArray<nsString> mObjectStoreNames;
   nsTArray<nsString> mIndexNames;
 
   nsCOMPtr<nsIIDBTransaction> mCurrentTransaction;
 
   nsRefPtr<LazyIdleThread> mConnectionThread;
 
-  // Only touched on mStorageThread!
+  // Only touched on mStorageThread! These must be destroyed in the
+  // FireCloseConnectionRunnable method.
   nsCOMPtr<mozIStorageConnection> mConnection;
   nsCOMPtr<mozIStorageStatement> mPutStmt;
   nsCOMPtr<mozIStorageStatement> mPutAutoIncrementStmt;
   nsCOMPtr<mozIStorageStatement> mPutOverwriteStmt;
   nsCOMPtr<mozIStorageStatement> mPutOverwriteAutoIncrementStmt;
 };
 
 END_INDEXEDDB_NAMESPACE