Bug 920573 - HTTP cache v2: Remove all cache files during shutdown when "Clear history when Firefox closes" + "Cache" setting is checked, r=honzab
authorMichal Novotny <michal.novotny@gmail.com>
Wed, 09 Apr 2014 10:06:59 +0200
changeset 177810 70f74c983cdf
parent 177809 7fa9564a2486
child 177811 ddea7fdd09bf
push id26566
push useremorley@mozilla.com
push date2014-04-10 16:55 +0000
treeherdermozilla-central@83ae54e18689 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershonzab
bugs920573
milestone31.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 920573 - HTTP cache v2: Remove all cache files during shutdown when "Clear history when Firefox closes" + "Cache" setting is checked, r=honzab
netwerk/cache2/CacheFileIOManager.cpp
netwerk/cache2/CacheFileIOManager.h
netwerk/cache2/CacheIndex.cpp
netwerk/cache2/CacheObserver.cpp
netwerk/cache2/CacheObserver.h
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -1208,16 +1208,20 @@ CacheFileIOManager::Shutdown()
   MOZ_ASSERT(gInstance->mHandlesByLastUsed.Length() == 0);
 
   if (gInstance->mIOThread) {
     gInstance->mIOThread->Shutdown();
   }
 
   CacheIndex::Shutdown();
 
+  if (CacheObserver::ClearCacheOnShutdown()) {
+    gInstance->SyncRemoveAllCacheFiles();
+  }
+
   nsRefPtr<CacheFileIOManager> ioMan;
   ioMan.swap(gInstance);
 
   return NS_OK;
 }
 
 nsresult
 CacheFileIOManager::ShutdownInternal()
@@ -2849,17 +2853,19 @@ CacheFileIOManager::RemoveTrashInternal(
 
 nsresult
 CacheFileIOManager::FindTrashDirToRemove()
 {
   LOG(("CacheFileIOManager::FindTrashDirToRemove()"));
 
   nsresult rv;
 
-  MOZ_ASSERT(mIOThread->IsCurrentThread());
+  // We call this method on the main thread during shutdown when user wants to
+  // remove all cache files.
+  MOZ_ASSERT(mIOThread->IsCurrentThread() || mShuttingDown);
 
   nsCOMPtr<nsISimpleEnumerator> iter;
   rv = mCacheDirectory->GetDirectoryEntries(getter_AddRefs(iter));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool more;
   nsCOMPtr<nsISupports> elem;
 
@@ -3276,16 +3282,91 @@ CacheFileIOManager::NSPRHandleUsed(Cache
 
   DebugOnly<bool> found;
   found = mHandlesByLastUsed.RemoveElement(aHandle);
   MOZ_ASSERT(found);
 
   mHandlesByLastUsed.AppendElement(aHandle);
 }
 
+nsresult
+CacheFileIOManager::SyncRemoveDir(nsIFile *aFile, const char *aDir)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> file;
+
+  if (!aDir) {
+    file = aFile;
+  } else {
+    rv = aFile->Clone(getter_AddRefs(file));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = file->AppendNative(nsDependentCString(aDir));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+#ifdef PR_LOGGING
+  nsAutoCString path;
+  file->GetNativePath(path);
+#endif
+
+  LOG(("CacheFileIOManager::SyncRemoveDir() - Removing directory %s",
+       path.get()));
+
+  rv = file->Remove(true);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    LOG(("CacheFileIOManager::SyncRemoveDir() - Removing failed! [rv=0x%08x]",
+         rv));
+  }
+
+  return rv;
+}
+
+void
+CacheFileIOManager::SyncRemoveAllCacheFiles()
+{
+  LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles()"));
+
+  nsresult rv;
+
+  SyncRemoveDir(mCacheDirectory, kEntriesDir);
+  SyncRemoveDir(mCacheDirectory, kDoomedDir);
+
+  // Clear any intermediate state of trash dir enumeration.
+  mFailedTrashDirs.Clear();
+  mTrashDir = nullptr;
+
+  while (true) {
+    // FindTrashDirToRemove() fills mTrashDir if there is any trash directory.
+    rv = FindTrashDirToRemove();
+    if (rv == NS_ERROR_NOT_AVAILABLE) {
+      LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles() - No trash directory "
+           "found."));
+      break;
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles() - "
+           "FindTrashDirToRemove() returned an unexpected error. [rv=0x%08x]",
+           rv));
+      break;
+    }
+
+    rv = SyncRemoveDir(mTrashDir, nullptr);
+    if (NS_FAILED(rv)) {
+      nsAutoCString leafName;
+      mTrashDir->GetNativeLeafName(leafName);
+      mFailedTrashDirs.AppendElement(leafName);
+    }
+  }
+}
+
 // Memory reporting
 
 namespace { // anon
 
 // A helper class that dispatches and waits for an event that gets result of
 // CacheFileIOManager->mHandles.SizeOfExcludingThis() on the I/O thread
 // to safely get handles memory report.
 // We must do this, since the handle list is only accessed and managed w/o
--- a/netwerk/cache2/CacheFileIOManager.h
+++ b/netwerk/cache2/CacheFileIOManager.h
@@ -337,16 +337,20 @@ private:
   nsresult GetDoomedFile(nsIFile **_retval);
   nsresult IsEmptyDirectory(nsIFile *aFile, bool *_retval);
   nsresult CheckAndCreateDir(nsIFile *aFile, const char *aDir,
                              bool aEnsureEmptyDir);
   nsresult CreateCacheTree();
   nsresult OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate = false);
   void     NSPRHandleUsed(CacheFileHandle *aHandle);
 
