Line data Source code
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/. */
4 :
5 : #ifndef CacheStorageService__h__
6 : #define CacheStorageService__h__
7 :
8 : #include "nsICacheStorageService.h"
9 : #include "nsIMemoryReporter.h"
10 : #include "nsITimer.h"
11 : #include "nsICacheTesting.h"
12 :
13 : #include "nsClassHashtable.h"
14 : #include "nsDataHashtable.h"
15 : #include "nsString.h"
16 : #include "nsThreadUtils.h"
17 : #include "nsProxyRelease.h"
18 : #include "mozilla/Monitor.h"
19 : #include "mozilla/Mutex.h"
20 : #include "mozilla/Atomics.h"
21 : #include "mozilla/TimeStamp.h"
22 : #include "nsTArray.h"
23 :
24 : class nsIURI;
25 : class nsICacheEntryDoomCallback;
26 : class nsICacheStorageVisitor;
27 : class nsIRunnable;
28 : class nsIThread;
29 : class nsIEventTarget;
30 :
31 : namespace mozilla {
32 : namespace net {
33 :
34 : class CacheStorageService;
35 : class CacheStorage;
36 : class CacheEntry;
37 : class CacheEntryHandle;
38 :
39 : class CacheMemoryConsumer
40 : {
41 : private:
42 : friend class CacheStorageService;
43 : uint32_t mReportedMemoryConsumption : 30;
44 : uint32_t mFlags : 2;
45 :
46 : private:
47 : CacheMemoryConsumer() = delete;
48 :
49 : protected:
50 : enum {
51 : // No special treatment, reports always to the disk-entries pool.
52 : NORMAL = 0,
53 : // This consumer is belonging to a memory-only cache entry, used to decide
54 : // which of the two disk and memory pools count this consumption at.
55 : MEMORY_ONLY = 1 << 0,
56 : // Prevent reports of this consumer at all, used for disk data chunks since
57 : // we throw them away as soon as the entry is not used by any consumer and
58 : // don't want to make them wipe the whole pool out during their short life.
59 : DONT_REPORT = 1 << 1
60 : };
61 :
62 : explicit CacheMemoryConsumer(uint32_t aFlags);
63 4 : ~CacheMemoryConsumer() { DoMemoryReport(0); }
64 : void DoMemoryReport(uint32_t aCurrentSize);
65 : };
66 :
67 : class CacheStorageService final : public nsICacheStorageService
68 : , public nsIMemoryReporter
69 : , public nsITimerCallback
70 : , public nsICacheTesting
71 : {
72 : public:
73 : NS_DECL_THREADSAFE_ISUPPORTS
74 : NS_DECL_NSICACHESTORAGESERVICE
75 : NS_DECL_NSIMEMORYREPORTER
76 : NS_DECL_NSITIMERCALLBACK
77 : NS_DECL_NSICACHETESTING
78 :
79 : CacheStorageService();
80 :
81 : void Shutdown();
82 : void DropPrivateBrowsingEntries();
83 :
84 : // Takes care of deleting any pending trashes for both cache1 and cache2
85 : // as well as the cache directory of an inactive cache version when requested.
86 : static void CleaupCacheDirectories(uint32_t aVersion, uint32_t aActive);
87 :
88 204 : static CacheStorageService* Self() { return sSelf; }
89 : static nsISupports* SelfISupports() { return static_cast<nsICacheStorageService*>(Self()); }
90 : nsresult Dispatch(nsIRunnable* aEvent);
91 0 : static bool IsRunning() { return sSelf && !sSelf->mShutdown; }
92 : static bool IsOnManagementThread();
93 : already_AddRefed<nsIEventTarget> Thread() const;
94 10 : mozilla::Mutex& Lock() { return mLock; }
95 :
96 : // Tracks entries that may be forced valid in a pruned hashtable.
97 : nsDataHashtable<nsCStringHashKey, TimeStamp> mForcedValidEntries;
98 : void ForcedValidEntriesPrune(TimeStamp &now);
99 :
100 : // Helper thread-safe interface to pass entry info, only difference from
101 : // nsICacheStorageVisitor is that instead of nsIURI only the uri spec is
102 : // passed.
103 0 : class EntryInfoCallback {
104 : public:
105 : virtual void OnEntryInfo(const nsACString & aURISpec, const nsACString & aIdEnhance,
106 : int64_t aDataSize, int32_t aFetchCount,
107 : uint32_t aLastModifiedTime, uint32_t aExpirationTime,
108 : bool aPinned, nsILoadContextInfo* aInfo) = 0;
109 : };
110 :
111 : // Invokes OnEntryInfo for the given aEntry, synchronously.
112 : static void GetCacheEntryInfo(CacheEntry* aEntry, EntryInfoCallback *aVisitor);
113 :
114 : nsresult GetCacheIndexEntryAttrs(CacheStorage const* aStorage,
115 : const nsACString &aURI,
116 : const nsACString &aIdExtension,
117 : bool *aHasAltData,
118 : uint32_t *aFileSizeKb);
119 :
120 : static uint32_t CacheQueueSize(bool highPriority);
121 :
122 : // Memory reporting
123 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
124 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
125 0 : MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
126 :
127 : private:
128 : virtual ~CacheStorageService();
129 : void ShutdownBackground();
130 :
131 : private:
132 : // The following methods may only be called on the management
133 : // thread.
134 : friend class CacheEntry;
135 :
136 : /**
137 : * Registers the entry in management ordered arrays, a mechanism
138 : * helping with weighted purge of entries.
139 : * Management arrays keep hard reference to the entry. Entry is
140 : * responsible to remove it self or the service is responsible to
141 : * remove the entry when it's no longer needed.
142 : */
143 : void RegisterEntry(CacheEntry* aEntry);
144 :
145 : /**
146 : * Deregisters the entry from management arrays. References are
147 : * then released.
148 : */
149 : void UnregisterEntry(CacheEntry* aEntry);
150 :
151 : /**
152 : * Removes the entry from the related entry hash table, if still present.
153 : */
154 : bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false);
155 :
156 : /**
157 : * Tells the storage service whether this entry is only to be stored in
158 : * memory.
159 : */
160 : void RecordMemoryOnlyEntry(CacheEntry* aEntry,
161 : bool aOnlyInMemory,
162 : bool aOverwrite);
163 :
164 : /**
165 : * Sets a cache entry valid (overrides the default loading behavior by loading
166 : * directly from cache) for the given number of seconds
167 : * See nsICacheEntry.idl for more details
168 : */
169 : void ForceEntryValidFor(nsACString const &aContextKey,
170 : nsACString const &aEntryKey,
171 : uint32_t aSecondsToTheFuture);
172 :
173 : /**
174 : * Remove the validity info
175 : */
176 : void RemoveEntryForceValid(nsACString const &aContextKey,
177 : nsACString const &aEntryKey);
178 :
179 : /**
180 : * Retrieves the status of the cache entry to see if it has been forced valid
181 : * (so it will loaded directly from cache without further validation)
182 : */
183 : bool IsForcedValidEntry(nsACString const &aContextKey,
184 : nsACString const &aEntryKey);
185 :
186 : private:
187 : friend class CacheIndex;
188 :
189 : /**
190 : * CacheIndex uses this to prevent a cache entry from being prememptively
191 : * thrown away when forced valid
192 : * See nsICacheEntry.idl for more details
193 : */
194 : bool IsForcedValidEntry(nsACString const &aEntryKeyWithContext);
195 :
196 : private:
197 : // These are helpers for telemetry monitoring of the memory pools.
198 : void TelemetryPrune(TimeStamp &now);
199 : void TelemetryRecordEntryCreation(CacheEntry const* entry);
200 : void TelemetryRecordEntryRemoval(CacheEntry const* entry);
201 :
202 : private:
203 : // Following methods are thread safe to call.
204 : friend class CacheStorage;
205 :
206 : /**
207 : * Get, or create when not existing and demanded, an entry for the storage
208 : * and uri+id extension.
209 : */
210 : nsresult AddStorageEntry(CacheStorage const* aStorage,
211 : const nsACString & aURI,
212 : const nsACString & aIdExtension,
213 : bool aReplace,
214 : CacheEntryHandle** aResult);
215 :
216 : /**
217 : * Check existance of an entry. This may throw NS_ERROR_NOT_AVAILABLE
218 : * when the information cannot be obtained synchronously w/o blocking.
219 : */
220 : nsresult CheckStorageEntry(CacheStorage const* aStorage,
221 : const nsACString & aURI,
222 : const nsACString & aIdExtension,
223 : bool* aResult);
224 :
225 : /**
226 : * Removes the entry from the related entry hash table, if still present
227 : * and returns it.
228 : */
229 : nsresult DoomStorageEntry(CacheStorage const* aStorage,
230 : const nsACString & aURI,
231 : const nsACString & aIdExtension,
232 : nsICacheEntryDoomCallback* aCallback);
233 :
234 : /**
235 : * Removes and returns entry table for the storage.
236 : */
237 : nsresult DoomStorageEntries(CacheStorage const* aStorage,
238 : nsICacheEntryDoomCallback* aCallback);
239 :
240 : /**
241 : * Walk all entiries beloging to the storage.
242 : */
243 : nsresult WalkStorageEntries(CacheStorage const* aStorage,
244 : bool aVisitEntries,
245 : nsICacheStorageVisitor* aVisitor);
246 :
247 : private:
248 : friend class CacheFileIOManager;
249 :
250 : /**
251 : * CacheFileIOManager uses this method to notify CacheStorageService that
252 : * an active entry was removed. This method is called even if the entry
253 : * removal was originated by CacheStorageService.
254 : */
255 : void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo,
256 : const nsACString & aIdExtension,
257 : const nsACString & aURISpec);
258 :
259 : /**
260 : * Tries to find an existing entry in the hashtables and synchronously call
261 : * OnCacheEntryInfo of the aVisitor callback when found.
262 : * @retuns
263 : * true, when the entry has been found that also implies the callbacks has
264 : * beem invoked
265 : * false, when an entry has not been found
266 : */
267 : bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo,
268 : const nsACString & aIdExtension,
269 : const nsACString & aURISpec,
270 : EntryInfoCallback *aCallback);
271 :
272 : private:
273 : friend class CacheMemoryConsumer;
274 :
275 : /**
276 : * When memory consumption of this entry radically changes, this method
277 : * is called to reflect the size of allocated memory. This call may purge
278 : * unspecified number of entries from memory (but not from disk).
279 : */
280 : void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer,
281 : uint32_t aCurrentMemoryConsumption);
282 :
283 : /**
284 : * If not already pending, it schedules mPurgeTimer that fires after 1 second
285 : * and dispatches PurgeOverMemoryLimit().
286 : */
287 : void SchedulePurgeOverMemoryLimit();
288 :
289 : /**
290 : * Called on the management thread, removes all expired and then least used
291 : * entries from the memory, first from the disk pool and then from the memory
292 : * pool.
293 : */
294 : void PurgeOverMemoryLimit();
295 :
296 : private:
297 : nsresult DoomStorageEntries(const nsACString& aContextKey,
298 : nsILoadContextInfo* aContext,
299 : bool aDiskStorage,
300 : bool aPin,
301 : nsICacheEntryDoomCallback* aCallback);
302 : nsresult AddStorageEntry(const nsACString& aContextKey,
303 : const nsACString & aURI,
304 : const nsACString & aIdExtension,
305 : bool aWriteToDisk,
306 : bool aSkipSizeCheck,
307 : bool aPin,
308 : bool aReplace,
309 : CacheEntryHandle** aResult);
310 :
311 : static CacheStorageService* sSelf;
312 :
313 : mozilla::Mutex mLock;
314 : mozilla::Mutex mForcedValidEntriesLock;
315 :
316 : bool mShutdown;
317 :
318 : // Accessible only on the service thread
319 : class MemoryPool
320 : {
321 : public:
322 : enum EType
323 : {
324 : DISK,
325 : MEMORY,
326 : } mType;
327 :
328 : explicit MemoryPool(EType aType);
329 : ~MemoryPool();
330 :
331 : nsTArray<RefPtr<CacheEntry> > mFrecencyArray;
332 : nsTArray<RefPtr<CacheEntry> > mExpirationArray;
333 : Atomic<uint32_t, Relaxed> mMemorySize;
334 :
335 : bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize,
336 : uint32_t aCurrentMemoryConsumption);
337 : /**
338 : * Purges entries from memory based on the frecency ordered array.
339 : */
340 : void PurgeOverMemoryLimit();
341 : void PurgeExpired();
342 : void PurgeByFrecency(bool &aFrecencyNeedsSort, uint32_t aWhat);
343 : void PurgeAll(uint32_t aWhat);
344 :
345 : private:
346 : uint32_t Limit() const;
347 : MemoryPool() = delete;
348 : };
349 :
350 : MemoryPool mDiskPool;
351 : MemoryPool mMemoryPool;
352 : TimeStamp mLastPurgeTime;
353 22 : MemoryPool& Pool(bool aUsingDisk)
354 : {
355 22 : return aUsingDisk ? mDiskPool : mMemoryPool;
356 : }
357 0 : MemoryPool const& Pool(bool aUsingDisk) const
358 : {
359 0 : return aUsingDisk ? mDiskPool : mMemoryPool;
360 : }
361 :
362 : nsCOMPtr<nsITimer> mPurgeTimer;
363 :
364 : class PurgeFromMemoryRunnable : public Runnable
365 : {
366 : public:
367 0 : PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat)
368 0 : : Runnable("net::CacheStorageService::PurgeFromMemoryRunnable")
369 : , mService(aService)
370 0 : , mWhat(aWhat)
371 : {
372 0 : }
373 :
374 : private:
375 0 : virtual ~PurgeFromMemoryRunnable() { }
376 :
377 : NS_IMETHOD Run() override;
378 :
379 : RefPtr<CacheStorageService> mService;
380 : uint32_t mWhat;
381 : };
382 :
383 : // Used just for telemetry purposes, accessed only on the management thread.
384 : // Note: not included in the memory reporter, this is not expected to be huge
385 : // and also would be complicated to report since reporting happens on the main
386 : // thread but this table is manipulated on the management thread.
387 : nsDataHashtable<nsCStringHashKey, mozilla::TimeStamp> mPurgeTimeStamps;
388 :
389 : // nsICacheTesting
390 : class IOThreadSuspender : public Runnable
391 : {
392 : public:
393 0 : IOThreadSuspender()
394 0 : : Runnable("net::CacheStorageService::IOThreadSuspender")
395 : , mMon("IOThreadSuspender")
396 0 : , mSignaled(false)
397 : {
398 0 : }
399 : void Notify();
400 : private:
401 0 : virtual ~IOThreadSuspender() { }
402 : NS_IMETHOD Run() override;
403 :
404 : Monitor mMon;
405 : bool mSignaled;
406 : };
407 :
408 : RefPtr<IOThreadSuspender> mActiveIOSuspender;
409 : };
410 :
411 : template<class T>
412 49 : void ProxyRelease(const char* aName, nsCOMPtr<T> &object, nsIEventTarget* target)
413 : {
414 49 : NS_ProxyRelease(aName, target, object.forget());
415 49 : }
416 :
417 : template<class T>
418 0 : void ProxyReleaseMainThread(const char* aName, nsCOMPtr<T> &object)
419 : {
420 0 : ProxyRelease(aName, object, GetMainThreadEventTarget());
421 0 : }
422 :
423 : } // namespace net
424 : } // namespace mozilla
425 :
426 : #define NS_CACHE_STORAGE_SERVICE_CID \
427 : { 0xea70b098, 0x5014, 0x4e21, \
428 : { 0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0 } } \
429 :
430 : #define NS_CACHE_STORAGE_SERVICE_CONTRACTID \
431 : "@mozilla.org/netwerk/cache-storage-service;1"
432 :
433 : #define NS_CACHE_STORAGE_SERVICE_CONTRACTID2 \
434 : "@mozilla.org/network/cache-storage-service;1"
435 :
436 : #endif
|