Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef _nsCacheService_h_
8 : #define _nsCacheService_h_
9 :
10 : #include "nsICacheService.h"
11 : #include "nsCacheSession.h"
12 : #include "nsCacheDevice.h"
13 : #include "nsCacheEntry.h"
14 : #include "nsThreadUtils.h"
15 : #include "nsICacheListener.h"
16 : #include "nsIMemoryReporter.h"
17 :
18 : #include "prthread.h"
19 : #include "nsIObserver.h"
20 : #include "nsString.h"
21 : #include "nsTArray.h"
22 : #include "nsRefPtrHashtable.h"
23 : #include "mozilla/CondVar.h"
24 : #include "mozilla/Mutex.h"
25 : #include "mozilla/Telemetry.h"
26 :
27 : class nsCacheRequest;
28 : class nsCacheProfilePrefObserver;
29 : class nsDiskCacheDevice;
30 : class nsMemoryCacheDevice;
31 : class nsOfflineCacheDevice;
32 : class nsCacheServiceAutoLock;
33 : class nsITimer;
34 : class mozIStorageService;
35 :
36 :
37 : /******************************************************************************
38 : * nsNotifyDoomListener
39 : *****************************************************************************/
40 :
41 0 : class nsNotifyDoomListener : public mozilla::Runnable {
42 : public:
43 0 : nsNotifyDoomListener(nsICacheListener* listener, nsresult status)
44 0 : : mozilla::Runnable("nsNotifyDoomListener")
45 : , mListener(listener) // transfers reference
46 0 : , mStatus(status)
47 : {
48 0 : }
49 :
50 0 : NS_IMETHOD Run() override
51 : {
52 0 : mListener->OnCacheEntryDoomed(mStatus);
53 0 : NS_RELEASE(mListener);
54 0 : return NS_OK;
55 : }
56 :
57 : private:
58 : nsICacheListener *mListener;
59 : nsresult mStatus;
60 : };
61 :
62 : /******************************************************************************
63 : * nsCacheService
64 : ******************************************************************************/
65 :
66 : class nsCacheService final : public nsICacheServiceInternal,
67 : public nsIMemoryReporter
68 : {
69 : virtual ~nsCacheService();
70 :
71 : public:
72 : NS_DECL_THREADSAFE_ISUPPORTS
73 : NS_DECL_NSICACHESERVICE
74 : NS_DECL_NSICACHESERVICEINTERNAL
75 : NS_DECL_NSIMEMORYREPORTER
76 :
77 : nsCacheService();
78 :
79 : // Define a Create method to be used with a factory:
80 : static nsresult
81 : Create(nsISupports* outer, const nsIID& iid, void* *result);
82 :
83 :
84 : /**
85 : * Methods called by nsCacheSession
86 : */
87 : static nsresult OpenCacheEntry(nsCacheSession * session,
88 : const nsACString & key,
89 : nsCacheAccessMode accessRequested,
90 : bool blockingMode,
91 : nsICacheListener * listener,
92 : nsICacheEntryDescriptor ** result);
93 :
94 : static nsresult EvictEntriesForSession(nsCacheSession * session);
95 :
96 : static nsresult IsStorageEnabledForPolicy(nsCacheStoragePolicy storagePolicy,
97 : bool * result);
98 :
99 : static nsresult DoomEntry(nsCacheSession *session,
100 : const nsACString &key,
101 : nsICacheListener *listener);
102 :
103 : /**
104 : * Methods called by nsCacheEntryDescriptor
105 : */
106 :
107 : static void CloseDescriptor(nsCacheEntryDescriptor * descriptor);
108 :
109 : static nsresult GetFileForEntry(nsCacheEntry * entry,
110 : nsIFile ** result);
111 :
112 : static nsresult OpenInputStreamForEntry(nsCacheEntry * entry,
113 : nsCacheAccessMode mode,
114 : uint32_t offset,
115 : nsIInputStream ** result);
116 :
117 : static nsresult OpenOutputStreamForEntry(nsCacheEntry * entry,
118 : nsCacheAccessMode mode,
119 : uint32_t offset,
120 : nsIOutputStream ** result);
121 :
122 : static nsresult OnDataSizeChange(nsCacheEntry * entry, int32_t deltaSize);
123 :
124 : static nsresult SetCacheElement(nsCacheEntry * entry, nsISupports * element);
125 :
126 : static nsresult ValidateEntry(nsCacheEntry * entry);
127 :
128 : static int32_t CacheCompressionLevel();
129 :
130 : static bool GetClearingEntries();
131 :
132 : static void GetCacheBaseDirectoty(nsIFile ** result);
133 : static void GetDiskCacheDirectory(nsIFile ** result);
134 : static void GetAppCacheDirectory(nsIFile ** result);
135 :
136 : /**
137 : * Methods called by any cache classes
138 : */
139 :
140 : static
141 1 : nsCacheService * GlobalInstance() { return gService; }
142 :
143 : static nsresult DoomEntry(nsCacheEntry * entry);
144 :
145 : static bool IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy policy);
146 :
147 : /**
148 : * Called by disk cache to notify us to use the new max smart size
149 : */
150 : static void MarkStartingFresh();
151 :
152 : /**
153 : * Methods called by nsApplicationCacheService
154 : */
155 :
156 : nsresult GetOfflineDevice(nsOfflineCacheDevice ** aDevice);
157 :
158 : /**
159 : * Creates an offline cache device that works over a specific profile directory.
160 : * A tool to preload offline cache for profiles different from the current
161 : * application's profile directory.
162 : */
163 : nsresult GetCustomOfflineDevice(nsIFile *aProfileDir,
164 : int32_t aQuota,
165 : nsOfflineCacheDevice **aDevice);
166 :
167 : // This method may be called to release an object while the cache service
168 : // lock is being held. If a non-null target is specified and the target
169 : // does not correspond to the current thread, then the release will be
170 : // proxied to the specified target. Otherwise, the object will be added to
171 : // the list of objects to be released when the cache service is unlocked.
172 : static void ReleaseObject_Locked(nsISupports * object,
173 : nsIEventTarget * target = nullptr);
174 :
175 : static nsresult DispatchToCacheIOThread(nsIRunnable* event);
176 :
177 : // Calling this method will block the calling thread until all pending
178 : // events on the cache-io thread has finished. The calling thread must
179 : // hold the cache-lock
180 : static nsresult SyncWithCacheIOThread();
181 :
182 :
183 : /**
184 : * Methods called by nsCacheProfilePrefObserver
185 : */
186 : static void OnProfileShutdown();
187 : static void OnProfileChanged();
188 :
189 : static void SetDiskCacheEnabled(bool enabled);
190 : // Sets the disk cache capacity (in kilobytes)
191 : static void SetDiskCacheCapacity(int32_t capacity);
192 : // Set max size for a disk-cache entry (in KB). -1 disables limit up to
193 : // 1/8th of disk cache size
194 : static void SetDiskCacheMaxEntrySize(int32_t maxSize);
195 : // Set max size for a memory-cache entry (in kilobytes). -1 disables
196 : // limit up to 90% of memory cache size
197 : static void SetMemoryCacheMaxEntrySize(int32_t maxSize);
198 :
199 : static void SetOfflineCacheEnabled(bool enabled);
200 : // Sets the offline cache capacity (in kilobytes)
201 : static void SetOfflineCacheCapacity(int32_t capacity);
202 :
203 : static void SetMemoryCache();
204 :
205 : static void SetCacheCompressionLevel(int32_t level);
206 :
207 : // Starts smart cache size computation if disk device is available
208 : static nsresult SetDiskSmartSize();
209 :
210 : static void MoveOrRemoveDiskCache(nsIFile *aOldCacheDir,
211 : nsIFile *aNewCacheDir,
212 : const char *aCacheSubdir);
213 :
214 : nsresult Init();
215 : void Shutdown();
216 :
217 0 : static bool IsInitialized()
218 : {
219 0 : if (!gService) {
220 0 : return false;
221 : }
222 0 : return gService->mInitialized;
223 : }
224 :
225 0 : static void AssertOwnsLock()
226 0 : { gService->mLock.AssertCurrentThreadOwns(); }
227 :
228 : static void LeavePrivateBrowsing();
229 : bool IsDoomListEmpty();
230 :
231 : typedef bool (*DoomCheckFn)(nsCacheEntry* entry);
232 :
233 : // Accessors to the disabled functionality
234 : nsresult CreateSessionInternal(const char * clientID,
235 : nsCacheStoragePolicy storagePolicy,
236 : bool streamBased,
237 : nsICacheSession **result);
238 : nsresult VisitEntriesInternal(nsICacheVisitor *visitor);
239 : nsresult EvictEntriesInternal(nsCacheStoragePolicy storagePolicy);
240 :
241 : private:
242 : friend class nsCacheServiceAutoLock;
243 : friend class nsOfflineCacheDevice;
244 : friend class nsProcessRequestEvent;
245 : friend class nsSetSmartSizeEvent;
246 : friend class nsBlockOnCacheThreadEvent;
247 : friend class nsSetDiskSmartSizeCallback;
248 : friend class nsDoomEvent;
249 : friend class nsDisableOldMaxSmartSizePrefEvent;
250 : friend class nsDiskCacheMap;
251 : friend class nsAsyncDoomEvent;
252 : friend class nsCacheEntryDescriptor;
253 :
254 : /**
255 : * Internal Methods
256 : */
257 :
258 : static void Lock();
259 : static void Lock(::mozilla::Telemetry::HistogramID mainThreadLockerID);
260 : static void Unlock();
261 : void LockAcquired();
262 : void LockReleased();
263 :
264 : nsresult CreateDiskDevice();
265 : nsresult CreateOfflineDevice();
266 : nsresult CreateCustomOfflineDevice(nsIFile *aProfileDir,
267 : int32_t aQuota,
268 : nsOfflineCacheDevice **aDevice);
269 : nsresult CreateMemoryDevice();
270 :
271 : nsresult RemoveCustomOfflineDevice(nsOfflineCacheDevice *aDevice);
272 :
273 : nsresult CreateRequest(nsCacheSession * session,
274 : const nsACString & clientKey,
275 : nsCacheAccessMode accessRequested,
276 : bool blockingMode,
277 : nsICacheListener * listener,
278 : nsCacheRequest ** request);
279 :
280 : nsresult DoomEntry_Internal(nsCacheEntry * entry,
281 : bool doProcessPendingRequests);
282 :
283 : nsresult EvictEntriesForClient(const char * clientID,
284 : nsCacheStoragePolicy storagePolicy);
285 :
286 : // Notifies request listener asynchronously on the request's thread, and
287 : // releases the descriptor on the request's thread. If this method fails,
288 : // the descriptor is not released.
289 : nsresult NotifyListener(nsCacheRequest * request,
290 : nsICacheEntryDescriptor * descriptor,
291 : nsCacheAccessMode accessGranted,
292 : nsresult error);
293 :
294 : nsresult ActivateEntry(nsCacheRequest * request,
295 : nsCacheEntry ** entry,
296 : nsCacheEntry ** doomedEntry);
297 :
298 : nsCacheDevice * EnsureEntryHasDevice(nsCacheEntry * entry);
299 :
300 : nsCacheEntry * SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy, bool *collision);
301 :
302 : void DeactivateEntry(nsCacheEntry * entry);
303 :
304 : nsresult ProcessRequest(nsCacheRequest * request,
305 : bool calledFromOpenCacheEntry,
306 : nsICacheEntryDescriptor ** result);
307 :
308 : nsresult ProcessPendingRequests(nsCacheEntry * entry);
309 :
310 : void ClearDoomList(void);
311 : void DoomActiveEntries(DoomCheckFn check);
312 : void CloseAllStreams();
313 : void FireClearNetworkCacheStoredAnywhereNotification();
314 :
315 : void LogCacheStatistics();
316 :
317 : nsresult SetDiskSmartSize_Locked();
318 :
319 : /**
320 : * Data Members
321 : */
322 :
323 : static nsCacheService * gService; // there can be only one...
324 :
325 : nsCOMPtr<mozIStorageService> mStorageService;
326 :
327 : nsCacheProfilePrefObserver * mObserver;
328 :
329 : mozilla::Mutex mLock;
330 : mozilla::CondVar mCondVar;
331 : bool mNotified;
332 :
333 : mozilla::Mutex mTimeStampLock;
334 : mozilla::TimeStamp mLockAcquiredTimeStamp;
335 :
336 : nsCOMPtr<nsIThread> mCacheIOThread;
337 :
338 : nsTArray<nsISupports*> mDoomedObjects;
339 : nsCOMPtr<nsITimer> mSmartSizeTimer;
340 :
341 : bool mInitialized;
342 : bool mClearingEntries;
343 :
344 : bool mEnableMemoryDevice;
345 : bool mEnableDiskDevice;
346 : bool mEnableOfflineDevice;
347 :
348 : nsMemoryCacheDevice * mMemoryDevice;
349 : nsDiskCacheDevice * mDiskDevice;
350 : nsOfflineCacheDevice * mOfflineDevice;
351 :
352 : nsRefPtrHashtable<nsStringHashKey, nsOfflineCacheDevice> mCustomOfflineDevices;
353 :
354 : nsCacheEntryHashTable mActiveEntries;
355 : PRCList mDoomedEntries;
356 :
357 : // stats
358 :
359 : uint32_t mTotalEntries;
360 : uint32_t mCacheHits;
361 : uint32_t mCacheMisses;
362 : uint32_t mMaxKeyLength;
363 : uint32_t mMaxDataSize;
364 : uint32_t mMaxMetaSize;
365 :
366 : // Unexpected error totals
367 : uint32_t mDeactivateFailures;
368 : uint32_t mDeactivatedUnboundEntries;
369 : };
370 :
371 : /******************************************************************************
372 : * nsCacheServiceAutoLock
373 : ******************************************************************************/
374 :
375 : #define LOCK_TELEM(x) \
376 : (::mozilla::Telemetry::CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_##x)
377 :
378 : // Instantiate this class to acquire the cache service lock for a particular
379 : // execution scope.
380 : class nsCacheServiceAutoLock {
381 : public:
382 0 : nsCacheServiceAutoLock() {
383 0 : nsCacheService::Lock();
384 0 : }
385 0 : explicit nsCacheServiceAutoLock(mozilla::Telemetry::HistogramID mainThreadLockerID) {
386 0 : nsCacheService::Lock(mainThreadLockerID);
387 0 : }
388 0 : ~nsCacheServiceAutoLock() {
389 0 : nsCacheService::Unlock();
390 0 : }
391 : };
392 :
393 : #endif // _nsCacheService_h_
|