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