Bug 580790 - Connection::initialize can access preferences off of the main thread
☠☠ backed out by 8d4d8fc43475 ☠ ☠
authorShawn Wilsher <sdwilsh@shawnwilsher.com>
Fri, 06 Aug 2010 10:28:46 -0700
changeset 49052 0b3af3fef0fdfeb5e696c13d773d352e56d94b12
parent 49051 1302220623fd88d5360f9c3c8aabfa0c1e3176eb
child 49053 06acfdb2a93e4822f47808c4596225067c33052e
child 49055 8d4d8fc43475a18933f6d48e2260289d9cff0db9
push idunknown
push userunknown
push dateunknown
bugs580790
milestone2.0b4pre
Bug 580790 - Connection::initialize can access preferences off of the main thread This part fixes the storage service so that it caches the value from the preference service, and obtains the value once on the main thread. r=asuth a=blocking2.0
storage/src/mozStorageConnection.cpp
storage/src/mozStorageService.cpp
storage/src/mozStorageService.h
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -43,18 +43,16 @@
 
 #include <stdio.h>
 
 #include "nsError.h"
 #include "nsIMutableArray.h"
 #include "nsHashSets.h"
 #include "nsAutoPtr.h"
 #include "nsIFile.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
 #include "nsThreadUtils.h"
 #include "nsAutoLock.h"
 
 #include "mozIStorageAggregateFunction.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageFunction.h"
 
 #include "mozStorageAsyncStatementExecution.h"
