Bug 702217 - Fall back to SQLite when we fail PrefixSet construction. r=dcamp a=akeybl
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Wed, 18 Jan 2012 14:08:46 +0100
changeset 84947 1370ecdf1fe5b195209828496a684ce46d22892e
parent 84946 5ec1ce401db86f2cf0d13a3b9ab770885a8543f4
child 84948 3431949414a6e2e65764ba1ba308d31fa827e690
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdcamp, akeybl
bugs702217
milestone11.0a2
Bug 702217 - Fall back to SQLite when we fail PrefixSet construction. r=dcamp a=akeybl
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -1096,16 +1096,22 @@ public:
   // Queue a lookup for the worker to perform, called in the main thread.
   nsresult QueueLookup(const nsACString& lookupKey,
                        nsIUrlClassifierLookupCallback* callback);
 
   // Handle any queued-up lookups.  We call this function during long-running
   // update operations to prevent lookups from blocking for too long.
   nsresult HandlePendingLookups();
 
+  // Blocks the PrefixSet from being updated while the main thread is doing
+  // its lookups. LockPrefixSet will return whether the PrefixSet is in a
+  // usable state. If not, we should fall through to SQLite lookups.
+  bool LockPrefixSet();
+  void UnlockPrefixSet();
+
 private:
   // No subclassing
   ~nsUrlClassifierDBServiceWorker();
 
   // Disallow copy constructor
   nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&);
 
   // Try to open the db, DATABASE_FILENAME.
@@ -1318,16 +1324,19 @@ private:
   PRIntervalTime mUpdateStartTime;
 
   nsCOMPtr<nsICryptoHMAC> mHMAC;
   // The number of noise entries to add to the set of lookup results.
   PRInt32 mGethashNoise;
 
   // Set of prefixes known to be in the database
   nsRefPtr<nsUrlClassifierPrefixSet> mPrefixSet;
+  // Can we use the PrefixSet (low memory conditions)
+  bool mPrefixSetEnabled;
+  Mutex mPrefixSetEnabledLock;
 
   // Pending lookups are stored in a queue for processing.  The queue
   // is protected by mPendingLookupLock.
   Mutex mPendingLookupLock;
 
   class PendingLookup {
   public:
     nsCString mKey;
@@ -1357,16 +1366,18 @@ nsUrlClassifierDBServiceWorker::nsUrlCla
   , mPrimaryStream(false)
   , mHaveCachedLists(false)
   , mCachedListsTable(PR_UINT32_MAX)
   , mHaveCachedAddChunks(false)
   , mHaveCachedSubChunks(false)
   , mUpdateStartTime(0)
   , mGethashNoise(0)
   , mPrefixSet(0)
+  , mPrefixSetEnabled(true)
+  , mPrefixSetEnabledLock("mPrefixSetEnabledLock")
   , mPendingLookupLock("nsUrlClassifierDBServerWorker.mPendingLookupLock")
 {
 }
 
 nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker()
 {
   NS_ASSERTION(!mConnection,
                "Db connection not closed, leaking memory!  Call CloseDb "
@@ -1426,24 +1437,39 @@ nsUrlClassifierDBServiceWorker::QueueLoo
 }
 
 nsresult
 nsUrlClassifierDBService::CheckClean(const nsACString &spec,
                                      bool *clean)
 {
   Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_LOOKUP_TIME> timer;
 
+  // Is the PrefixSet usable?
+  bool usePrefixSet = mWorker->LockPrefixSet();
+
+  // No, bail out and pretend the URL is not clean. We will do
+  // a database lookup and get the correct result.
+  if (!usePrefixSet) {
+    mWorker->UnlockPrefixSet();
+    *clean = false;
+    return NS_OK;
+  }
+
   // Get the set of fragments to look up.
   nsTArray<nsCString> fragments;
   nsresult rv = GetLookupFragments(spec, fragments);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    goto error_checkclean;
+  }
 
   PRUint32 prefixkey;
   rv = mPrefixSet->GetKey(&prefixkey);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    goto error_checkclean;
+  }
 
   *clean = true;
 
   for (PRUint32 i = 0; i < fragments.Length(); i++) {
     nsUrlClassifierDomainHash fragmentKeyHash;
     fragmentKeyHash.FromPlaintext(fragments[i], mHash);
 
     // Find the corresponding host key
@@ -1454,30 +1480,39 @@ nsUrlClassifierDBService::CheckClean(con
          can't check these against the DB */
       continue;
     }
 
     PRUint32 hostprefix = hostkey.ToUint32();
     PRUint32 fragkey = fragmentKeyHash.ToUint32();
     PRUint32 codedkey;
     rv = KeyedHash(fragkey, hostprefix, prefixkey, &codedkey);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      goto error_checkclean;
+    }
 
     bool found = false;
     bool ready = false;  /* opportunistic probe */
     rv = mPrefixSet->Probe(codedkey, prefixkey, &ready, &found);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) {
+      goto error_checkclean;
+    }
     LOG(("CheckClean Probed %X ready: %d found: %d ",
          codedkey, ready, found));
     if (found || !ready) {
       *clean = false;
     }
   }
 
+  mWorker->UnlockPrefixSet();
   return NS_OK;
+
+ error_checkclean:
+  mWorker->UnlockPrefixSet();
+  return rv;
 }
 
 static nsresult GetHostKeys(const nsACString &spec,
                             nsTArray<nsCString> &hostKeys)
 {
   nsACString::const_iterator begin, end, iter;
   spec.BeginReading(begin);
   spec.EndReading(end);
@@ -3629,16 +3664,27 @@ nsresult nsUrlClassifierStore::ReadPrefi
     LOG(("Gathering took %dms\n",
          PR_IntervalToMilliseconds(clockEnd - clockStart)));
   }
 #endif
 
   return NS_OK;
 }
 
+bool nsUrlClassifierDBServiceWorker::LockPrefixSet()
+{
+  mPrefixSetEnabledLock.Lock();
+  return mPrefixSetEnabled;
+}
+
+void nsUrlClassifierDBServiceWorker::UnlockPrefixSet()
+{
+  mPrefixSetEnabledLock.Unlock();
+}
+
 nsresult
 nsUrlClassifierDBServiceWorker::ConstructPrefixSet()
 {
   Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_CONSTRUCT_TIME> timer;
 
   PRUint32 key;
   nsresult rv = mPrefixSet->GetKey(&key);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -3674,20 +3720,26 @@ nsUrlClassifierDBServiceWorker::Construc
   if (NS_FAILED(rv)) {
     goto error_bailout;
   }
 
   // store the new tree to disk
   rv = mPrefixSet->StoreToFile(mPSFile);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store the prefixset");
 
+  // re-enable prefixset usage if disabled earlier
+  mPrefixSetEnabled = true;
+
   return NS_OK;
 
  error_bailout:
-  // load an empty prefixset so the browser can work
+  // disable prefixset usage
+  MutexAutoLock lock(mPrefixSetEnabledLock);
+  mPrefixSetEnabled = false;
+  // load an empty prefixset
   nsAutoTArray<PRUint32, 1> sentinel;
   sentinel.Clear();
   sentinel.AppendElement(0);
   mPrefixSet->SetPrefixes(sentinel.Elements(), sentinel.Length());
   if (rv == NS_ERROR_OUT_OF_MEMORY) {
     Telemetry::Accumulate(Telemetry::URLCLASSIFIER_PS_OOM, 1);
   }
   return rv;