Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #ifndef CacheStorageService__h__ |
michael@0 | 6 | #define CacheStorageService__h__ |
michael@0 | 7 | |
michael@0 | 8 | #include "nsICacheStorageService.h" |
michael@0 | 9 | #include "nsIMemoryReporter.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "nsITimer.h" |
michael@0 | 12 | #include "nsClassHashtable.h" |
michael@0 | 13 | #include "nsString.h" |
michael@0 | 14 | #include "nsThreadUtils.h" |
michael@0 | 15 | #include "nsProxyRelease.h" |
michael@0 | 16 | #include "mozilla/Mutex.h" |
michael@0 | 17 | #include "mozilla/Atomics.h" |
michael@0 | 18 | #include "nsTArray.h" |
michael@0 | 19 | |
michael@0 | 20 | class nsIURI; |
michael@0 | 21 | class nsICacheEntryOpenCallback; |
michael@0 | 22 | class nsICacheEntryDoomCallback; |
michael@0 | 23 | class nsICacheStorageVisitor; |
michael@0 | 24 | class nsIRunnable; |
michael@0 | 25 | class nsIThread; |
michael@0 | 26 | class nsIEventTarget; |
michael@0 | 27 | |
michael@0 | 28 | namespace mozilla { |
michael@0 | 29 | namespace net { |
michael@0 | 30 | |
michael@0 | 31 | class CacheStorageService; |
michael@0 | 32 | class CacheStorage; |
michael@0 | 33 | class CacheEntry; |
michael@0 | 34 | class CacheEntryHandle; |
michael@0 | 35 | class CacheEntryTable; |
michael@0 | 36 | |
michael@0 | 37 | class CacheMemoryConsumer |
michael@0 | 38 | { |
michael@0 | 39 | private: |
michael@0 | 40 | friend class CacheStorageService; |
michael@0 | 41 | uint32_t mReportedMemoryConsumption : 30; |
michael@0 | 42 | uint32_t mFlags : 2; |
michael@0 | 43 | |
michael@0 | 44 | private: |
michael@0 | 45 | CacheMemoryConsumer() MOZ_DELETE; |
michael@0 | 46 | |
michael@0 | 47 | protected: |
michael@0 | 48 | enum { |
michael@0 | 49 | // No special treatment, reports always to the disk-entries pool. |
michael@0 | 50 | NORMAL = 0, |
michael@0 | 51 | // This consumer is belonging to a memory-only cache entry, used to decide |
michael@0 | 52 | // which of the two disk and memory pools count this consumption at. |
michael@0 | 53 | MEMORY_ONLY = 1 << 0, |
michael@0 | 54 | // Prevent reports of this consumer at all, used for disk data chunks since |
michael@0 | 55 | // we throw them away as soon as the entry is not used by any consumer and |
michael@0 | 56 | // don't want to make them wipe the whole pool out during their short life. |
michael@0 | 57 | DONT_REPORT = 1 << 1 |
michael@0 | 58 | }; |
michael@0 | 59 | |
michael@0 | 60 | CacheMemoryConsumer(uint32_t aFlags); |
michael@0 | 61 | ~CacheMemoryConsumer() { DoMemoryReport(0); } |
michael@0 | 62 | void DoMemoryReport(uint32_t aCurrentSize); |
michael@0 | 63 | }; |
michael@0 | 64 | |
michael@0 | 65 | class CacheStorageService : public nsICacheStorageService |
michael@0 | 66 | , public nsIMemoryReporter |
michael@0 | 67 | , public nsITimerCallback |
michael@0 | 68 | { |
michael@0 | 69 | public: |
michael@0 | 70 | NS_DECL_THREADSAFE_ISUPPORTS |
michael@0 | 71 | NS_DECL_NSICACHESTORAGESERVICE |
michael@0 | 72 | NS_DECL_NSIMEMORYREPORTER |
michael@0 | 73 | NS_DECL_NSITIMERCALLBACK |
michael@0 | 74 | |
michael@0 | 75 | CacheStorageService(); |
michael@0 | 76 | |
michael@0 | 77 | void Shutdown(); |
michael@0 | 78 | void DropPrivateBrowsingEntries(); |
michael@0 | 79 | |
michael@0 | 80 | // Wipes out the new or the old cache directory completely. |
michael@0 | 81 | static void WipeCacheDirectory(uint32_t aVersion); |
michael@0 | 82 | |
michael@0 | 83 | static CacheStorageService* Self() { return sSelf; } |
michael@0 | 84 | static nsISupports* SelfISupports() { return static_cast<nsICacheStorageService*>(Self()); } |
michael@0 | 85 | nsresult Dispatch(nsIRunnable* aEvent); |
michael@0 | 86 | static bool IsRunning() { return sSelf && !sSelf->mShutdown; } |
michael@0 | 87 | static bool IsOnManagementThread(); |
michael@0 | 88 | already_AddRefed<nsIEventTarget> Thread() const; |
michael@0 | 89 | mozilla::Mutex& Lock() { return mLock; } |
michael@0 | 90 | |
michael@0 | 91 | // Memory reporting |
michael@0 | 92 | size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
michael@0 | 93 | size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
michael@0 | 94 | MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) |
michael@0 | 95 | |
michael@0 | 96 | private: |
michael@0 | 97 | virtual ~CacheStorageService(); |
michael@0 | 98 | void ShutdownBackground(); |
michael@0 | 99 | |
michael@0 | 100 | private: |
michael@0 | 101 | // The following methods may only be called on the management |
michael@0 | 102 | // thread. |
michael@0 | 103 | friend class CacheEntry; |
michael@0 | 104 | |
michael@0 | 105 | /** |
michael@0 | 106 | * Registers the entry in management ordered arrays, a mechanism |
michael@0 | 107 | * helping with weighted purge of entries. |
michael@0 | 108 | * Management arrays keep hard reference to the entry. Entry is |
michael@0 | 109 | * responsible to remove it self or the service is responsible to |
michael@0 | 110 | * remove the entry when it's no longer needed. |
michael@0 | 111 | */ |
michael@0 | 112 | void RegisterEntry(CacheEntry* aEntry); |
michael@0 | 113 | |
michael@0 | 114 | /** |
michael@0 | 115 | * Deregisters the entry from management arrays. References are |
michael@0 | 116 | * then released. |
michael@0 | 117 | */ |
michael@0 | 118 | void UnregisterEntry(CacheEntry* aEntry); |
michael@0 | 119 | |
michael@0 | 120 | /** |
michael@0 | 121 | * Removes the entry from the related entry hash table, if still present. |
michael@0 | 122 | */ |
michael@0 | 123 | bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false); |
michael@0 | 124 | |
michael@0 | 125 | /** |
michael@0 | 126 | * Tells the storage service whether this entry is only to be stored in |
michael@0 | 127 | * memory. |
michael@0 | 128 | */ |
michael@0 | 129 | void RecordMemoryOnlyEntry(CacheEntry* aEntry, |
michael@0 | 130 | bool aOnlyInMemory, |
michael@0 | 131 | bool aOverwrite); |
michael@0 | 132 | |
michael@0 | 133 | private: |
michael@0 | 134 | // Following methods are thread safe to call. |
michael@0 | 135 | friend class CacheStorage; |
michael@0 | 136 | |
michael@0 | 137 | /** |
michael@0 | 138 | * Get, or create when not existing and demanded, an entry for the storage |
michael@0 | 139 | * and uri+id extension. |
michael@0 | 140 | */ |
michael@0 | 141 | nsresult AddStorageEntry(CacheStorage const* aStorage, |
michael@0 | 142 | nsIURI* aURI, |
michael@0 | 143 | const nsACString & aIdExtension, |
michael@0 | 144 | bool aCreateIfNotExist, |
michael@0 | 145 | bool aReplace, |
michael@0 | 146 | CacheEntryHandle** aResult); |
michael@0 | 147 | |
michael@0 | 148 | /** |
michael@0 | 149 | * Removes the entry from the related entry hash table, if still present |
michael@0 | 150 | * and returns it. |
michael@0 | 151 | */ |
michael@0 | 152 | nsresult DoomStorageEntry(CacheStorage const* aStorage, |
michael@0 | 153 | nsIURI* aURI, |
michael@0 | 154 | const nsACString & aIdExtension, |
michael@0 | 155 | nsICacheEntryDoomCallback* aCallback); |
michael@0 | 156 | |
michael@0 | 157 | /** |
michael@0 | 158 | * Removes and returns entry table for the storage. |
michael@0 | 159 | */ |
michael@0 | 160 | nsresult DoomStorageEntries(CacheStorage const* aStorage, |
michael@0 | 161 | nsICacheEntryDoomCallback* aCallback); |
michael@0 | 162 | |
michael@0 | 163 | /** |
michael@0 | 164 | * Walk all entiries beloging to the storage. |
michael@0 | 165 | */ |
michael@0 | 166 | nsresult WalkStorageEntries(CacheStorage const* aStorage, |
michael@0 | 167 | bool aVisitEntries, |
michael@0 | 168 | nsICacheStorageVisitor* aVisitor); |
michael@0 | 169 | |
michael@0 | 170 | private: |
michael@0 | 171 | friend class CacheFileIOManager; |
michael@0 | 172 | |
michael@0 | 173 | /** |
michael@0 | 174 | * CacheFileIOManager uses this method to notify CacheStorageService that |
michael@0 | 175 | * an active entry was removed. This method is called even if the entry |
michael@0 | 176 | * removal was originated by CacheStorageService. |
michael@0 | 177 | */ |
michael@0 | 178 | void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo, |
michael@0 | 179 | const nsACString & aIdExtension, |
michael@0 | 180 | const nsACString & aURISpec); |
michael@0 | 181 | |
michael@0 | 182 | private: |
michael@0 | 183 | friend class CacheMemoryConsumer; |
michael@0 | 184 | |
michael@0 | 185 | /** |
michael@0 | 186 | * When memory consumption of this entry radically changes, this method |
michael@0 | 187 | * is called to reflect the size of allocated memory. This call may purge |
michael@0 | 188 | * unspecified number of entries from memory (but not from disk). |
michael@0 | 189 | */ |
michael@0 | 190 | void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer, |
michael@0 | 191 | uint32_t aCurrentMemoryConsumption); |
michael@0 | 192 | |
michael@0 | 193 | /** |
michael@0 | 194 | * If not already pending, it schedules mPurgeTimer that fires after 1 second |
michael@0 | 195 | * and dispatches PurgeOverMemoryLimit(). |
michael@0 | 196 | */ |
michael@0 | 197 | void SchedulePurgeOverMemoryLimit(); |
michael@0 | 198 | |
michael@0 | 199 | /** |
michael@0 | 200 | * Called on the management thread, removes all expired and then least used |
michael@0 | 201 | * entries from the memory, first from the disk pool and then from the memory |
michael@0 | 202 | * pool. |
michael@0 | 203 | */ |
michael@0 | 204 | void PurgeOverMemoryLimit(); |
michael@0 | 205 | |
michael@0 | 206 | private: |
michael@0 | 207 | nsresult DoomStorageEntries(nsCSubstring const& aContextKey, |
michael@0 | 208 | nsILoadContextInfo* aContext, |
michael@0 | 209 | bool aDiskStorage, |
michael@0 | 210 | nsICacheEntryDoomCallback* aCallback); |
michael@0 | 211 | nsresult AddStorageEntry(nsCSubstring const& aContextKey, |
michael@0 | 212 | nsIURI* aURI, |
michael@0 | 213 | const nsACString & aIdExtension, |
michael@0 | 214 | bool aWriteToDisk, |
michael@0 | 215 | bool aCreateIfNotExist, |
michael@0 | 216 | bool aReplace, |
michael@0 | 217 | CacheEntryHandle** aResult); |
michael@0 | 218 | |
michael@0 | 219 | static CacheStorageService* sSelf; |
michael@0 | 220 | |
michael@0 | 221 | mozilla::Mutex mLock; |
michael@0 | 222 | |
michael@0 | 223 | bool mShutdown; |
michael@0 | 224 | |
michael@0 | 225 | // Accessible only on the service thread |
michael@0 | 226 | class MemoryPool |
michael@0 | 227 | { |
michael@0 | 228 | public: |
michael@0 | 229 | enum EType |
michael@0 | 230 | { |
michael@0 | 231 | DISK, |
michael@0 | 232 | MEMORY, |
michael@0 | 233 | } mType; |
michael@0 | 234 | |
michael@0 | 235 | MemoryPool(EType aType); |
michael@0 | 236 | ~MemoryPool(); |
michael@0 | 237 | |
michael@0 | 238 | nsTArray<nsRefPtr<CacheEntry> > mFrecencyArray; |
michael@0 | 239 | nsTArray<nsRefPtr<CacheEntry> > mExpirationArray; |
michael@0 | 240 | mozilla::Atomic<uint32_t> mMemorySize; |
michael@0 | 241 | |
michael@0 | 242 | bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize, |
michael@0 | 243 | uint32_t aCurrentMemoryConsumption); |
michael@0 | 244 | /** |
michael@0 | 245 | * Purges entries from memory based on the frecency ordered array. |
michael@0 | 246 | */ |
michael@0 | 247 | void PurgeOverMemoryLimit(); |
michael@0 | 248 | void PurgeExpired(); |
michael@0 | 249 | void PurgeByFrecency(bool &aFrecencyNeedsSort, uint32_t aWhat); |
michael@0 | 250 | void PurgeAll(uint32_t aWhat); |
michael@0 | 251 | |
michael@0 | 252 | private: |
michael@0 | 253 | uint32_t const Limit() const; |
michael@0 | 254 | MemoryPool() MOZ_DELETE; |
michael@0 | 255 | }; |
michael@0 | 256 | |
michael@0 | 257 | MemoryPool mDiskPool; |
michael@0 | 258 | MemoryPool mMemoryPool; |
michael@0 | 259 | MemoryPool& Pool(bool aUsingDisk) |
michael@0 | 260 | { |
michael@0 | 261 | return aUsingDisk ? mDiskPool : mMemoryPool; |
michael@0 | 262 | } |
michael@0 | 263 | MemoryPool const& Pool(bool aUsingDisk) const |
michael@0 | 264 | { |
michael@0 | 265 | return aUsingDisk ? mDiskPool : mMemoryPool; |
michael@0 | 266 | } |
michael@0 | 267 | |
michael@0 | 268 | nsCOMPtr<nsITimer> mPurgeTimer; |
michael@0 | 269 | |
michael@0 | 270 | class PurgeFromMemoryRunnable : public nsRunnable |
michael@0 | 271 | { |
michael@0 | 272 | public: |
michael@0 | 273 | PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat) |
michael@0 | 274 | : mService(aService), mWhat(aWhat) { } |
michael@0 | 275 | |
michael@0 | 276 | private: |
michael@0 | 277 | virtual ~PurgeFromMemoryRunnable() { } |
michael@0 | 278 | |
michael@0 | 279 | NS_IMETHOD Run() |
michael@0 | 280 | { |
michael@0 | 281 | // TODO not all flags apply to both pools |
michael@0 | 282 | mService->Pool(true).PurgeAll(mWhat); |
michael@0 | 283 | mService->Pool(false).PurgeAll(mWhat); |
michael@0 | 284 | return NS_OK; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | nsRefPtr<CacheStorageService> mService; |
michael@0 | 288 | uint32_t mWhat; |
michael@0 | 289 | }; |
michael@0 | 290 | }; |
michael@0 | 291 | |
michael@0 | 292 | template<class T> |
michael@0 | 293 | void ProxyRelease(nsCOMPtr<T> &object, nsIThread* thread) |
michael@0 | 294 | { |
michael@0 | 295 | T* release; |
michael@0 | 296 | object.forget(&release); |
michael@0 | 297 | |
michael@0 | 298 | NS_ProxyRelease(thread, release); |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | template<class T> |
michael@0 | 302 | void ProxyReleaseMainThread(nsCOMPtr<T> &object) |
michael@0 | 303 | { |
michael@0 | 304 | nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
michael@0 | 305 | ProxyRelease(object, mainThread); |
michael@0 | 306 | } |
michael@0 | 307 | |
michael@0 | 308 | } // net |
michael@0 | 309 | } // mozilla |
michael@0 | 310 | |
michael@0 | 311 | #define NS_CACHE_STORAGE_SERVICE_CID \ |
michael@0 | 312 | { 0xea70b098, 0x5014, 0x4e21, \ |
michael@0 | 313 | { 0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0 } } \ |
michael@0 | 314 | |
michael@0 | 315 | #define NS_CACHE_STORAGE_SERVICE_CONTRACTID \ |
michael@0 | 316 | "@mozilla.org/netwerk/cache-storage-service;1" |
michael@0 | 317 | |
michael@0 | 318 | #endif |