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"
12 #include "nsICacheTesting.h"
14 #include "nsClassHashtable.h"
15 #include "nsTHashMap.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"
27 class nsICacheEntryDoomCallback
;
28 class nsICacheStorageVisitor
;
35 class OriginAttributes
;
39 class CacheStorageService
;
42 class CacheEntryHandle
;
44 class CacheMemoryConsumer
{
46 friend class CacheStorageService
;
48 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields
, 32, (
49 (uint32_t, ReportedMemoryConsumption
, 30),
55 CacheMemoryConsumer() = delete;
59 // No special treatment, reports always to the disk-entries pool.
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.
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.
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
,
81 NS_DECL_THREADSAFE_ISUPPORTS
82 NS_DECL_NSICACHESTORAGESERVICE
83 NS_DECL_NSIMEMORYREPORTER
84 NS_DECL_NSITIMERCALLBACK
85 NS_DECL_NSICACHETESTING
88 CacheStorageService();
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()
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
117 class EntryInfoCallback
{
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
);
139 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
140 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
141 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf
)
144 virtual ~CacheStorageService();
145 void ShutdownBackground();
148 // The following methods may only be called on the management
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
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
176 void RecordMemoryOnlyEntry(CacheEntry
* aEntry
, bool aOnlyInMemory
,
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
);
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
);
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
);
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
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
);
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.
279 * true, when the entry has been found that also implies the callbacks has
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
);
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
310 void PurgeOverMemoryLimit();
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
342 explicit MemoryPool(EType aType
);
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();
356 void PurgeByFrecency(uint32_t aWhat
);
357 void PurgeAll(uint32_t aWhat
);
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
;
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};
383 class PurgeFromMemoryRunnable
: public Runnable
{
385 PurgeFromMemoryRunnable(CacheStorageService
* aService
, uint32_t aWhat
)
386 : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable"),
391 virtual ~PurgeFromMemoryRunnable() = default;
393 NS_IMETHOD
Run() override
;
395 RefPtr
<CacheStorageService
> mService
;
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
;
406 class IOThreadSuspender
: public Runnable
{
409 : Runnable("net::CacheStorageService::IOThreadSuspender"),
410 mMon("IOThreadSuspender") {}
414 virtual ~IOThreadSuspender() = default;
415 NS_IMETHOD
Run() override
;
417 Monitor mMon MOZ_UNANNOTATED
;
418 bool mSignaled
{false};
421 RefPtr
<IOThreadSuspender
> mActiveIOSuspender
;
425 void ProxyRelease(const char* aName
, nsCOMPtr
<T
>& object
,
426 nsIEventTarget
* target
) {
427 NS_ProxyRelease(aName
, target
, object
.forget());
431 void ProxyReleaseMainThread(const char* aName
, nsCOMPtr
<T
>& object
) {
432 ProxyRelease(aName
, object
, GetMainThreadSerialEventTarget());
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"