Bug 667593 - Intermittent runtime abort in netwerk/test/unit/test_bug650955.js r=michal.novotny
authorbjarne@runitsoft.com
Tue, 06 Sep 2011 12:23:26 -0400
changeset 76604 d8f1caaeb9b1f15dd6d67cbbc58ce84004f21bc3
parent 76603 f921f632208e2a7e9eba943c6dce96a8b6a33b77
child 76605 48ee21dc3854ffbf203228380be0dc1258186d5f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersmichal
bugs667593, 650955
milestone9.0a1
Bug 667593 - Intermittent runtime abort in netwerk/test/unit/test_bug650955.js r=michal.novotny
netwerk/cache/nsDiskCacheDevice.cpp
--- a/netwerk/cache/nsDiskCacheDevice.cpp
+++ b/netwerk/cache/nsDiskCacheDevice.cpp
@@ -81,16 +81,48 @@
 
 #include "mozilla/FunctionTimer.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Telemetry.h"
 
 static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
 using namespace mozilla;
 
+class nsDiskCacheDeviceDeactivateEntryEvent : public nsRunnable {
+public:
+    nsDiskCacheDeviceDeactivateEntryEvent(nsDiskCacheDevice *device,
+                                          nsCacheEntry * entry,
+                                          nsDiskCacheBinding * binding)
+        : mCanceled(PR_FALSE),
+          mEntry(entry),
+          mDevice(device),
+          mBinding(binding)
+    {
+    }
+
+    NS_IMETHOD Run()
+    {
+        nsCacheServiceAutoLock lock;
+#ifdef PR_LOGGING
+        CACHE_LOG_DEBUG(("nsDiskCacheDeviceDeactivateEntryEvent[%p]\n", this));
+#endif
+        if (!mCanceled) {
+            (void) mDevice->DeactivateEntry_Private(mEntry, mBinding);
+        }
+        return NS_OK;
+    }
+
+    void CancelEvent() { mCanceled = PR_TRUE; }
+private:
+    PRBool mCanceled;
+    nsCacheEntry *mEntry;
+    nsDiskCacheDevice *mDevice;
+    nsDiskCacheBinding *mBinding;
+};
+
 /******************************************************************************
  *  nsDiskCacheEvictor
  *
  *  Helper class for nsDiskCacheDevice.
  *
  *****************************************************************************/
 
 class nsDiskCacheEvictor : public nsDiskCacheRecordVisitor
@@ -136,16 +168,22 @@ nsDiskCacheEvictor::VisitRecord(nsDiskCa
             (diskEntry->Key()[mClientIDSize] != ':') ||
             (memcmp(diskEntry->Key(), mClientID, mClientIDSize) != 0)) {
             return kVisitNextRecord;  // clientID doesn't match, skip it
         }
     }
     
     nsDiskCacheBinding * binding = mBindery->FindActiveBinding(mapRecord->HashNumber());
     if (binding) {
+        // If the entry is pending deactivation, cancel deactivation and doom
+        // the entry
+        if (binding->mDeactivateEvent) {
+            binding->mDeactivateEvent->CancelEvent();
+            binding->mDeactivateEvent = nsnull;
+        }
         // We are currently using this entry, so all we can do is doom it.
         // Since we're enumerating the records, we don't want to call
         // DeleteRecord when nsCacheService::DoomEntry() calls us back.
         binding->mDoomed = PR_TRUE;         // mark binding record as 'deleted'
         nsCacheService::DoomEntry(binding->mCacheEntry);
     } else {
         // entry not in use, just delete storage because we're enumerating the records
         (void) mCacheMap->DeleteStorage(mapRecord);
@@ -448,49 +486,16 @@ nsDiskCacheDevice::Shutdown_Private(PRBo
 
 
 const char *
 nsDiskCacheDevice::GetDeviceID()
 {
     return DISK_CACHE_DEVICE_ID;
 }
 
-class nsDiskCacheDeviceDeactivateEntryEvent : public nsRunnable {
-public:
-    nsDiskCacheDeviceDeactivateEntryEvent(nsDiskCacheDevice *device,
-                                          nsCacheEntry * entry,
-                                          nsDiskCacheBinding * binding)
-        : mCanceled(PR_FALSE),
-          mEntry(entry),
-          mDevice(device),
-          mBinding(binding)
-    {
-    }
-
-    NS_IMETHOD Run()
-    {
-        nsCacheServiceAutoLock lock;
-#ifdef PR_LOGGING
-        CACHE_LOG_DEBUG(("nsDiskCacheDeviceDeactivateEntryEvent[%p]\n", this));
-#endif
-        if (!mCanceled) {
-            (void) mDevice->DeactivateEntry_Private(mEntry, mBinding);
-        }
-        return NS_OK;
-    }
-    
-    void CancelEvent() { mCanceled = PR_TRUE; }
-private:
-    PRBool mCanceled;
-    nsCacheEntry *mEntry;
-    nsDiskCacheDevice *mDevice;
-    nsDiskCacheBinding *mBinding;
-};
-
-
 /**
  *  FindEntry -
  *
  *      cases:  key not in disk cache, hash number free
  *              key not in disk cache, hash number used
  *              key in disk cache
  *
  *  NOTE: called while holding the cache service lock
@@ -630,16 +635,21 @@ nsDiskCacheDevice::BindEntry(nsCacheEntr
     // Find out if there is already an active binding for this hash. If yes it
     // should have another key since BindEntry() shouldn't be called twice for
     // the same entry. Doom the old entry, the new one will get another
     // generation number so files won't collide.
     binding = mBindery.FindActiveBinding(hashNumber);
     if (binding) {
         NS_ASSERTION(!binding->mCacheEntry->Key()->Equals(*entry->Key()),
                      "BindEntry called for already bound entry!");
+        // If the entry is pending deactivation, cancel deactivation
+        if (binding->mDeactivateEvent) {
+            binding->mDeactivateEvent->CancelEvent();
+            binding->mDeactivateEvent = nsnull;
+        }
         nsCacheService::DoomEntry(binding->mCacheEntry);
         binding = nsnull;
     }
 
     // Lookup hash number in cache map. There can be a colliding inactive entry.
     // See bug #321361 comment 21 for the scenario. If there is such entry,
     // delete it.
     rv = mCacheMap.FindRecord(hashNumber, &record);
@@ -671,16 +681,21 @@ nsDiskCacheDevice::BindEntry(nsCacheEntr
         PRUint32    oldHashNumber = oldRecord.HashNumber();
         if (oldHashNumber) {
             // gotta evict this one first
             nsDiskCacheBinding * oldBinding = mBindery.FindActiveBinding(oldHashNumber);
             if (oldBinding) {
                 // XXX if debug : compare keys for hashNumber collision
 
                 if (!oldBinding->mCacheEntry->IsDoomed()) {
+                    // If the old entry is pending deactivation, cancel deactivation
+                    if (oldBinding->mDeactivateEvent) {
+                        oldBinding->mDeactivateEvent->CancelEvent();
+                        oldBinding->mDeactivateEvent = nsnull;
+                    }
                 // we've got a live one!
                     nsCacheService::DoomEntry(oldBinding->mCacheEntry);
                     // storage will be delete when oldBinding->mCacheEntry is Deactivated
                 }
             } else {
                 // delete storage
                 // XXX if debug : compare keys for hashNumber collision
                 rv = mCacheMap.DeleteStorage(&oldRecord);