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