diff options
Diffstat (limited to 'netwerk/cache2/CacheStorageService.h')
-rw-r--r-- | netwerk/cache2/CacheStorageService.h | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/netwerk/cache2/CacheStorageService.h b/netwerk/cache2/CacheStorageService.h new file mode 100644 index 000000000..f40459d84 --- /dev/null +++ b/netwerk/cache2/CacheStorageService.h @@ -0,0 +1,422 @@ +/* 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 CacheStorageService__h__ +#define CacheStorageService__h__ + +#include "nsICacheStorageService.h" +#include "nsIMemoryReporter.h" +#include "nsITimer.h" +#include "nsICacheTesting.h" + +#include "nsClassHashtable.h" +#include "nsDataHashtable.h" +#include "nsString.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" +#include "mozilla/Monitor.h" +#include "mozilla/Mutex.h" +#include "mozilla/Atomics.h" +#include "mozilla/TimeStamp.h" +#include "nsTArray.h" + +class nsIURI; +class nsICacheEntryDoomCallback; +class nsICacheStorageVisitor; +class nsIRunnable; +class nsIThread; +class nsIEventTarget; + +namespace mozilla { +namespace net { + +class CacheStorageService; +class CacheStorage; +class CacheEntry; +class CacheEntryHandle; + +class CacheMemoryConsumer +{ +private: + friend class CacheStorageService; + uint32_t mReportedMemoryConsumption : 30; + uint32_t mFlags : 2; + +private: + CacheMemoryConsumer() = delete; + +protected: + enum { + // No special treatment, reports always to the disk-entries pool. + NORMAL = 0, + // This consumer is belonging to a memory-only cache entry, used to decide + // which of the two disk and memory pools count this consumption at. + MEMORY_ONLY = 1 << 0, + // Prevent reports of this consumer at all, used for disk data chunks since + // we throw them away as soon as the entry is not used by any consumer and + // don't want to make them wipe the whole pool out during their short life. + DONT_REPORT = 1 << 1 + }; + + explicit CacheMemoryConsumer(uint32_t aFlags); + ~CacheMemoryConsumer() { DoMemoryReport(0); } + void DoMemoryReport(uint32_t aCurrentSize); +}; + +class CacheStorageService final : public nsICacheStorageService + , public nsIMemoryReporter + , public nsITimerCallback + , public nsICacheTesting +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICACHESTORAGESERVICE + NS_DECL_NSIMEMORYREPORTER + NS_DECL_NSITIMERCALLBACK + NS_DECL_NSICACHETESTING + + CacheStorageService(); + + void Shutdown(); + void DropPrivateBrowsingEntries(); + + // Takes care of deleting any pending trashes for both cache1 and cache2 + // as well as the cache directory of an inactive cache version when requested. + static void CleaupCacheDirectories(uint32_t aVersion, uint32_t aActive); + + static CacheStorageService* Self() { return sSelf; } + static nsISupports* SelfISupports() { return static_cast<nsICacheStorageService*>(Self()); } + nsresult Dispatch(nsIRunnable* aEvent); + static bool IsRunning() { return sSelf && !sSelf->mShutdown; } + static bool IsOnManagementThread(); + already_AddRefed<nsIEventTarget> Thread() const; + mozilla::Mutex& Lock() { return mLock; } + + // Tracks entries that may be forced valid in a pruned hashtable. + nsDataHashtable<nsCStringHashKey, TimeStamp> mForcedValidEntries; + void ForcedValidEntriesPrune(TimeStamp &now); + + // Helper thread-safe interface to pass entry info, only difference from + // nsICacheStorageVisitor is that instead of nsIURI only the uri spec is + // passed. + class EntryInfoCallback { + public: + virtual void OnEntryInfo(const nsACString & aURISpec, const nsACString & aIdEnhance, + int64_t aDataSize, int32_t aFetchCount, + uint32_t aLastModifiedTime, uint32_t aExpirationTime, + bool aPinned) = 0; + }; + + // Invokes OnEntryInfo for the given aEntry, synchronously. + static void GetCacheEntryInfo(CacheEntry* aEntry, EntryInfoCallback *aVisitor); + + static uint32_t CacheQueueSize(bool highPriority); + + // Memory reporting + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) + +private: + virtual ~CacheStorageService(); + void ShutdownBackground(); + +private: + // The following methods may only be called on the management + // thread. + friend class CacheEntry; + + /** + * Registers the entry in management ordered arrays, a mechanism + * helping with weighted purge of entries. + * Management arrays keep hard reference to the entry. Entry is + * responsible to remove it self or the service is responsible to + * remove the entry when it's no longer needed. + */ + void RegisterEntry(CacheEntry* aEntry); + + /** + * Deregisters the entry from management arrays. References are + * then released. + */ + void UnregisterEntry(CacheEntry* aEntry); + + /** + * Removes the entry from the related entry hash table, if still present. + */ + bool RemoveEntry(CacheEntry* aEntry, bool aOnlyUnreferenced = false); + + /** + * Tells the storage service whether this entry is only to be stored in + * memory. + */ + void RecordMemoryOnlyEntry(CacheEntry* aEntry, + bool aOnlyInMemory, + bool aOverwrite); + + /** + * Sets a cache entry valid (overrides the default loading behavior by loading + * directly from cache) for the given number of seconds + * See nsICacheEntry.idl for more details + */ + void ForceEntryValidFor(nsACString const &aContextKey, + nsACString const &aEntryKey, + uint32_t aSecondsToTheFuture); + + /** + * Remove the validity info + */ + void RemoveEntryForceValid(nsACString const &aContextKey, + nsACString const &aEntryKey); + + /** + * Retrieves the status of the cache entry to see if it has been forced valid + * (so it will loaded directly from cache without further validation) + */ + bool IsForcedValidEntry(nsACString const &aContextKey, + nsACString const &aEntryKey); + +private: + friend class CacheIndex; + + /** + * CacheIndex uses this to prevent a cache entry from being prememptively + * thrown away when forced valid + * See nsICacheEntry.idl for more details + */ + bool IsForcedValidEntry(nsACString const &aEntryKeyWithContext); + +private: + // These are helpers for telemetry monitoring of the memory pools. + void TelemetryPrune(TimeStamp &now); + void TelemetryRecordEntryCreation(CacheEntry const* entry); + void TelemetryRecordEntryRemoval(CacheEntry const* entry); + +private: + // Following methods are thread safe to call. + friend class CacheStorage; + + /** + * Get, or create when not existing and demanded, an entry for the storage + * and uri+id extension. + */ + nsresult AddStorageEntry(CacheStorage const* aStorage, + const nsACString & aURI, + const nsACString & aIdExtension, + bool aReplace, + CacheEntryHandle** aResult); + + /** + * Check existance of an entry. This may throw NS_ERROR_NOT_AVAILABLE + * when the information cannot be obtained synchronously w/o blocking. + */ + nsresult CheckStorageEntry(CacheStorage const* aStorage, + const nsACString & aURI, + const nsACString & aIdExtension, + bool* aResult); + + /** + * Removes the entry from the related entry hash table, if still present + * and returns it. + */ + nsresult DoomStorageEntry(CacheStorage const* aStorage, + const nsACString & aURI, + const nsACString & aIdExtension, + nsICacheEntryDoomCallback* aCallback); + + /** + * Removes and returns entry table for the storage. + */ + nsresult DoomStorageEntries(CacheStorage const* aStorage, + nsICacheEntryDoomCallback* aCallback); + + /** + * Walk all entiries beloging to the storage. + */ + nsresult WalkStorageEntries(CacheStorage const* aStorage, + bool aVisitEntries, + nsICacheStorageVisitor* aVisitor); + +private: + friend class CacheFileIOManager; + + /** + * CacheFileIOManager uses this method to notify CacheStorageService that + * an active entry was removed. This method is called even if the entry + * removal was originated by CacheStorageService. + */ + void CacheFileDoomed(nsILoadContextInfo* aLoadContextInfo, + const nsACString & aIdExtension, + const nsACString & aURISpec); + + /** + * Tries to find an existing entry in the hashtables and synchronously call + * OnCacheEntryInfo of the aVisitor callback when found. + * @retuns + * true, when the entry has been found that also implies the callbacks has + * beem invoked + * false, when an entry has not been found + */ + bool GetCacheEntryInfo(nsILoadContextInfo* aLoadContextInfo, + const nsACString & aIdExtension, + const nsACString & aURISpec, + EntryInfoCallback *aCallback); + +private: + friend class CacheMemoryConsumer; + + /** + * When memory consumption of this entry radically changes, this method + * is called to reflect the size of allocated memory. This call may purge + * unspecified number of entries from memory (but not from disk). + */ + void OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer, + uint32_t aCurrentMemoryConsumption); + + /** + * If not already pending, it schedules mPurgeTimer that fires after 1 second + * and dispatches PurgeOverMemoryLimit(). + */ + void SchedulePurgeOverMemoryLimit(); + + /** + * Called on the management thread, removes all expired and then least used + * entries from the memory, first from the disk pool and then from the memory + * pool. + */ + void PurgeOverMemoryLimit(); + +private: + nsresult DoomStorageEntries(nsCSubstring const& aContextKey, + nsILoadContextInfo* aContext, + bool aDiskStorage, + bool aPin, + nsICacheEntryDoomCallback* aCallback); + nsresult AddStorageEntry(nsCSubstring const& aContextKey, + const nsACString & aURI, + const nsACString & aIdExtension, + bool aWriteToDisk, + bool aSkipSizeCheck, + bool aPin, + bool aReplace, + CacheEntryHandle** aResult); + + static CacheStorageService* sSelf; + + mozilla::Mutex mLock; + mozilla::Mutex mForcedValidEntriesLock; + + bool mShutdown; + + // Accessible only on the service thread + class MemoryPool + { + public: + enum EType + { + DISK, + MEMORY, + } mType; + + explicit MemoryPool(EType aType); + ~MemoryPool(); + + nsTArray<RefPtr<CacheEntry> > mFrecencyArray; + nsTArray<RefPtr<CacheEntry> > mExpirationArray; + Atomic<uint32_t, Relaxed> mMemorySize; + + bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize, + uint32_t aCurrentMemoryConsumption); + /** + * Purges entries from memory based on the frecency ordered array. + */ + void PurgeOverMemoryLimit(); + void PurgeExpired(); + void PurgeByFrecency(bool &aFrecencyNeedsSort, uint32_t aWhat); + void PurgeAll(uint32_t aWhat); + + private: + uint32_t Limit() const; + MemoryPool() = delete; + }; + + MemoryPool mDiskPool; + MemoryPool mMemoryPool; + TimeStamp mLastPurgeTime; + MemoryPool& Pool(bool aUsingDisk) + { + return aUsingDisk ? mDiskPool : mMemoryPool; + } + MemoryPool const& Pool(bool aUsingDisk) const + { + return aUsingDisk ? mDiskPool : mMemoryPool; + } + + nsCOMPtr<nsITimer> mPurgeTimer; + + class PurgeFromMemoryRunnable : public Runnable + { + public: + PurgeFromMemoryRunnable(CacheStorageService* aService, uint32_t aWhat) + : mService(aService), mWhat(aWhat) { } + + private: + virtual ~PurgeFromMemoryRunnable() { } + + NS_IMETHOD Run() override; + + RefPtr<CacheStorageService> mService; + uint32_t mWhat; + }; + + // Used just for telemetry purposes, accessed only on the management thread. + // Note: not included in the memory reporter, this is not expected to be huge + // and also would be complicated to report since reporting happens on the main + // thread but this table is manipulated on the management thread. + nsDataHashtable<nsCStringHashKey, mozilla::TimeStamp> mPurgeTimeStamps; + + // nsICacheTesting + class IOThreadSuspender : public Runnable + { + public: + IOThreadSuspender() : mMon("IOThreadSuspender"), mSignaled(false) { } + void Notify(); + private: + virtual ~IOThreadSuspender() { } + NS_IMETHOD Run() override; + + Monitor mMon; + bool mSignaled; + }; + + RefPtr<IOThreadSuspender> mActiveIOSuspender; +}; + +template<class T> +void ProxyRelease(nsCOMPtr<T> &object, nsIThread* thread) +{ + NS_ProxyRelease(thread, object.forget()); +} + +template<class T> +void ProxyReleaseMainThread(nsCOMPtr<T> &object) +{ + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + ProxyRelease(object, mainThread); +} + +} // namespace net +} // namespace mozilla + +#define NS_CACHE_STORAGE_SERVICE_CID \ + { 0xea70b098, 0x5014, 0x4e21, \ + { 0xae, 0xe1, 0x75, 0xe6, 0xb2, 0xc4, 0xb8, 0xe0 } } \ + +#define NS_CACHE_STORAGE_SERVICE_CONTRACTID \ + "@mozilla.org/netwerk/cache-storage-service;1" + +#define NS_CACHE_STORAGE_SERVICE_CONTRACTID2 \ + "@mozilla.org/network/cache-storage-service;1" + +#endif |