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