Bug 795887 - Close cache on suspend_process_notification observer notifiations. r=michal
authorBrian R. Bondy <netzen@gmail.com>
Fri, 09 Nov 2012 10:34:03 -0500
changeset 112919 ea5c4c1b0edf6101acd445bb7e0e1c9511a237f7
parent 112918 479a7ef74ae040ad13d0d7bcbd8759c7e6ea9c15
child 112920 f19782bd70a0feb3880bc2258e53ffae10e60d00
push id23840
push userryanvm@gmail.com
push dateSat, 10 Nov 2012 12:26:58 +0000
treeherderautoland@ea5c4c1b0edf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs795887
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 795887 - Close cache on suspend_process_notification observer notifiations. r=michal
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -73,18 +73,21 @@ using namespace mozilla;
 
 #define SANITIZE_ON_SHUTDOWN_PREF   "privacy.sanitize.sanitizeOnShutdown"
 #define CLEAR_ON_SHUTDOWN_PREF      "privacy.clearOnShutdown.cache"
 
 static const char * observerList[] = { 
     "profile-before-change",
     "profile-do-change",
     NS_XPCOM_SHUTDOWN_OBSERVER_ID,
-    "last-pb-context-exited"
+    "last-pb-context-exited",
+    "suspend_process_notification",
+    "resume_process_notification"
 };
+
 static const char * prefList[] = { 
     DISK_CACHE_ENABLE_PREF,
     DISK_CACHE_SMART_SIZE_ENABLED_PREF,
     DISK_CACHE_CAPACITY_PREF,
     DISK_CACHE_DIR_PREF,
     DISK_CACHE_MAX_ENTRY_SIZE_PREF,
     DISK_CACHE_USE_OLD_MAX_SMART_SIZE_PREF,
     OFFLINE_CACHE_ENABLE_PREF,
@@ -222,17 +225,17 @@ public:
         : mSmartSize(smartSize) {}
 
     NS_IMETHOD Run() 
     {
         NS_ASSERTION(NS_IsMainThread(), 
                      "Setting smart size data off the main thread");
 
         // Main thread may have already called nsCacheService::Shutdown
-        if (!nsCacheService::gService || !nsCacheService::gService->mObserver)
+        if (!nsCacheService::IsInitialized())
             return NS_ERROR_NOT_AVAILABLE;
 
         // Ensure smart sizing wasn't switched off while event was pending.
         // It is safe to access the observer without the lock since we are
         // on the main thread and the value changes only on the main thread.
         if (!nsCacheService::gService->mObserver->SmartSizeEnabled())
             return NS_OK;
 
@@ -375,29 +378,39 @@ NS_IMETHODIMP
 nsCacheProfilePrefObserver::Observe(nsISupports *     subject,
                                     const char *      topic,
                                     const PRUnichar * data_unicode)
 {
     nsresult rv;
     NS_ConvertUTF16toUTF8 data(data_unicode);
     CACHE_LOG_ALWAYS(("Observe [topic=%s data=%s]\n", topic, data.get()));
 
+    if (!nsCacheService::IsInitialized()) {
+        if (!strcmp("resume_process_notification", topic)) {
+            // A suspended process has a closed cache, so re-open it here.
+            nsCacheService::GlobalInstance()->Init();
+        }
+        return NS_OK;
+    }
+
     if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) {
         // xpcom going away, shutdown cache service
-        if (nsCacheService::GlobalInstance())
-            nsCacheService::GlobalInstance()->Shutdown();
-    
+        nsCacheService::GlobalInstance()->Shutdown();
     } else if (!strcmp("profile-before-change", topic)) {
         // profile before change
         mHaveProfile = false;
 
         // XXX shutdown devices
         nsCacheService::OnProfileShutdown(!strcmp("shutdown-cleanse",
                                                   data.get()));
         
+    } else if (!strcmp("suspend_process_notification", topic)) {
+        // A suspended process may never return, so shutdown the cache to reduce
+        // cache corruption.
+        nsCacheService::GlobalInstance()->Shutdown();
     } else if (!strcmp("profile-do-change", topic)) {
         // profile after change
         mHaveProfile = true;
         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
         ReadPrefs(branch);
         nsCacheService::OnProfileChanged();
     
     } else if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, topic)) {
@@ -1075,17 +1088,18 @@ NS_THREADSAFE_MEMORY_REPORTER_IMPLEMENT(
     KIND_HEAP,
     UNITS_BYTES,
     nsCacheService::DiskDeviceHeapSize,
     "Memory used by the network disk cache.")
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheService, nsICacheService)
 
 nsCacheService::nsCacheService()
-    : mLock("nsCacheService.mLock"),
+    : mObserver(nullptr),
+      mLock("nsCacheService.mLock"),
       mCondVar(mLock, "nsCacheService.mCondVar"),
       mInitialized(false),
       mClearingEntries(false),
       mEnableMemoryDevice(true),
       mEnableDiskDevice(true),
       mMemoryDevice(nullptr),
       mDiskDevice(nullptr),
       mOfflineDevice(nullptr),
