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"
13 #include "nsICacheTesting.h"
15 #include "nsClassHashtable.h"
16 #include "nsTHashMap.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"
28 class nsICacheEntryDoomCallback
;
29 class nsICacheStorageVisitor
;
36 class OriginAttributes
;
40 class CacheStorageService
;
43 class CacheEntryHandle
;
45 class CacheMemoryConsumer
{
47 friend class CacheStorageService
;
49 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields
, 32, (
50 (uint32_t, ReportedMemoryConsumption
, 30),
56 CacheMemoryConsumer() = delete;
60 // No special treatment, reports always to the disk-entries pool.
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.
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.
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
,
82 NS_DECL_THREADSAFE_ISUPPORTS
83 NS_DECL_NSICACHESTORAGESERVICE
84 NS_DECL_NSIMEMORYREPORTER
85 NS_DECL_NSITIMERCALLBACK
86 NS_DECL_NSICACHETESTING
89 CacheStorageService();
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()
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
118 class EntryInfoCallback
{
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
);
140 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
141 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
142 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf
)
145 virtual ~CacheStorageService();
146 void ShutdownBackground();
149 // The following methods may only be called on the management
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
173 void RecordMemoryOnlyEntry(CacheEntry
* aEntry
, bool aOnlyInMemory
,
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
);
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
);
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
);
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
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
);
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.
276 * true, when the entry has been found that also implies the callbacks has
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
);
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
307 void PurgeExpiredOrOverMemoryLimit();
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
339 explicit MemoryPool(EType aType
);
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
);
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
;
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};
380 class PurgeFromMemoryRunnable
: public Runnable
{
382 PurgeFromMemoryRunnable(CacheStorageService
* aService
, uint32_t aWhat
)
383 : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable"),
388 virtual ~PurgeFromMemoryRunnable() = default;
390 NS_IMETHOD
Run() override
;
392 RefPtr
<CacheStorageService
> mService
;
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
;
403 class IOThreadSuspender
: public Runnable
{
406 : Runnable("net::CacheStorageService::IOThreadSuspender"),
407 mMon("IOThreadSuspender") {}
411 virtual ~IOThreadSuspender() = default;
412 NS_IMETHOD
Run() override
;
414 Monitor mMon MOZ_UNANNOTATED
;
415 bool mSignaled
{false};
418 RefPtr
<IOThreadSuspender
> mActiveIOSuspender
;
422 void ProxyRelease(const char* aName
, nsCOMPtr
<T
>& object
,
423 nsIEventTarget
* target
) {
424 NS_ProxyRelease(aName
, target
, object
.forget());
428 void ProxyReleaseMainThread(const char* aName
, nsCOMPtr
<T
>& object
) {
429 ProxyRelease(aName
, object
, GetMainThreadSerialEventTarget());
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"