Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / netwerk / cache2 / CacheObserver.cpp
blob59a798d15172a31732ad175946c9fbb2e4283015
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "CacheObserver.h"
7 #include "CacheStorageService.h"
8 #include "CacheFileIOManager.h"
9 #include "LoadContextInfo.h"
10 #include "nsICacheStorage.h"
11 #include "nsIObserverService.h"
12 #include "mozilla/Services.h"
13 #include "mozilla/Preferences.h"
14 #include "mozilla/TimeStamp.h"
15 #include "nsServiceManagerUtils.h"
16 #include "mozilla/net/NeckoCommon.h"
17 #include "prsystem.h"
18 #include <time.h>
19 #include <math.h>
20 #include "nsIUserIdleService.h"
22 namespace mozilla::net {
24 StaticRefPtr<CacheObserver> CacheObserver::sSelf;
26 static float const kDefaultHalfLifeHours = 24.0F; // 24 hours
27 float CacheObserver::sHalfLifeHours = kDefaultHalfLifeHours;
29 // The default value will be overwritten as soon as the correct smart size is
30 // calculated by CacheFileIOManager::UpdateSmartCacheSize(). It's limited to 1GB
31 // just for case the size is never calculated which might in theory happen if
32 // GetDiskSpaceAvailable() always fails.
33 Atomic<uint32_t, Relaxed> CacheObserver::sSmartDiskCacheCapacity(1024 * 1024);
35 Atomic<PRIntervalTime> CacheObserver::sShutdownDemandedTime(
36 PR_INTERVAL_NO_TIMEOUT);
38 NS_IMPL_ISUPPORTS(CacheObserver, nsIObserver, nsISupportsWeakReference)
40 // static
41 nsresult CacheObserver::Init() {
42 if (IsNeckoChild()) {
43 return NS_OK;
46 if (sSelf) {
47 return NS_OK;
50 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
51 if (!obs) {
52 return NS_ERROR_UNEXPECTED;
55 sSelf = new CacheObserver();
57 obs->AddObserver(sSelf, "prefservice:after-app-defaults", true);
58 obs->AddObserver(sSelf, "profile-do-change", true);
59 obs->AddObserver(sSelf, "profile-before-change", true);
60 obs->AddObserver(sSelf, "xpcom-shutdown", true);
61 obs->AddObserver(sSelf, "last-pb-context-exited", true);
62 obs->AddObserver(sSelf, "memory-pressure", true);
63 obs->AddObserver(sSelf, "browser-delayed-startup-finished", true);
64 obs->AddObserver(sSelf, OBSERVER_TOPIC_IDLE_DAILY, true);
66 return NS_OK;
69 // static
70 nsresult CacheObserver::Shutdown() {
71 if (!sSelf) {
72 return NS_ERROR_NOT_INITIALIZED;
75 sSelf = nullptr;
76 return NS_OK;
79 void CacheObserver::AttachToPreferences() {
80 mozilla::Preferences::GetComplex(
81 "browser.cache.disk.parent_directory", NS_GET_IID(nsIFile),
82 getter_AddRefs(mCacheParentDirectoryOverride));
84 sHalfLifeHours = std::max(
85 0.01F, std::min(1440.0F, mozilla::Preferences::GetFloat(
86 "browser.cache.frecency_half_life_hours",
87 kDefaultHalfLifeHours)));
90 // static
91 uint32_t CacheObserver::MemoryCacheCapacity() {
92 if (StaticPrefs::browser_cache_memory_capacity() >= 0) {
93 return StaticPrefs::browser_cache_memory_capacity();
96 // Cache of the calculated memory capacity based on the system memory size in
97 // KB (C++11 guarantees local statics will be initialized once and in a
98 // thread-safe way.)
99 static int32_t sAutoMemoryCacheCapacity = ([] {
100 uint64_t bytes = PR_GetPhysicalMemorySize();
101 // If getting the physical memory failed, arbitrarily assume
102 // 32 MB of RAM. We use a low default to have a reasonable
103 // size on all the devices we support.
104 if (bytes == 0) {
105 bytes = 32 * 1024 * 1024;
107 // Conversion from unsigned int64_t to double doesn't work on all platforms.
108 // We need to truncate the value at INT64_MAX to make sure we don't
109 // overflow.
110 if (bytes > INT64_MAX) {
111 bytes = INT64_MAX;
113 uint64_t kbytes = bytes >> 10;
114 double kBytesD = double(kbytes);
115 double x = log(kBytesD) / log(2.0) - 14;
117 int32_t capacity = 0;
118 if (x > 0) {
119 // 0.1 is added here for rounding
120 capacity = (int32_t)(x * x / 3.0 + x + 2.0 / 3 + 0.1);
121 if (capacity > 32) {
122 capacity = 32;
124 capacity <<= 10;
126 return capacity;
127 })();
129 return sAutoMemoryCacheCapacity;
132 // static
133 void CacheObserver::SetSmartDiskCacheCapacity(uint32_t aCapacity) {
134 sSmartDiskCacheCapacity = aCapacity;
137 // static
138 uint32_t CacheObserver::DiskCacheCapacity() {
139 return SmartCacheSizeEnabled() ? sSmartDiskCacheCapacity
140 : StaticPrefs::browser_cache_disk_capacity();
143 // static
144 void CacheObserver::ParentDirOverride(nsIFile** aDir) {
145 if (NS_WARN_IF(!aDir)) return;
147 *aDir = nullptr;
149 if (!sSelf) return;
150 if (!sSelf->mCacheParentDirectoryOverride) return;
152 sSelf->mCacheParentDirectoryOverride->Clone(aDir);
155 // static
156 bool CacheObserver::EntryIsTooBig(int64_t aSize, bool aUsingDisk) {
157 // If custom limit is set, check it.
158 int64_t preferredLimit =
159 aUsingDisk ? MaxDiskEntrySize() : MaxMemoryEntrySize();
161 // do not convert to bytes when the limit is -1, which means no limit
162 if (preferredLimit > 0) {
163 preferredLimit <<= 10;
166 if (preferredLimit != -1 && aSize > preferredLimit) return true;
168 // Otherwise (or when in the custom limit), check limit based on the global
169 // limit. It's 1/8 of the respective capacity.
170 int64_t derivedLimit =
171 aUsingDisk ? DiskCacheCapacity() : MemoryCacheCapacity();
172 derivedLimit <<= (10 - 3);
174 return aSize > derivedLimit;
177 // static
178 bool CacheObserver::IsPastShutdownIOLag() {
179 #ifdef DEBUG
180 return false;
181 #else
182 if (sShutdownDemandedTime == PR_INTERVAL_NO_TIMEOUT ||
183 MaxShutdownIOLag() == UINT32_MAX) {
184 return false;
187 static const PRIntervalTime kMaxShutdownIOLag =
188 PR_SecondsToInterval(MaxShutdownIOLag());
190 if ((PR_IntervalNow() - sShutdownDemandedTime) > kMaxShutdownIOLag) {
191 return true;
194 return false;
195 #endif
198 NS_IMETHODIMP
199 CacheObserver::Observe(nsISupports* aSubject, const char* aTopic,
200 const char16_t* aData) {
201 if (!strcmp(aTopic, "prefservice:after-app-defaults")) {
202 CacheFileIOManager::Init();
203 return NS_OK;
206 if (!strcmp(aTopic, "profile-do-change")) {
207 AttachToPreferences();
208 CacheFileIOManager::Init();
209 CacheFileIOManager::OnProfile();
210 return NS_OK;
213 if (!strcmp(aTopic, "profile-change-net-teardown") ||
214 !strcmp(aTopic, "profile-before-change") ||
215 !strcmp(aTopic, "xpcom-shutdown")) {
216 if (sShutdownDemandedTime == PR_INTERVAL_NO_TIMEOUT) {
217 sShutdownDemandedTime = PR_IntervalNow();
220 RefPtr<CacheStorageService> service = CacheStorageService::Self();
221 if (service) {
222 service->Shutdown();
225 CacheFileIOManager::Shutdown();
226 return NS_OK;
229 if (!strcmp(aTopic, "last-pb-context-exited")) {
230 RefPtr<CacheStorageService> service = CacheStorageService::Self();
231 if (service) {
232 service->DropPrivateBrowsingEntries();
235 return NS_OK;
238 if (!strcmp(aTopic, "memory-pressure")) {
239 RefPtr<CacheStorageService> service = CacheStorageService::Self();
240 if (service) {
241 service->PurgeFromMemory(nsICacheStorageService::PURGE_EVERYTHING);
244 return NS_OK;
247 if (!strcmp(aTopic, "browser-delayed-startup-finished")) {
248 CacheFileIOManager::OnDelayedStartupFinished();
249 return NS_OK;
252 if (!strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) {
253 CacheFileIOManager::OnIdleDaily();
254 return NS_OK;
257 MOZ_ASSERT(false, "Missing observer handler");
258 return NS_OK;
261 } // namespace mozilla::net