Bug 964898 - Auto delete unused cache version data on demand, r=jduell
authorHonza Bambas <honzab.moz@firemni.cz>
Wed, 05 Feb 2014 20:29:54 +0100
changeset 173254 955e0211df1091f81a4f2f74a99eb10d8964ebec
parent 173249 bef65fd678a49ba94119bb19c74427a53974a042
child 173255 4706d1967ebc7299653bdbd09fb66c2bc5a12793
push idunknown
push userunknown
push dateunknown
reviewersjduell
bugs964898
milestone30.0a1
Bug 964898 - Auto delete unused cache version data on demand, r=jduell
netwerk/cache/moz.build
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
netwerk/cache2/CacheFileIOManager.cpp
netwerk/cache2/CacheFileIOManager.h
netwerk/cache2/CacheObserver.cpp
netwerk/cache2/CacheObserver.h
netwerk/cache2/CacheStorageService.cpp
netwerk/cache2/CacheStorageService.h
netwerk/cache2/moz.build
--- a/netwerk/cache/moz.build
+++ b/netwerk/cache/moz.build
@@ -13,16 +13,17 @@ XPIDL_SOURCES += [
     'nsICacheVisitor.idl',
 ]
 
 XPIDL_MODULE = 'necko_cache'
 
 EXPORTS += [
     'nsApplicationCacheService.h',
     'nsCacheService.h',
+    'nsDeleteDir.h'
 ]
 
 # These files cannot be built in unified mode because they force NSPR logging.
 SOURCES += [
     'nsApplicationCacheService.cpp',
     'nsCache.cpp',
     'nsCacheEntry.cpp',
     'nsCacheEntryDescriptor.cpp',
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -3048,16 +3048,33 @@ nsCacheService::CloseAllStreams()
 
 bool
 nsCacheService::GetClearingEntries()
 {
     AssertOwnsLock();
     return gService->mClearingEntries;
 }
 
+// static
+void nsCacheService::GetDiskCacheDirectory(nsIFile ** result) {
+    *result = nullptr;
+    if (gService && gService->mObserver) {
+        nsCOMPtr<nsIFile> directory =
+            gService->mObserver->DiskCacheParentDirectory();
+        if (!directory)
+            return;
+
+        nsresult rv = directory->AppendNative(NS_LITERAL_CSTRING("Cache"));
+        if (NS_FAILED(rv))
+            return;
+
+        directory.forget(result);
+    }
+}
+
 
 #if defined(PR_LOGGING)
 void
 nsCacheService::LogCacheStatistics()
 {
     uint32_t hitPercentage = (uint32_t)((((double)mCacheHits) /
         ((double)(mCacheHits + mCacheMisses))) * 100);
     CACHE_LOG_ALWAYS(("\nCache Service Statistics:\n\n"));
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -122,16 +122,18 @@ public:
     static nsresult  SetCacheElement(nsCacheEntry * entry, nsISupports * element);
 
     static nsresult  ValidateEntry(nsCacheEntry * entry);
 
     static int32_t   CacheCompressionLevel();
 
     static bool      GetClearingEntries();
 
+    static void      GetDiskCacheDirectory(nsIFile ** result);
+
     /**
      * Methods called by any cache classes
      */
 
     static
     nsCacheService * GlobalInstance()   { return gService; }
 
     static nsresult  DoomEntry(nsCacheEntry * entry);
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -1606,16 +1606,29 @@ CacheFileIOManager::EnumerateEntryFiles(
 
   rv = enumerator->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aEnumerator = enumerator.forget();
   return NS_OK;
 }
 
+// static
+void CacheFileIOManager::GetCacheDirectory(nsIFile** result)
+{
+  *result = nullptr;
+
+  nsRefPtr<CacheFileIOManager> ioMan = gInstance;
+  if (!ioMan)
+    return;
+
+  nsCOMPtr<nsIFile> file = ioMan->mCacheDirectory;
+  file.forget(result);
+}
+
 static nsresult
 TruncFile(PRFileDesc *aFD, uint32_t aEOF)
 {
 #if defined(XP_UNIX)
   if (ftruncate(PR_FileDesc2NativeHandle(aFD), aEOF) != 0) {
     NS_ERROR("ftruncate failed");
     return NS_ERROR_FAILURE;
   }
--- a/netwerk/cache2/CacheFileIOManager.h
+++ b/netwerk/cache2/CacheFileIOManager.h
@@ -219,16 +219,18 @@ public:
   enum EEnumerateMode {
     ENTRIES,
     DOOMED
   };
 
   static nsresult EnumerateEntryFiles(EEnumerateMode aMode,
                                       CacheEntriesEnumerator** aEnumerator);
 
+  static void GetCacheDirectory(nsIFile** result);
+
 private:
   friend class CacheFileHandle;
   friend class CacheFileChunk;
   friend class CacheFile;
   friend class ShutdownEvent;
   friend class OpenFileEvent;
   friend class CloseHandleEvent;
   friend class ReadEvent;
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -20,16 +20,18 @@ namespace net {
 
 CacheObserver* CacheObserver::sSelf = nullptr;
 
 static uint32_t const kDefaultMemoryLimit = 50 * 1024; // 50 MB
 uint32_t CacheObserver::sMemoryLimit = kDefaultMemoryLimit;
 
 static uint32_t const kDefaultUseNewCache = 0; // Don't use the new cache by default
 uint32_t CacheObserver::sUseNewCache = kDefaultUseNewCache;
+static int32_t const kAutoDeleteCacheVersion = -1; // Auto-delete off by default
+static int32_t sAutoDeleteCacheVersion = kAutoDeleteCacheVersion;
 
 static int32_t const kDefaultHalfLifeExperiment = -1; // Disabled
 int32_t CacheObserver::sHalfLifeExperiment = kDefaultHalfLifeExperiment;
 
 static uint32_t const kDefaultHalfLifeHours = 6; // 6 hours
 uint32_t CacheObserver::sHalfLifeHours = kDefaultHalfLifeHours;
 
 static bool const kDefaultUseDiskCache = true;
@@ -66,16 +68,17 @@ CacheObserver::Init()
     return NS_ERROR_UNEXPECTED;
   }
 
   sSelf = new CacheObserver();
   NS_ADDREF(sSelf);
 
   obs->AddObserver(sSelf, "prefservice:after-app-defaults", true);
   obs->AddObserver(sSelf, "profile-do-change", true);
+  obs->AddObserver(sSelf, "sessionstore-windows-restored", true);
   obs->AddObserver(sSelf, "profile-before-change", true);
   obs->AddObserver(sSelf, "xpcom-shutdown", true);
   obs->AddObserver(sSelf, "last-pb-context-exited", true);
   obs->AddObserver(sSelf, "webapps-clear-data", true);
   obs->AddObserver(sSelf, "memory-pressure", true);
 
   return NS_OK;
 }
@@ -89,16 +92,19 @@ CacheObserver::Shutdown()
 
   NS_RELEASE(sSelf);
   return NS_OK;
 }
 
 void
 CacheObserver::AttachToPreferences()
 {
+  sAutoDeleteCacheVersion = mozilla::Preferences::GetInt(
+    "browser.cache.auto_delete_cache_version", kAutoDeleteCacheVersion);
+
   mozilla::Preferences::AddUintVarCache(
     &sUseNewCache, "browser.cache.use_new_backend", kDefaultUseNewCache);
 
   mozilla::Preferences::AddBoolVarCache(
     &sUseDiskCache, "browser.cache.disk.enable", kDefaultUseDiskCache);
   mozilla::Preferences::AddBoolVarCache(
     &sUseMemoryCache, "browser.cache.memory.enable", kDefaultUseMemoryCache);
 
@@ -148,16 +154,31 @@ CacheObserver::AttachToPreferences()
   default: // The experiment is off or broken
     sHalfLifeExperiment = -1;
     sHalfLifeHours = std::max(1U, std::min(1440U, mozilla::Preferences::GetUint(
       "browser.cache.frecency_half_life_hours", kDefaultHalfLifeHours)));
     break;
   }
 }
 
