Bug 1885489 - Part 9: Add SnapshotIterator::readObject(). r=iain
[gecko.git] / netwerk / cache2 / CacheStorageService.h
blob0adc9f004d6ad9b7e32f35e58138407ed8dc40b3
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 "mozilla/LinkedList.h"
9 #include "nsICacheStorageService.h"
10 #include "nsIMemoryReporter.h"
11 #include "nsINamed.h"
12 #include "nsITimer.h"
13 #include "nsICacheTesting.h"
15 #include "nsClassHashtable.h"
16 #include "nsTHashMap.h"
17 #include "nsString.h"
18 #include "nsThreadUtils.h"
19 #include "nsProxyRelease.h"
20 #include "mozilla/Monitor.h"
21 #include "mozilla/Mutex.h"
22 #include "mozilla/AtomicBitfields.h"
23 #include "mozilla/Atomics.h"
24 #include "mozilla/TimeStamp.h"
25 #include "nsTArray.h"
27 class nsIURI;
28 class nsICacheEntryDoomCallback;
29 class nsICacheStorageVisitor;
30 class nsIRunnable;
31 class nsIThread;
32 class nsIEventTarget;
34 namespace mozilla {
36 class OriginAttributes;
38 namespace net {
40 class CacheStorageService;
41 class CacheStorage;
42 class CacheEntry;
43 class CacheEntryHandle;
45 class CacheMemoryConsumer {
46 private:
47 friend class CacheStorageService;
48 // clang-format off
49 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 32, (
50 (uint32_t, ReportedMemoryConsumption, 30),
51 (uint32_t, Flags, 2)
53 // clang-format on
55 private:
56 CacheMemoryConsumer() = delete;
58 protected:
59 enum {
60 // No special treatment, reports always to the disk-entries pool.
61 NORMAL = 0,
62 // This consumer is belonging to a memory-only cache entry, used to decide
63 // which of the two disk and memory pools count this consumption at.
64 MEMORY_ONLY = 1 << 0,
65 // Prevent reports of this consumer at all, used for disk data chunks since
66 // we throw them away as soon as the entry is not used by any consumer and
67 // don't want to make them wipe the whole pool out during their short life.
68 DONT_REPORT = 1 << 1
71 explicit CacheMemoryConsumer(uint32_t aFlags);
72 ~CacheMemoryConsumer() { DoMemoryReport(0); }
73 void DoMemoryReport(uint32_t aCurrentSize);
76 class CacheStorageService final : public nsICacheStorageService,
77 public nsIMemoryReporter,
78 public nsITimerCallback,
79 public nsICacheTesting,
80 public nsINamed {
81 public:
82 NS_DECL_THREADSAFE_ISUPPORTS
83 NS_DECL_NSICACHESTORAGESERVICE
84 NS_DECL_NSIMEMORYREPORTER
85 NS_DECL_NSITIMERCALLBACK
86 NS_DECL_NSICACHETESTING
87 NS_DECL_NSINAMED
89 CacheStorageService();
91 void Shutdown();
92 void DropPrivateBrowsingEntries();
94 static CacheStorageService* Self() { return sSelf; }
95 static nsISupports* SelfISupports() {
96 return static_cast<nsICacheStorageService*>(Self());
98 nsresult Dispatch(nsIRunnable* aEvent);
99 static bool IsRunning() { return sSelf && !sSelf->mShutdown; }
100 static bool IsOnManagementThread();
101 already_AddRefed<nsIEventTarget> Thread() const;
102 mozilla::Mutex& Lock() { return mLock; }
104 // Tracks entries that may be forced valid in a pruned hashtable.
105 struct ForcedValidData {
106 // The timestamp is computed when the entry gets inserted into the map.
107 // It should never be null for an entry in the map.
108 TimeStamp validUntil;
109 // viewed gets set to true by a call to MarkForcedValidEntryUse()
110 bool viewed = false;
112 nsTHashMap<nsCStringHashKey, ForcedValidData> mForcedValidEntries;
113 void ForcedValidEntriesPrune(TimeStamp& now);
115 // Helper thread-safe interface to pass entry info, only difference from
116 // nsICacheStorageVisitor is that instead of nsIURI only the uri spec is
117 // passed.
118 class EntryInfoCallback {
119 public:
120 virtual void OnEntryInfo(const nsACString& aURISpec,
121 const nsACString& aIdEnhance, int64_t aDataSize,
122 int64_t aAltDataSize, uint32_t aFetchCount,
123 uint32_t aLastModifiedTime,
124 uint32_t aExpirationTime, bool aPinned,
125 nsILoadContextInfo* aInfo) = 0;
128 // Invokes OnEntryInfo for the given aEntry, synchronously.
129 static void GetCacheEntryInfo(CacheEntry* aEntry,
130 EntryInfoCallback* aCallback);
132 nsresult GetCacheIndexEntryAttrs(CacheStorage const* aStorage,
133 const nsACString& aURI,
134 const nsACString& aIdExtension,
135 bool* aHasAltData, uint32_t* aFileSizeKb);
137 static uint32_t CacheQueueSize(bool highPriority);
139 // Memory reporting
140 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
141 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
142 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
144 private:
145 virtual ~CacheStorageService();
146 void ShutdownBackground();
148 private:
149 // The following methods may only be called on the management
150 // thread.
151 friend class CacheEntry;
154 * Registers the entry into the associated MemoryPool.
155 * Holds a strong reference until it is unregistered.
157 void RegisterEntry(CacheEntry* aEntry);
160 * Deregisters the entry from the associated MemoryPool.
162 void UnregisterEntry(CacheEntry* aEntry);
165 * Removes the entry from the related entry hash table, if still present.
167 bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false);
170 * Tells the storage service whether this entry is only to be stored in
171 * memory.
173 void RecordMemoryOnlyEntry(CacheEntry* aEntry, bool aOnlyInMemory,
174 bool aOverwrite);
177 * Sets a cache entry valid (overrides the default loading behavior by loading
178 * directly from cache) for the given number of seconds
179 * See nsICacheEntry.idl for more details
181 void ForceEntryValidFor(nsACString const& aContextKey,
182 nsACString const& aEntryKey,
183 uint32_t aSecondsToTheFuture);
186 * Remove the validity info
188 void RemoveEntryForceValid(nsACString const& aContextKey,
189 nsACString const& aEntryKey);
192 * Retrieves the status of the cache entry to see if it has been forced valid
193 * (so it will loaded directly from cache without further validation)
195 bool IsForcedValidEntry(nsACString const& aContextKey,
196 nsACString const& aEntryKey);
198 // Marks the entry as used, so we may properly report when it gets evicted
199 // if the prefetched resource was used or not.
200 void MarkForcedValidEntryUse(nsACString const& aContextKey,
201 nsACString const& aEntryKey);
203 private:
204 friend class CacheIndex;
207 * CacheIndex uses this to prevent a cache entry from being prememptively
208 * thrown away when forced valid
209 * See nsICacheEntry.idl for more details
211 bool IsForcedValidEntry(nsACString const& aContextEntryKey);
213 private:
214 // These are helpers for telemetry monitoring of the memory pools.
215 void TelemetryPrune(TimeStamp& now);
216 void TelemetryRecordEntryCreation(CacheEntry const* entry);
217 void TelemetryRecordEntryRemoval(CacheEntry* entry);
219 private:
220 // Following methods are thread safe to call.
221 friend class CacheStorage;
224 * Get, or create when not existing and demanded, an entry for the storage
225 * and uri+id extension.
227 nsresult AddStorageEntry(CacheStorage const* aStorage, const nsACString& aURI,
228 const nsACString& aIdExtension, uint32_t aFlags,
229 CacheEntryHandle** aResult);
232 * Check existance of an entry. This may throw NS_ERROR_NOT_AVAILABLE
233 * when the information cannot be obtained synchronously w/o blocking.
235 nsresult CheckStorageEntry(CacheStorage const* aStorage,
236 const nsACString& aURI,
237 const nsACString& aIdExtension, bool* aResult);
240 * Removes the entry from the related entry hash table, if still present
241 * and returns it.
243 nsresult DoomStorageEntry(CacheStorage const* aStorage,
244 const nsACString& aURI,
245 const nsACString& aIdExtension,
246 nsICacheEntryDoomCallback* aCallback);
249 * Removes and returns entry table for the storage.
251 nsresult DoomStorageEntries(CacheStorage const* aStorage,
252 nsICacheEntryDoomCallback* aCallback);
255 * Walk all entiries beloging to the storage.
257 nsresult WalkStorageEntries(CacheStorage const* aStorage, bool aVisitEntries,
258 nsICacheStorageVisitor* aVisitor);
260 private:
261 friend class CacheFileIOManager;
264 * CacheFileIOManager uses this method to notify CacheStorageService that
265 * an active entry was removed. This method is called even if the entry
266 * removal was originated by CacheStorageService.
268 void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
269 const nsACString& aIdExtension,
270 const nsACString& aURISpec);
273 * Tries to find an existing entry in the hashtables and synchronously call
274 * OnCacheEntryInfo of the aVisitor callback when found.
275 * @retuns
276 * true, when the entry has been found that also implies the callbacks has
277 * beem invoked
278 * false, when an entry has not been found
280 bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
281 const nsACString& aIdExtension,
282 const nsACString& aURISpec,
283 EntryInfoCallback* aCallback);
285 private:
286 friend class CacheMemoryConsumer;
289 * When memory consumption of this entry radically changes, this method
290 * is called to reflect the size of allocated memory. This call may purge
291 * unspecified number of entries from memory (but not from disk).
293 void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
294 uint32_t aCurrentMemoryConsumption);
297 * If not already pending, it schedules mPurgeTimer that fires after 1 second
298 * and dispatches PurgeOverMemoryLimit().
300 void SchedulePurgeOverMemoryLimit();
303 * Called on the management thread, removes all expired and then least used
304 * entries from the memory, first from the disk pool and then from the memory
305 * pool.
307 void PurgeExpiredOrOverMemoryLimit();
309 private:
310 nsresult DoomStorageEntries(const nsACString& aContextKey,
311 nsILoadContextInfo* aContext, bool aDiskStorage,
312 bool aPin, nsICacheEntryDoomCallback* aCallback);
313 nsresult AddStorageEntry(const nsACString& aContextKey,
314 const nsACString& aURI,
315 const nsACString& aIdExtension, bool aWriteToDisk,
316 bool aSkipSizeCheck, bool aPin, uint32_t aFlags,
317 CacheEntryHandle** aResult);
319 nsresult ClearOriginInternal(
320 const nsAString& aOrigin,
321 const mozilla::OriginAttributes& aOriginAttributes, bool aAnonymous);
323 static CacheStorageService* sSelf;
325 mozilla::Mutex mLock MOZ_UNANNOTATED{"CacheStorageService.mLock"};
326 mozilla::Mutex mForcedValidEntriesLock{
327 "CacheStorageService.mForcedValidEntriesLock"};
329 Atomic<bool, Relaxed> mShutdown{false};
331 // Accessible only on the service thread
332 class MemoryPool {
333 public:
334 enum EType {
335 DISK,
336 MEMORY,
337 } mType;
339 explicit MemoryPool(EType aType);
340 ~MemoryPool();
342 // We want to have constant O(1) for removal from this list.
343 LinkedList<RefPtr<CacheEntry>> mManagedEntries;
344 Atomic<uint32_t, Relaxed> mMemorySize{0};
346 bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize,
347 uint32_t aCurrentMemoryConsumption);
349 * Purges entries from memory based on the frecency ordered array.
351 void PurgeExpiredOrOverMemoryLimit();
352 size_t PurgeExpired(size_t minprogress);
353 Result<size_t, nsresult> PurgeByFrecency(size_t minprogress);
354 size_t PurgeAll(uint32_t aWhat, size_t minprogress);
356 private:
357 uint32_t Limit() const;
358 MemoryPool() = delete;
361 MemoryPool mDiskPool{MemoryPool::DISK};
362 MemoryPool mMemoryPool{MemoryPool::MEMORY};
363 TimeStamp mLastPurgeTime;
364 MemoryPool& Pool(bool aUsingDisk) {
365 return aUsingDisk ? mDiskPool : mMemoryPool;
367 MemoryPool const& Pool(bool aUsingDisk) const {
368 return aUsingDisk ? mDiskPool : mMemoryPool;
371 nsCOMPtr<nsITimer> mPurgeTimer;
372 #ifdef MOZ_TSAN
373 // In OnMemoryConsumptionChange() we check whether the timer exists, but we
374 // cannot grab the lock there (see comment 6 in bug 1614637) and TSan reports
375 // a data race. This data race is harmless, so we use this atomic flag only in
376 // TSan build to suppress it.
377 Atomic<bool, Relaxed> mPurgeTimerActive{false};
378 #endif
380 class PurgeFromMemoryRunnable : public Runnable {
381 public:
382 PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat)
383 : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable"),
384 mService(aService),
385 mWhat(aWhat) {}
387 private:
388 virtual ~PurgeFromMemoryRunnable() = default;
390 NS_IMETHOD Run() override;
392 RefPtr<CacheStorageService> mService;
393 uint32_t mWhat;
396 // Used just for telemetry purposes, accessed only on the management thread.
397 // Note: not included in the memory reporter, this is not expected to be huge
398 // and also would be complicated to report since reporting happens on the main
399 // thread but this table is manipulated on the management thread.
400 nsTHashMap<nsCStringHashKey, mozilla::TimeStamp> mPurgeTimeStamps;
402 // nsICacheTesting
403 class IOThreadSuspender : public Runnable {
404 public:
405 IOThreadSuspender()
406 : Runnable("net::CacheStorageService::IOThreadSuspender"),
407 mMon("IOThreadSuspender") {}
408 void Notify();
410 private:
411 virtual ~IOThreadSuspender() = default;
412 NS_IMETHOD Run() override;
414 Monitor mMon MOZ_UNANNOTATED;
415 bool mSignaled{false};
418 RefPtr<IOThreadSuspender> mActiveIOSuspender;
421 template <class T>
422 void ProxyRelease(const char* aName, nsCOMPtr<T>& object,
423 nsIEventTarget* target) {
424 NS_ProxyRelease(aName, target, object.forget());
427 template <class T>
428 void ProxyReleaseMainThread(const char* aName, nsCOMPtr<T>& object) {
429 ProxyRelease(aName, object, GetMainThreadSerialEventTarget());
432 } // namespace net
433 } // namespace mozilla
435 #define NS_CACHE_STORAGE_SERVICE_CID \
437 0xea70b098, 0x5014, 0x4e21, { \
438 0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0 \
442 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID \
443 "@mozilla.org/netwerk/cache-storage-service;1"
445 #define NS_CACHE_STORAGE_SERVICE_CONTRACTID2 \
446 "@mozilla.org/network/cache-storage-service;1"
448 #endif