+  // Removing all cache files during shutdown
+  nsresult SyncRemoveDir(nsIFile *aFile, const char *aDir);
+  void     SyncRemoveAllCacheFiles();
+
   nsresult ScheduleMetadataWriteInternal(CacheFile * aFile);
   nsresult UnscheduleMetadataWriteInternal(CacheFile * aFile);
   nsresult ShutdownMetadataWriteSchedulingInternal();
 
   // Memory reporting (private part)
   size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
 
   static CacheFileIOManager           *gInstance;
--- a/netwerk/cache2/CacheIndex.cpp
+++ b/netwerk/cache2/CacheIndex.cpp
@@ -485,19 +485,21 @@ CacheIndex::Shutdown()
   index.swap(gInstance);
 
   if (!index) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   CacheIndexAutoLock lock(index);
 
+  bool sanitize = CacheObserver::ClearCacheOnShutdown();
+
   LOG(("CacheIndex::Shutdown() - [state=%d, indexOnDiskIsValid=%d, "
-       "dontMarkIndexClean=%d]", index->mState, index->mIndexOnDiskIsValid,
-       index->mDontMarkIndexClean));
+       "dontMarkIndexClean=%d, sanitize=%d]", index->mState,
+       index->mIndexOnDiskIsValid, index->mDontMarkIndexClean, sanitize));
 
   MOZ_ASSERT(index->mShuttingDown);
 
   EState oldState = index->mState;
   index->ChangeState(SHUTDOWN);
 
   if (oldState != READY) {
     LOG(("CacheIndex::Shutdown() - Unexpected state. Did posting of "
@@ -505,17 +507,17 @@ CacheIndex::Shutdown()
   }
 
   switch (oldState) {
     case WRITING:
       index->FinishWrite(false);
       // no break
     case READY:
       if (index->mIndexOnDiskIsValid && !index->mDontMarkIndexClean) {
-        if (NS_FAILED(index->WriteLogToDisk())) {
+        if (!sanitize && NS_FAILED(index->WriteLogToDisk())) {
           index->RemoveIndexFromDisk();
         }
       } else {
         index->RemoveIndexFromDisk();
       }
       break;
     case READING:
       index->FinishRead(false);
@@ -523,16 +525,20 @@ CacheIndex::Shutdown()
     case BUILDING:
     case UPDATING:
       index->FinishUpdate(false);
       break;
     default:
       MOZ_ASSERT(false, "Unexpected state!");
   }
 
+  if (sanitize) {
+    index->RemoveIndexFromDisk();
+  }
+
   return NS_OK;
 }
 
 // static
 nsresult
 CacheIndex::AddEntry(const SHA1Sum::Hash *aHash)
 {
   LOG(("CacheIndex::AddEntry() [hash=%08x%08x%08x%08x%08x]", LOGSHA1(aHash)));
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -57,16 +57,22 @@ static uint32_t const kDefaultMaxMemoryE
 uint32_t CacheObserver::sMaxMemoryEntrySize = kDefaultMaxMemoryEntrySize;
 
 static uint32_t const kDefaultMaxDiskEntrySize = 50 * 1024; // 50 MB
 uint32_t CacheObserver::sMaxDiskEntrySize = kDefaultMaxDiskEntrySize;
 
 static uint32_t const kDefaultCompressionLevel = 1;
 uint32_t CacheObserver::sCompressionLevel = kDefaultCompressionLevel;
 
+static bool kDefaultSanitizeOnShutdown = false;
+bool CacheObserver::sSanitizeOnShutdown = kDefaultSanitizeOnShutdown;
+
+static bool kDefaultClearCacheOnShutdown = false;
+bool CacheObserver::sClearCacheOnShutdown = kDefaultClearCacheOnShutdown;
+
 NS_IMPL_ISUPPORTS2(CacheObserver,
                    nsIObserver,
                    nsISupportsWeakReference)
 
 // static
 nsresult
 CacheObserver::Init()
 {
@@ -183,16 +189,21 @@ CacheObserver::AttachToPreferences()
 
   case -1:
   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;
   }
+
+  mozilla::Preferences::AddBoolVarCache(
+    &sSanitizeOnShutdown, "privacy.sanitize.sanitizeOnShutdown", kDefaultSanitizeOnShutdown);
+  mozilla::Preferences::AddBoolVarCache(
+    &sClearCacheOnShutdown, "privacy.clearOnShutdown.cache", kDefaultClearCacheOnShutdown);
 }
 
 // static
 uint32_t const CacheObserver::MemoryCacheCapacity()
 {
   if (sMemoryCacheCapacity >= 0)
     return sMemoryCacheCapacity << 10;
 
--- a/netwerk/cache2/CacheObserver.h
+++ b/netwerk/cache2/CacheObserver.h
@@ -42,16 +42,18 @@ class CacheObserver : public nsIObserver
   static uint32_t const MaxDiskEntrySize() // result in bytes.
     { return sMaxDiskEntrySize << 10; }
   static uint32_t const CompressionLevel()
     { return sCompressionLevel; }
   static uint32_t const HalfLifeSeconds()
     { return sHalfLifeHours * 60 * 60; }
   static int32_t const HalfLifeExperiment()
     { return sHalfLifeExperiment; }
+  static bool const ClearCacheOnShutdown()
+    { return sSanitizeOnShutdown && sClearCacheOnShutdown; }
   static void ParentDirOverride(nsIFile ** aDir);
 
   static bool const EntryIsTooBig(int64_t aSize, bool aUsingDisk);
 
 private:
   static CacheObserver* sSelf;
 
   void AttachToPreferences();
@@ -64,16 +66,18 @@ private:
   static int32_t sMemoryCacheCapacity;
   static int32_t sAutoMemoryCacheCapacity;
   static uint32_t sDiskCacheCapacity;
   static uint32_t sMaxMemoryEntrySize;
   static uint32_t sMaxDiskEntrySize;
   static uint32_t sCompressionLevel;
   static uint32_t sHalfLifeHours;
   static int32_t sHalfLifeExperiment;
+  static bool sSanitizeOnShutdown;
+  static bool sClearCacheOnShutdown;
 
   // Non static properties, accessible via sSelf
   nsCOMPtr<nsIFile> mCacheParentDirectoryOverride;
 };
 
 } // net
 } // mozilla