@@ -1106,16 +1120,21 @@ nsCacheService::nsCacheService()
     mCustomOfflineDevices.Init();
 }
 
 nsCacheService::~nsCacheService()
 {
     if (mInitialized) // Shutdown hasn't been called yet.
         (void) Shutdown();
 
+    if (mObserver) {
+        mObserver->Remove();
+        NS_RELEASE(mObserver);
+    }
+
     gService = nullptr;
 }
 
 
 nsresult
 nsCacheService::Init()
 {
     // Thie method must be called on the main thread because mCacheIOThread must
@@ -1146,21 +1165,22 @@ nsCacheService::Init()
         NS_WARNING("Can't initialize nsDeleteDir");
     }
 
     // initialize hashtable for active cache entries
     rv = mActiveEntries.Init();
     if (NS_FAILED(rv)) return rv;
     
     // create profile/preference observer
-    mObserver = new nsCacheProfilePrefObserver();
-    if (!mObserver)  return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(mObserver);
-    
-    mObserver->Install();
+    if (!mObserver) {
+      mObserver = new nsCacheProfilePrefObserver();
+      NS_ADDREF(mObserver);
+      mObserver->Install();
+    }
+
     mEnableDiskDevice    = mObserver->DiskCacheEnabled();
     mEnableOfflineDevice = mObserver->OfflineCacheEnabled();
     mEnableMemoryDevice  = mObserver->MemoryCacheEnabled();
 
     mInitialized = true;
     return NS_OK;
 }
 
@@ -1209,18 +1229,16 @@ nsCacheService::Shutdown()
 
         // Make sure to wait for any pending cache-operations before
         // proceeding with destructive actions (bug #620660)
         (void) SyncWithCacheIOThread();
 
         // obtain the disk cache directory in case we need to sanitize it
         parentDir = mObserver->DiskCacheParentDirectory();
         shouldSanitize = mObserver->SanitizeAtShutdown();
-        mObserver->Remove();
-        NS_RELEASE(mObserver);
         
         // unregister memory reporters, before deleting the devices, just
         // to be safe
         NS_UnregisterMemoryReporter(MemoryCacheReporter);
         MemoryCacheReporter = nullptr;
 
         NS_UnregisterMemoryReporter(DiskCacheReporter);
         DiskCacheReporter = nullptr;
@@ -1588,17 +1606,17 @@ nsCacheService::CreateDiskDevice()
 class nsDisableOldMaxSmartSizePrefEvent: public nsRunnable
 {
 public:
     nsDisableOldMaxSmartSizePrefEvent() {}
 
     NS_IMETHOD Run()
     {
         // Main thread may have already called nsCacheService::Shutdown
-        if (!nsCacheService::gService || !nsCacheService::gService->mObserver)
+        if (!nsCacheService::IsInitialized())
             return NS_ERROR_NOT_AVAILABLE;
 
         nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
         if (!branch) {
             return NS_ERROR_NOT_AVAILABLE;
         }
 
         nsresult rv = branch->SetBoolPref(DISK_CACHE_USE_OLD_MAX_SMART_SIZE_PREF, false);
@@ -1670,17 +1688,19 @@ nsCacheService::GetCustomOfflineDevice(n
 }
 
 nsresult
 nsCacheService::CreateOfflineDevice()
 {
     CACHE_LOG_ALWAYS(("Creating default offline device"));
 
     if (mOfflineDevice)        return NS_OK;
-    if (!mObserver)            return NS_ERROR_NOT_AVAILABLE;
+    if (!nsCacheService::IsInitialized()) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
 
     nsresult rv = CreateCustomOfflineDevice(
         mObserver->OfflineCacheParentDirectory(),
         mObserver->OfflineCacheCapacity(),
         &mOfflineDevice);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
@@ -2425,18 +2445,17 @@ nsCacheService::SetDiskCacheCapacity(int
 {
     if (!gService)  return;
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_SETDISKCACHECAPACITY));
 
     if (gService->mDiskDevice) {
         gService->mDiskDevice->SetCapacity(capacity);
     }
 
-    if (gService->mObserver)
-        gService->mEnableDiskDevice = gService->mObserver->DiskCacheEnabled();
+    gService->mEnableDiskDevice = gService->mObserver->DiskCacheEnabled();
 }
 
 void
 nsCacheService::SetDiskCacheMaxEntrySize(int32_t  maxSize)
 {
     if (!gService)  return;
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_SETDISKCACHEMAXENTRYSIZE));
 
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -197,16 +197,24 @@ public:
     static void      SetCacheCompressionLevel(int32_t level);
 
     // Starts smart cache size computation if disk device is available
     static nsresult  SetDiskSmartSize();
 
     nsresult         Init();
     void             Shutdown();
 
+    static bool      IsInitialized()
+    {
+      if (!gService) {
+          return false;
+      }
+      return gService->mInitialized;
+    }
+
     static void      AssertOwnsLock()
     { gService->mLock.AssertCurrentThreadOwns(); }
 
     static void      LeavePrivateBrowsing();
     bool             IsDoomListEmpty();
 
     typedef bool (*DoomCheckFn)(nsCacheEntry* entry);