@@ -74,18 +72,16 @@
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gStorageLog = nsnull;
 #endif
 
 namespace mozilla {
 namespace storage {
 
-#define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
-
 ////////////////////////////////////////////////////////////////////////////////
 //// Variant Specialization Functions (variantToSQLiteT)
 
 static int
 sqlite3_T_int(sqlite3_context *aCtx,
               int aValue)
 {
   ::sqlite3_result_int(aCtx, aValue);
@@ -432,23 +428,18 @@ Connection::initialize(nsIFile *aDatabas
 
   if (srv != SQLITE_OK) {
     ::sqlite3_close(mDBConn);
     mDBConn = nsnull;
 
     return convertResultCode(srv);
   }
 
-  // Set the synchronous PRAGMA, according to the pref
-  nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
-  PRInt32 synchronous = 1; // Default to NORMAL if pref not set
-  if (pref)
-    (void)pref->GetIntPref(PREF_TS_SYNCHRONOUS, &synchronous);
-
-  switch (synchronous) {
+  // Set the synchronous PRAGMA, according to the preference.
+  switch (Service::getSynchronousPref()) {
     case 2:
       (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
           "PRAGMA synchronous = FULL;"));
       break;
     case 0:
       (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
           "PRAGMA synchronous = OFF;"));
       break;
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -37,35 +37,43 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozStorageService.h"
 #include "mozStorageConnection.h"
-#include "prinit.h"
+#include "pratom.h"
 #include "nsAutoPtr.h"
 #include "nsCollationCID.h"
 #include "nsEmbedCID.h"
 #include "nsThreadUtils.h"
 #include "mozStoragePrivateHelpers.h"
 #include "nsILocale.h"
 #include "nsILocaleService.h"
 #include "nsIXPConnect.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
 
 #include "sqlite3.h"
 
 #include "nsIPromptService.h"
 #include "nsIMemoryReporter.h"
 
 #include "mozilla/FunctionTimer.h"
 
+////////////////////////////////////////////////////////////////////////////////
+//// Defines
+
+#define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
+#define PREF_TS_SYNCHRONOUS_DEFAULT 1
+
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Memory Reporting
 
 static PRInt64
 GetStorageSQLitePageCacheMemoryUsed(void *)
@@ -99,19 +107,21 @@ NS_MEMORY_REPORTER_IMPLEMENT(StorageSQLi
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Helpers
 
 class ServiceMainThreadInitializer : public nsRunnable
 {
 public:
   ServiceMainThreadInitializer(nsIObserver *aObserver,
-                               nsIXPConnect **aXPConnectPtr)
+                               nsIXPConnect **aXPConnectPtr,
+                               PRInt32 *aSynchronousPrefValPtr)
   : mObserver(aObserver)
   , mXPConnectPtr(aXPConnectPtr)
+  , mSynchronousPrefValPtr(aSynchronousPrefValPtr)
   {
   }
 
   NS_IMETHOD Run()
   {
     NS_PRECONDITION(NS_IsMainThread(), "Must be running on the main thread!");
 
     // NOTE:  All code that can only run on the main thread and needs to be run
@@ -127,27 +137,37 @@ public:
     NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
     nsresult rv = os->AddObserver(mObserver, "xpcom-shutdown", PR_FALSE);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // We cache XPConnect for our language helpers.  XPConnect can only be
     // used on the main thread.
     (void)CallGetService(nsIXPConnect::GetCID(), mXPConnectPtr);
 
+    // We need to obtain the toolkit.storage.synchronous preferences on the main
+    // thread because the preference service can only be accessed there.  This
+    // is cached in the service for all future Open[Unshared]Database calls.
+    nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
+    PRInt32 synchronous = PREF_TS_SYNCHRONOUS_DEFAULT;
+    if (pref)
+      (void)pref->GetIntPref(PREF_TS_SYNCHRONOUS, &synchronous);
+    ::PR_AtomicSet(mSynchronousPrefValPtr, synchronous);
+
     // Register our SQLite memory reporters.  Registration can only happen on
     // the main thread (otherwise you'll get cryptic crashes).
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(StorageSQLitePageCacheMemoryUsed));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(StorageSQLiteOtherMemoryUsed));
 
     return NS_OK;
   }
 
 private:
   nsIObserver *mObserver;
   nsIXPConnect **mXPConnectPtr;
+  PRInt32 *mSynchronousPrefValPtr;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Service
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(
   Service,
   mozIStorageService,
@@ -187,16 +207,17 @@ Service::getSingleton()
       NS_RELEASE(gService);
   }
 
   return gService;
 }
 
 nsIXPConnect *Service::sXPConnect = nsnull;
 
+// static
 already_AddRefed<nsIXPConnect>
 Service::getXPConnect()
 {
   NS_PRECONDITION(NS_IsMainThread(),
                   "Must only get XPConnect on the main thread!");
   NS_PRECONDITION(gService,
                   "Can not get XPConnect without an instance of our service!");
 
@@ -204,16 +225,25 @@ Service::getXPConnect()
   // not cache the service after this point.
   nsCOMPtr<nsIXPConnect> xpc(sXPConnect);
   if (!xpc)
     xpc = do_GetService(nsIXPConnect::GetCID());
   NS_ASSERTION(xpc, "Could not get XPConnect!");
   return xpc.forget();
 }
 
+PRInt32 Service::sSynchronousPref;
+
+// static
+PRInt32
+Service::getSynchronousPref()
+{
+  return sSynchronousPref;
+}
+
 Service::Service()
 : mMutex("Service::mMutex")
 {
 }
 
 Service::~Service()
 {
   // Shutdown the sqlite3 API.  Warn if shutdown did not turn out okay, but
@@ -252,19 +282,23 @@ Service::initialize()
   // cache.  We do not need to lock here with mMutex because this function is
   // only ever called from Service::GetSingleton, which will only
   // call this function once, and will not return until this function returns.
   // (It does not matter where this is called relative to sqlite3_initialize.)
   rc = ::sqlite3_enable_shared_cache(1);
   if (rc != SQLITE_OK)
     return convertResultCode(rc);
 
+  // Set the default value for the toolkit.storage.synchronous pref.  It will be
+  // updated with the user preference on the main thread.
+  sSynchronousPref = PREF_TS_SYNCHRONOUS_DEFAULT;
+
   // Run the things that need to run on the main thread there.
   nsCOMPtr<nsIRunnable> event =
-    new ServiceMainThreadInitializer(this, &sXPConnect);
+    new ServiceMainThreadInitializer(this, &sXPConnect, &sSynchronousPref);
   if (event && ::NS_IsMainThread()) {
     (void)event->Run();
   }
   else {
     (void)::NS_DispatchToMainThread(event);
   }
 
   return NS_OK;
--- a/storage/src/mozStorageService.h
+++ b/storage/src/mozStorageService.h
@@ -89,16 +89,21 @@ public:
   NS_DECL_NSIOBSERVER
 
   /**
    * Obtains an already AddRefed pointer to XPConnect.  This is used by
    * language helpers.
    */
   static already_AddRefed<nsIXPConnect> getXPConnect();
 
+  /**
+   * Obtains the cached data for the toolkit.storage.synchronous preference.
+   */
+  static PRInt32 getSynchronousPref();
+
 private:
   Service();
   virtual ~Service();
 
   /**
    * Used for 1) locking around calls when initializing connections so that we
    * can ensure that the state of sqlite3_enable_shared_cache is sane and 2)
    * synchronizing access to mLocaleCollation.
@@ -128,14 +133,16 @@ private:
    */
   nsCOMPtr<nsICollation> mLocaleCollation;
 
   nsCOMPtr<nsIFile> mProfileStorageFile;
 
   static Service *gService;
 
   static nsIXPConnect *sXPConnect;
+
+  static PRInt32 sSynchronousPref;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif /* MOZSTORAGESERVICE_H */