+void CacheObserver::SchduleAutoDelete()
+{
+  // Auto-delete not set
+  if (sAutoDeleteCacheVersion == -1)
+    return;
+
+  // Don't autodelete the same version of the cache user has setup
+  // to use.
+  int32_t activeVersion = UseNewCache() ? 1 : 0;
+  if (sAutoDeleteCacheVersion == activeVersion)
+    return;
+
+  CacheStorageService::WipeCacheDirectory(sAutoDeleteCacheVersion);
+}
+
 // static
 bool const CacheObserver::UseNewCache()
 {
   switch (sUseNewCache) {
     case 0: // use the old cache backend
       return false;
 
     case 1: // use the new cache backend
@@ -279,16 +300,21 @@ CacheObserver::Observe(nsISupports* aSub
 
   if (!strcmp(aTopic, "profile-do-change")) {
     AttachToPreferences();
     CacheFileIOManager::Init();
     CacheFileIOManager::OnProfile();
     return NS_OK;
   }
 
+  if (!strcmp(aTopic, "sessionstore-windows-restored")) {
+    SchduleAutoDelete();
+    return NS_OK;
+  }
+
   if (!strcmp(aTopic, "profile-before-change")) {
     nsRefPtr<CacheStorageService> service = CacheStorageService::Self();
     if (service)
       service->Shutdown();
 
     return NS_OK;
   }
 
@@ -327,13 +353,14 @@ CacheObserver::Observe(nsISupports* aSub
   if (!strcmp(aTopic, "memory-pressure")) {
     nsRefPtr<CacheStorageService> service = CacheStorageService::Self();
     if (service)
       service->PurgeFromMemory(nsICacheStorageService::PURGE_EVERYTHING);
 
     return NS_OK;
   }
 
+  MOZ_ASSERT(false, "Missing observer handler");
   return NS_OK;
 }
 
 } // net
 } // mozilla
--- a/netwerk/cache2/CacheObserver.h
+++ b/netwerk/cache2/CacheObserver.h
@@ -46,16 +46,17 @@ class CacheObserver : public nsIObserver
     { return sHalfLifeExperiment; }
 
   static bool const EntryIsTooBig(int64_t aSize, bool aUsingDisk);
 
 private:
   static CacheObserver* sSelf;
 
   void AttachToPreferences();
+  void SchduleAutoDelete();
 
   static uint32_t sUseNewCache;
   static bool sUseDiskCache;
   static bool sUseMemoryCache;
   static uint32_t sMemoryLimit;
   static uint32_t sDiskCacheCapacity;
   static uint32_t sMaxMemoryEntrySize;
   static uint32_t sMaxDiskEntrySize;
--- a/netwerk/cache2/CacheStorageService.cpp
+++ b/netwerk/cache2/CacheStorageService.cpp
@@ -4,22 +4,23 @@
 
 #include "CacheLog.h"
 #include "CacheStorageService.h"
 #include "CacheFileIOManager.h"
 #include "CacheObserver.h"
 
 #include "nsICacheStorageVisitor.h"
 #include "nsIObserverService.h"
-#include "nsICacheService.h" // for old cache preference
 #include "CacheStorage.h"
 #include "AppCacheStorage.h"
 #include "CacheEntry.h"
 
 #include "OldWrappers.h"
+#include "nsCacheService.h"
+#include "nsDeleteDir.h"
 
 #include "nsIFile.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/TimeStamp.h"
@@ -379,16 +380,35 @@ void CacheStorageService::DropPrivateBro
 
   nsTArray<nsCString> keys;
   sGlobalEntryTables->EnumerateRead(&CollectPrivateContexts, &keys);
 
   for (uint32_t i = 0; i < keys.Length(); ++i)
     DoomStorageEntries(keys[i], true, nullptr);
 }
 
