Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / netwerk / cache2 / CacheStorageService.h
blob674f674424b6e9daf9c0a499099fa6a424bc243a
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 #ifndef CacheStorageService__h__
6 #define CacheStorageService__h__
8 #include "nsICacheStorageService.h"
9 #include "nsIMemoryReporter.h"
10 #include "nsINamed.h"
11 #include "nsITimer.h"
12 #include "nsICacheTesting.h"
14 #include "nsClassHashtable.h"
15 #include "nsTHashMap.h"
16 #include "nsString.h"
17 #include "nsThreadUtils.h"
18 #include "nsProxyRelease.h"
19 #include "mozilla/Monitor.h"
20 #include "mozilla/Mutex.h"
21 #include "mozilla/AtomicBitfields.h"
22 #include "mozilla/Atomics.h"
23 #include "mozilla/TimeStamp.h"
24 #include "nsTArray.h"
26 class nsIURI;
27 class nsICacheEntryDoomCallback;
28 class nsICacheStorageVisitor;
29 class nsIRunnable;
30 class nsIThread;
31 class nsIEventTarget;
33 namespace mozilla {
35 class OriginAttributes;
37 namespace net {
39 class CacheStorageService;
40 class CacheStorage;
41 class CacheEntry;
42 class CacheEntryHandle;
44 class CacheMemoryConsumer {
45 private:
46 friend class CacheStorageService;
47 // clang-format off
48 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 32, (
49 (uint32_t, ReportedMemoryConsumption, 30),
50 (uint32_t, Flags, 2)
52 // clang-format on
54 private:
55 CacheMemoryConsumer() = delete;
57 protected:
58 enum {
59 // No special treatment, reports always to the disk-entries pool.
60 NORMAL = 0,
61 // This consumer is belonging to a memory-only cache entry, used to decide
62 // which of the two disk and memory pools count this consumption at.
63 MEMORY_ONLY = 1 << 0,
64 // Prevent reports of this consumer at all, used for disk data chunks since
65 // we throw them away as soon as the entry is not used by any consumer and
66 // don't want to make them wipe the whole pool out during their short life.
67 DONT_REPORT = 1 << 1
70 explicit CacheMemoryConsumer(uint32_t aFlags);
71 ~CacheMemoryConsumer() { DoMemoryReport(0); }
72 void DoMemoryReport(uint32_t aCurrentSize);
75 class CacheStorageService final : public nsICacheStorageService,
76 public nsIMemoryReporter,
77 public nsITimerCallback,
78 public nsICacheTesting,
79 public nsINamed {
80 public:
81 NS_DECL_THREADSAFE_ISUPPORTS
82 NS_DECL_NSICACHESTORAGESERVICE
83 NS_DECL_NSIMEMORYREPORTER
84 NS_DECL_NSITIMERCALLBACK
85 NS_DECL_NSICACHETESTING
86 NS_DECL_NSINAMED
88 CacheStorageService();
90 void Shutdown();
91 void DropPrivateBrowsingEntries();
93 static CacheStorageService* Self() { return sSelf; }
94 static nsISupports* SelfISupports() {
95 return static_cast<nsICacheStorageService*>(Self());
97 nsresult Dispatch(nsIRunnable* aEvent);
98 static bool IsRunning() { return sSelf && !sSelf->mShutdown; }
99 static bool IsOnManagementThread();
100 already_AddRefed<nsIEventTarget> Thread() const;
101 mozilla::Mutex& Lock() { return mLock; }
103 // Tracks entries that may be forced valid in a pruned hashtable.
104 struct ForcedValidData {
105 // The timestamp is computed when the entry gets inserted into the map.
106 // It should never be null for an entry in the map.
107 TimeStamp validUntil;
108 // viewed gets set to true by a call to MarkForcedValidEntryUse()
109 bool viewed = false;
111 nsTHashMap<nsCStringHashKey, ForcedValidData> mForcedValidEntries;
112 void ForcedValidEntriesPrune(TimeStamp& now);
114 // Helper thread-safe interface to pass entry info, only difference from
115 // nsICacheStorageVisitor is that instead of nsIURI only the uri spec is
116 // passed.
117 class EntryInfoCallback {
118 public:
119 virtual void OnEntryInfo(const nsACString& aURISpec,
120 const nsACString& aIdEnhance, int64_t aDataSize,
121 int64_t aAltDataSize, uint32_t aFetchCount,
122 uint32_t aLastModifiedTime,
123 uint32_t aExpirationTime, bool aPinned,
124 nsILoadContextInfo* aInfo) = 0;
127 // Invokes OnEntryInfo for the given aEntry, synchronously.
128 static void GetCacheEntryInfo(CacheEntry* aEntry,
129 EntryInfoCallback* aCallback);
131 nsresult GetCacheIndexEntryAttrs(CacheStorage const* aStorage,
132 const nsACString& aURI,
133 const nsACString& aIdExtension,
134 bool* aHasAltData, uint32_t* aFileSizeKb);
136 static uint32_t CacheQueueSize(bool highPriority);
138 // Memory reporting
139 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
140 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
141 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
143 private:
144 virtual ~CacheStorageService();
145 void ShutdownBackground();
147 private:
148 // The following methods may only be called on the management
149 // thread.
150 friend class CacheEntry;
153 * Registers the entry in management ordered arrays, a mechanism
154 * helping with weighted purge of entries.
155 * Management arrays keep hard reference to the entry. Entry is
156 * responsible to remove it self or the service is responsible to
157 * remove the entry when it's no longer needed.
159 void RegisterEntry(CacheEntry* aEntry);
162 * Deregisters the entry from management arrays. References are
163 * then released.
165 void UnregisterEntry(CacheEntry* aEntry);
168 * Removes the entry from the related entry hash table, if still present.
170 bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false);
173 * Tells the storage service whether this entry is only to be stored in
174 * memory.
176 void RecordMemoryOnlyEntry(CacheEntry* aEntry, bool aOnlyInMemory,
177 bool aOverwrite);
180 * Sets a cache entry valid (overrides the default loading behavior by loading
181 * directly from cache) for the given number of seconds
182 * See nsICacheEntry.idl for more details
184 void ForceEntryValidFor(nsACString const& aContextKey,
185 nsACString const& aEntryKey,
186 uint32_t aSecondsToTheFuture);
189 * Remove the validity info
191 void RemoveEntryForceValid(nsACString const& aContextKey,
192 nsACString const& aEntryKey);
195 * Retrieves the status of the cache entry to see if it has been forced valid
196 * (so it will loaded directly from cache without further validation)
198 bool IsForcedValidEntry(nsACString const& aContextKey,
199 nsACString const& aEntryKey);
201 // Marks the entry as used, so we may properly report when it gets evicted
202 // if the prefetched resource was used or not.
203 void MarkForcedValidEntryUse(nsACString const& aContextKey,
204 nsACString const& aEntryKey);
206 private:
207 friend class CacheIndex;
210 * CacheIndex uses this to prevent a cache entry from being prememptively
211 * thrown away when forced valid
212 * See nsICacheEntry.idl for more details
214 bool IsForcedValidEntry(nsACString const& aContextEntryKey);
216 private:
217 // These are helpers for telemetry monitoring of the memory pools.
218 void TelemetryPrune(TimeStamp& now);
219 void TelemetryRecordEntryCreation(CacheEntry const* entry);
220 void TelemetryRecordEntryRemoval(CacheEntry* entry);
222 private:
223 // Following methods are thread safe to call.
224 friend class CacheStorage;
227 * Get, or create when not existing and demanded, an entry for the storage
228 * and uri+id extension.
230 nsresult AddStorageEntry(CacheStorage const* aStorage, const nsACString& aURI,
231 const nsACString& aIdExtension, uint32_t aFlags,
232 CacheEntryHandle** aResult);
235 * Check existance of an entry. This may throw NS_ERROR_NOT_AVAILABLE
236 * when the information cannot be obtained synchronously w/o blocking.
238 nsresult CheckStorageEntry(CacheStorage const* aStorage,
239 const nsACString& aURI,
240 const nsACString& aIdExtension, bool* aResult);
243 * Removes the entry from the related entry hash table, if still present
244 * and returns it.
246 nsresult DoomStorageEntry(CacheStorage const* aStorage,
247 const nsACString& aURI,
248 const nsACString& aIdExtension,
249 nsICacheEntryDoomCallback* aCallback);
252 * Removes and returns entry table for the storage.
254 nsresult DoomStorageEntries(CacheStorage const* aStorage,
255 nsICacheEntryDoomCallback* aCallback);
258 * Walk all entiries beloging to the storage.
260 nsresult WalkStorageEntries(CacheStorage const* aStorage, bool aVisitEntries,
261 nsICacheStorageVisitor* aVisitor);
263 private:
264 friend class CacheFileIOManager;
267 * CacheFileIOManager uses this method to notify CacheStorageService that
268 * an active entry was removed. This method is called even if the entry
269 * removal was originated by CacheStorageService.
271 void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
272 const nsACString& aIdExtension,
273 const nsACString& aURISpec);
276 * Tries to find an existing entry in the hashtables and synchronously call
277 * OnCacheEntryInfo of the aVisitor callback when found.
278 * @retuns
279 * true, when the entry has been found that also implies the callbacks has
280 * beem invoked
281 * false, when an entry has not been found
283 bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
284 const nsACString& aIdExtension,
285 const nsACString& aURISpec,
286 EntryInfoCallback* aCallback);
288 private:
289 friend class CacheMemoryConsumer;
292 * When memory consumption of this entry radically changes, this method
293 * is called to reflect the size of allocated memory. This call may purge
294 * unspecified number of entries from memory (but not from disk).
296 void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
297 uint32_t aCurrentMemoryConsumption);
300 * If not already pending, it schedules mPurgeTimer that fires after 1 second
301 * and dispatches PurgeOverMemoryLimit().
303 void SchedulePurgeOverMemoryLimit();
306 * Called on the management thread, removes all expired and then least used
307 * entries from the memory, first from the disk pool and then from the memory
308 * pool.
310 void PurgeOverMemoryLimit();
312 private:
313 nsresult DoomStorageEntries(const nsACString& aContextKey,
314 nsILoadContextInfo* aContext, bool aDiskStorage,
315 bool aPin, nsICacheEntryDoomCallback* aCallback);
316 nsresult AddStorageEntry(const nsACString& aContextKey,
317 const nsACString& aURI,
318 const nsACString& aIdExtension, bool aWriteToDisk,
319 bool aSkipSizeCheck, bool aPin, uint32_t aFlags,
320 CacheEntryHandle** aResult);
322 nsresult ClearOriginInternal(
323 const nsAString& aOrigin,
324 const mozilla::OriginAttributes& aOriginAttributes, bool aAnonymous);
326 static CacheStorageService* sSelf;
328 mozilla::Mutex mLock MOZ_UNANNOTATED{"CacheStorageService.mLock"};
329 mozilla::Mutex mForcedValidEntriesLock{
330 "CacheStorageService.mForcedValidEntriesLock"};
332 Atomic<bool, Relaxed> mShutdown{false};
334 // Accessible only on the service thread
335 class MemoryPool {
336 public:
337 enum EType {
338 DISK,
339 MEMORY,
340 } mType;
342 explicit MemoryPool(EType aType);
343 ~MemoryPool();
345 nsTArray<RefPtr<CacheEntry>> mFrecencyArray;
346 nsTArray<RefPtr<CacheEntry>> mExpirationArray;
347 Atomic<uint32_t, Relaxed> mMemorySize{0};
349 bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize,
350 uint32_t aCurrentMemoryConsumption);
352 * Purges entries from memory based on the frecency ordered array.
354 void PurgeOverMemoryLimit();
355 void PurgeExpired();
356 void PurgeByFrecency(uint32_t aWhat);
357 void PurgeAll(uint32_t aWhat);
359 private:
360 uint32_t Limit() const;
361 MemoryPool() = delete;
364 MemoryPool mDiskPool{MemoryPool::DISK};
365 MemoryPool mMemoryPool{MemoryPool::MEMORY};
366 TimeStamp mLastPurgeTime;
367 MemoryPool& Pool(bool aUsingDisk) {
368 return aUsingDisk ? mDiskPool : mMemoryPool;
370 MemoryPool const& Pool(bool aUsingDisk) const {
371 return aUsingDisk ? mDiskPool : mMemoryPool;
374 nsCOMPtr<nsITimer> mPurgeTimer;
375 #ifdef MOZ_TSAN
376 // In OnMemoryConsumptionChange() we check whether the timer exists, but we
377 // cannot grab the lock there (see comment 6 in bug 1614637) and TSan reports
378 // a data race. This data race is harmless, so we use this atomic flag only in
379 // TSan build to suppress it.
380 Atomic<bool, Relaxed> mPurgeTimerActive{false};
381 #endif
383 class PurgeFromMemoryRunnable : public Runnable {
384 public:
385 PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat)
386 : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable"),
387 mService(aService),
388 mWhat(aWhat) {}
390 private:
391 virtual ~PurgeFromMemoryRunnable() = default;
393 NS_IMETHOD Run() override;
395 RefPtr<CacheStorageService> mService;
396 uint32_t mWhat;
399 // Used just for telemetry purposes, accessed only on the management thread.
400 // Note: not included in the memory reporter, this is not expected to be huge
401 // and also would be complicated to report since reporting happens on the main
402 // thread but this table is manipulated on the management thread.
403 nsTHashMap<nsCStringHashKey, mozilla::TimeStamp> mPurgeTimeStamps;
405 // nsICacheTesting
406 class IOThreadSuspender : public Runnable {
407 public:
408 IOThreadSuspender()
409 : Runnable("net::CacheStorageService::IOThreadSuspender"),
410 mMon("IOThreadSuspender") {}
411 void Notify();
413 private:
414 virtual ~IOThreadSuspender() = default;
415 NS_IMETHOD Run() override;
417 Monitor mMon MOZ_UNANNOTATED;
418 bool mSignaled{false};
421 RefPtr<IOThreadSuspender> mActiveIOSuspender;
424 template <class T>
425 void ProxyRelease(const char* aName, nsCOMPtr<T>& object,
426 nsIEventTarget* target) {
427 NS_ProxyRelease(aName, target, object.forget());
430 template <class T>
431 void ProxyReleaseMainThread(const char* aName, nsCOMPtr<T>& object) {
432 ProxyRelease(aName, object, GetMainThreadSerialEventTarget());
435 } // namespace net
436 } // namespace mozilla
438 #define NS_CACHE_STORAGE_SERVICE_CID \
440 0xea70b098, 0x5014, 0x4e21, { \
441 0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0 \
445 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID \
446 "@mozilla.org/netwerk/cache-storage-service;1"
448 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID2 \
449 "@mozilla.org/network/cache-storage-service;1"
451 #endif