diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index 1d594dce9b2b..e7c4acfa226b 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -75,6 +75,7 @@ #include "mozilla/Util.h" // for DebugOnly #include "mozilla/Services.h" #include "mozilla/Telemetry.h" +#include "nsITimer.h" #include "mozilla/FunctionTimer.h" @@ -218,6 +219,20 @@ private: NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheProfilePrefObserver, nsIObserver) +class nsSetDiskSmartSizeCallback : public nsITimerCallback +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Notify(nsITimer* aTimer) { + nsCacheService::gService->SetDiskSmartSize(true); + NS_RELEASE(aTimer); + return NS_OK; + } +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsSetDiskSmartSizeCallback, nsITimerCallback) + // Runnable sent to main thread after the cache IO thread calculates available // disk space, so that there is no race in setting mDiskCacheCapacity. class nsSetSmartSizeEvent: public nsRunnable @@ -452,7 +467,7 @@ nsCacheProfilePrefObserver::Observe(nsISupports * subject, return rv; PRInt32 newCapacity = 0; if (smartSizeEnabled) { - nsCacheService::SetDiskSmartSize(); + nsCacheService::SetDiskSmartSize(false); } else { // Smart sizing switched off: use user specified size rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &newCapacity); @@ -1447,8 +1462,19 @@ nsCacheService::CreateDiskDevice() mDiskDevice = nsnull; } - SetDiskSmartSize_Locked(true); + // Disk device is usually created during the startup. Delay smart size + // calculation to avoid possible massive IO caused by eviction of entries + // in case the new smart size is smaller than current cache usage. + nsCOMPtr timer = do_CreateInstance("@mozilla.org/timer;1", &rv); + if (NS_FAILED(rv)) + return rv; + rv = timer->InitWithCallback(new nsSetDiskSmartSizeCallback(), 1000*60*3, + nsITimer::TYPE_ONE_SHOT); + if (NS_FAILED(rv)) + return rv; + + timer.forget(); return rv; } @@ -2646,13 +2672,13 @@ nsCacheService::OnEnterExitPrivateBrowsing() } nsresult -nsCacheService::SetDiskSmartSize() +nsCacheService::SetDiskSmartSize(bool checkPref) { nsCacheServiceAutoLock lock; if (!gService) return NS_ERROR_NOT_AVAILABLE; - return gService->SetDiskSmartSize_Locked(false); + return gService->SetDiskSmartSize_Locked(checkPref); } nsresult diff --git a/netwerk/cache/nsCacheService.h b/netwerk/cache/nsCacheService.h index a50c264479b7..755e88a9f51c 100644 --- a/netwerk/cache/nsCacheService.h +++ b/netwerk/cache/nsCacheService.h @@ -182,7 +182,7 @@ public: static void OnEnterExitPrivateBrowsing(); // Starts smart cache size computation if disk device is available - static nsresult SetDiskSmartSize(); + static nsresult SetDiskSmartSize(bool checkPref); nsresult Init(); void Shutdown(); @@ -196,6 +196,7 @@ private: friend class nsProcessRequestEvent; friend class nsSetSmartSizeEvent; friend class nsBlockOnCacheThreadEvent; + friend class nsSetDiskSmartSizeCallback; /** * Internal Methods diff --git a/netwerk/cache/nsDiskCacheDevice.cpp b/netwerk/cache/nsDiskCacheDevice.cpp index d37044ba1ecd..8fb44eb3906b 100644 --- a/netwerk/cache/nsDiskCacheDevice.cpp +++ b/netwerk/cache/nsDiskCacheDevice.cpp @@ -118,6 +118,22 @@ private: nsDiskCacheBinding *mBinding; }; +class nsEvictDiskCacheEntriesEvent : public nsRunnable { +public: + nsEvictDiskCacheEntriesEvent(nsDiskCacheDevice *device) + : mDevice(device) {} + + NS_IMETHOD Run() + { + nsCacheServiceAutoLock lock; + mDevice->EvictDiskCacheEntries(mDevice->mCacheCapacity); + return NS_OK; + } + +private: + nsDiskCacheDevice *mDevice; +}; + /****************************************************************************** * nsDiskCacheEvictor * @@ -1120,8 +1136,14 @@ nsDiskCacheDevice::SetCapacity(PRUint32 capacity) // Units are KiB's mCacheCapacity = capacity; if (Initialized()) { - // start evicting entries if the new size is smaller! - EvictDiskCacheEntries(mCacheCapacity); + if (NS_IsMainThread()) { + // Do not evict entries on the main thread + nsCacheService::DispatchToCacheIOThread( + new nsEvictDiskCacheEntriesEvent(this)); + } else { + // start evicting entries if the new size is smaller! + EvictDiskCacheEntries(mCacheCapacity); + } } // Let cache map know of the new capacity mCacheMap.NotifyCapacityChange(capacity); diff --git a/netwerk/cache/nsDiskCacheDevice.h b/netwerk/cache/nsDiskCacheDevice.h index 8d544863ab5f..f07adea08599 100644 --- a/netwerk/cache/nsDiskCacheDevice.h +++ b/netwerk/cache/nsDiskCacheDevice.h @@ -107,6 +107,7 @@ public: private: friend class nsDiskCacheDeviceDeactivateEntryEvent; + friend class nsEvictDiskCacheEntriesEvent; /** * Private methods */