+// static
+void CacheStorageService::WipeCacheDirectory(uint32_t aVersion)
+{
+  nsCOMPtr<nsIFile> cacheDir;
+  switch (aVersion) {
+  case 0:
+    nsCacheService::GetDiskCacheDirectory(getter_AddRefs(cacheDir));
+    break;
+  case 1:
+    CacheFileIOManager::GetCacheDirectory(getter_AddRefs(cacheDir));
+    break;
+  }
+
+  if (!cacheDir)
+    return;
+
+  nsDeleteDir::DeleteDir(cacheDir, true, 30000);
+}
+
 // Helper methods
 
 // static
 bool CacheStorageService::IsOnManagementThread()
 {
   nsRefPtr<CacheStorageService> service = Self();
   if (!service)
     return false;
--- a/netwerk/cache2/CacheStorageService.h
+++ b/netwerk/cache2/CacheStorageService.h
@@ -48,16 +48,19 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSICACHESTORAGESERVICE
 
   CacheStorageService();
 
   void Shutdown();
   void DropPrivateBrowsingEntries();
 
+  // Wipes out the new or the old cache directory completely.
+  static void WipeCacheDirectory(uint32_t aVersion);
+
   static CacheStorageService* Self() { return sSelf; }
   nsresult Dispatch(nsIRunnable* aEvent);
   static bool IsRunning() { return sSelf && !sSelf->mShutdown; }
   static bool IsOnManagementThread();
   already_AddRefed<nsIEventTarget> Thread() const;
   mozilla::Mutex& Lock() { return mLock; }
 
 private:
--- a/netwerk/cache2/moz.build
+++ b/netwerk/cache2/moz.build
@@ -42,15 +42,16 @@ SOURCES += [
     'CacheLog.cpp',
     'CacheStorage.cpp',
     'CacheStorageService.cpp',
     'OldWrappers.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '../base/src',
+    '../cache',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 FINAL_LIBRARY = 'necko'