1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/cache2/CacheEntry.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,383 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef CacheEntry__h__ 1.9 +#define CacheEntry__h__ 1.10 + 1.11 +#include "nsICacheEntry.h" 1.12 +#include "CacheFile.h" 1.13 + 1.14 +#include "nsIRunnable.h" 1.15 +#include "nsIOutputStream.h" 1.16 +#include "nsICacheEntryOpenCallback.h" 1.17 +#include "nsICacheEntryDoomCallback.h" 1.18 + 1.19 +#include "nsCOMPtr.h" 1.20 +#include "nsRefPtrHashtable.h" 1.21 +#include "nsDataHashtable.h" 1.22 +#include "nsHashKeys.h" 1.23 +#include "nsString.h" 1.24 +#include "nsCOMArray.h" 1.25 +#include "nsThreadUtils.h" 1.26 +#include "mozilla/Mutex.h" 1.27 +#include "mozilla/TimeStamp.h" 1.28 + 1.29 +static inline uint32_t 1.30 +PRTimeToSeconds(PRTime t_usec) 1.31 +{ 1.32 + PRTime usec_per_sec = PR_USEC_PER_SEC; 1.33 + return uint32_t(t_usec /= usec_per_sec); 1.34 +} 1.35 + 1.36 +#define NowInSeconds() PRTimeToSeconds(PR_Now()) 1.37 + 1.38 +class nsIStorageStream; 1.39 +class nsIOutputStream; 1.40 +class nsIURI; 1.41 +class nsIThread; 1.42 + 1.43 +namespace mozilla { 1.44 +namespace net { 1.45 + 1.46 +class CacheStorageService; 1.47 +class CacheStorage; 1.48 +class CacheFileOutputStream; 1.49 +class CacheOutputCloseListener; 1.50 +class CacheEntryHandle; 1.51 + 1.52 +class CacheEntry : public nsICacheEntry 1.53 + , public nsIRunnable 1.54 + , public CacheFileListener 1.55 +{ 1.56 +public: 1.57 + NS_DECL_THREADSAFE_ISUPPORTS 1.58 + NS_DECL_NSICACHEENTRY 1.59 + NS_DECL_NSIRUNNABLE 1.60 + 1.61 + CacheEntry(const nsACString& aStorageID, nsIURI* aURI, const nsACString& aEnhanceID, 1.62 + bool aUseDisk); 1.63 + 1.64 + void AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags); 1.65 + 1.66 + CacheEntryHandle* NewHandle(); 1.67 + 1.68 +public: 1.69 + uint32_t GetMetadataMemoryConsumption(); 1.70 + nsCString const &GetStorageID() const { return mStorageID; } 1.71 + nsCString const &GetEnhanceID() const { return mEnhanceID; } 1.72 + nsIURI* GetURI() const { return mURI; } 1.73 + // Accessible only under the CacheStorageService lock (asserts it) 1.74 + bool IsUsingDiskLocked() const; 1.75 + // Accessible at any time 1.76 + bool IsUsingDisk() const { return mUseDisk; } 1.77 + bool SetUsingDisk(bool aUsingDisk); 1.78 + bool IsReferenced() const; 1.79 + bool IsFileDoomed(); 1.80 + 1.81 + // Methods for entry management (eviction from memory), 1.82 + // called only on the management thread. 1.83 + 1.84 + // TODO make these inline 1.85 + double GetFrecency() const; 1.86 + uint32_t GetExpirationTime() const; 1.87 + 1.88 + bool IsRegistered() const; 1.89 + bool CanRegister() const; 1.90 + void SetRegistered(bool aRegistered); 1.91 + 1.92 + enum EPurge { 1.93 + PURGE_DATA_ONLY_DISK_BACKED, 1.94 + PURGE_WHOLE_ONLY_DISK_BACKED, 1.95 + PURGE_WHOLE, 1.96 + }; 1.97 + 1.98 + bool Purge(uint32_t aWhat); 1.99 + void PurgeAndDoom(); 1.100 + void DoomAlreadyRemoved(); 1.101 + 1.102 + nsresult HashingKeyWithStorage(nsACString &aResult); 1.103 + nsresult HashingKey(nsACString &aResult); 1.104 + 1.105 + static nsresult HashingKey(nsCSubstring const& aStorageID, 1.106 + nsCSubstring const& aEnhanceID, 1.107 + nsIURI* aURI, 1.108 + nsACString &aResult); 1.109 + 1.110 + static nsresult HashingKey(nsCSubstring const& aStorageID, 1.111 + nsCSubstring const& aEnhanceID, 1.112 + nsCSubstring const& aURISpec, 1.113 + nsACString &aResult); 1.114 + 1.115 + // Accessed only on the service management thread 1.116 + double mFrecency; 1.117 + uint32_t mSortingExpirationTime; 1.118 + 1.119 + // Memory reporting 1.120 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 1.121 + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 1.122 + 1.123 +private: 1.124 + virtual ~CacheEntry(); 1.125 + 1.126 + // CacheFileListener 1.127 + NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew); 1.128 + NS_IMETHOD OnFileDoomed(nsresult aResult); 1.129 + 1.130 + // Keep the service alive during life-time of an entry 1.131 + nsRefPtr<CacheStorageService> mService; 1.132 + 1.133 + // We must monitor when a cache entry whose consumer is responsible 1.134 + // for writing it the first time gets released. We must then invoke 1.135 + // waiting callbacks to not break the chain. 1.136 + class Callback 1.137 + { 1.138 + public: 1.139 + Callback(CacheEntry* aEntry, 1.140 + nsICacheEntryOpenCallback *aCallback, 1.141 + bool aReadOnly, bool aCheckOnAnyThread); 1.142 + Callback(Callback const &aThat); 1.143 + ~Callback(); 1.144 + 1.145 + // Called when this callback record changes it's owning entry, 1.146 + // mainly during recreation. 1.147 + void ExchangeEntry(CacheEntry* aEntry); 1.148 + 1.149 + // We are raising reference count here to take into account the pending 1.150 + // callback (that virtually holds a ref to this entry before it gets 1.151 + // it's pointer). 1.152 + nsRefPtr<CacheEntry> mEntry; 1.153 + nsCOMPtr<nsICacheEntryOpenCallback> mCallback; 1.154 + nsCOMPtr<nsIThread> mTargetThread; 1.155 + bool mReadOnly : 1; 1.156 + bool mCheckOnAnyThread : 1; 1.157 + bool mRecheckAfterWrite : 1; 1.158 + bool mNotWanted : 1; 1.159 + 1.160 + nsresult OnCheckThread(bool *aOnCheckThread) const; 1.161 + nsresult OnAvailThread(bool *aOnAvailThread) const; 1.162 + }; 1.163 + 1.164 + // Since OnCacheEntryAvailable must be invoked on the main thread 1.165 + // we need a runnable for it... 1.166 + class AvailableCallbackRunnable : public nsRunnable 1.167 + { 1.168 + public: 1.169 + AvailableCallbackRunnable(CacheEntry* aEntry, 1.170 + Callback const &aCallback) 1.171 + : mEntry(aEntry) 1.172 + , mCallback(aCallback) 1.173 + {} 1.174 + 1.175 + private: 1.176 + NS_IMETHOD Run() 1.177 + { 1.178 + mEntry->InvokeAvailableCallback(mCallback); 1.179 + return NS_OK; 1.180 + } 1.181 + 1.182 + nsRefPtr<CacheEntry> mEntry; 1.183 + Callback mCallback; 1.184 + }; 1.185 + 1.186 + // Since OnCacheEntryDoomed must be invoked on the main thread 1.187 + // we need a runnable for it... 1.188 + class DoomCallbackRunnable : public nsRunnable 1.189 + { 1.190 + public: 1.191 + DoomCallbackRunnable(CacheEntry* aEntry, nsresult aRv) 1.192 + : mEntry(aEntry), mRv(aRv) {} 1.193 + 1.194 + private: 1.195 + NS_IMETHOD Run() 1.196 + { 1.197 + nsCOMPtr<nsICacheEntryDoomCallback> callback; 1.198 + { 1.199 + mozilla::MutexAutoLock lock(mEntry->mLock); 1.200 + mEntry->mDoomCallback.swap(callback); 1.201 + } 1.202 + 1.203 + if (callback) 1.204 + callback->OnCacheEntryDoomed(mRv); 1.205 + return NS_OK; 1.206 + } 1.207 + 1.208 + nsRefPtr<CacheEntry> mEntry; 1.209 + nsresult mRv; 1.210 + }; 1.211 + 1.212 + // Loads from disk asynchronously 1.213 + bool Load(bool aTruncate, bool aPriority); 1.214 + void OnLoaded(); 1.215 + 1.216 + void RememberCallback(Callback const & aCallback); 1.217 + void InvokeCallbacksLock(); 1.218 + void InvokeCallbacks(); 1.219 + bool InvokeCallbacks(bool aReadOnly); 1.220 + bool InvokeCallback(Callback & aCallback); 1.221 + void InvokeAvailableCallback(Callback const & aCallback); 1.222 + 1.223 + nsresult OpenOutputStreamInternal(int64_t offset, nsIOutputStream * *_retval); 1.224 + 1.225 + // When this entry is new and recreated w/o a callback, we need to wrap it 1.226 + // with a handle to detect writing consumer is gone. 1.227 + CacheEntryHandle* NewWriteHandle(); 1.228 + void OnHandleClosed(CacheEntryHandle const* aHandle); 1.229 + 1.230 +private: 1.231 + friend class CacheEntryHandle; 1.232 + // Increment/decrements the number of handles keeping this entry. 1.233 + void AddHandleRef() { ++mHandlesCount; } 1.234 + void ReleaseHandleRef() { --mHandlesCount; } 1.235 + // Current number of handles keeping this entry. 1.236 + uint32_t HandlesCount() const { return mHandlesCount; } 1.237 + 1.238 +private: 1.239 + friend class CacheOutputCloseListener; 1.240 + void OnOutputClosed(); 1.241 + 1.242 +private: 1.243 + // Schedules a background operation on the management thread. 1.244 + // When executed on the management thread directly, the operation(s) 1.245 + // is (are) executed immediately. 1.246 + void BackgroundOp(uint32_t aOperation, bool aForceAsync = false); 1.247 + void StoreFrecency(); 1.248 + 1.249 + // Called only from DoomAlreadyRemoved() 1.250 + void DoomFile(); 1.251 + 1.252 + already_AddRefed<CacheEntryHandle> ReopenTruncated(bool aMemoryOnly, 1.253 + nsICacheEntryOpenCallback* aCallback); 1.254 + void TransferCallbacks(CacheEntry & aFromEntry); 1.255 + 1.256 + mozilla::Mutex mLock; 1.257 + 1.258 + // Reflects the number of existing handles for this entry 1.259 + ::mozilla::ThreadSafeAutoRefCnt mHandlesCount; 1.260 + 1.261 + nsTArray<Callback> mCallbacks; 1.262 + nsCOMPtr<nsICacheEntryDoomCallback> mDoomCallback; 1.263 + 1.264 + nsRefPtr<CacheFile> mFile; 1.265 + nsresult mFileStatus; 1.266 + nsCOMPtr<nsIURI> mURI; 1.267 + nsCString mEnhanceID; 1.268 + nsCString mStorageID; 1.269 + 1.270 + // Whether it's allowed to persist the data to disk 1.271 + // Synchronized by the service management lock. 1.272 + // Hence, leave it as a standalone boolean. 1.273 + bool mUseDisk; 1.274 + 1.275 + // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved(). 1.276 + // Left as a standalone flag to not bother with locking (there is no need). 1.277 + bool mIsDoomed; 1.278 + 1.279 + // Following flags are all synchronized with the cache entry lock. 1.280 + 1.281 + // Whether security info has already been looked up in metadata. 1.282 + bool mSecurityInfoLoaded : 1; 1.283 + // Prevents any callback invocation 1.284 + bool mPreventCallbacks : 1; 1.285 + // true: after load and an existing file, or after output stream has been opened. 1.286 + // note - when opening an input stream, and this flag is false, output stream 1.287 + // is open along ; this makes input streams on new entries behave correctly 1.288 + // when EOF is reached (WOULD_BLOCK is returned). 1.289 + // false: after load and a new file, or dropped to back to false when a writer 1.290 + // fails to open an output stream. 1.291 + bool mHasData : 1; 1.292 + 1.293 +#ifdef PR_LOG 1.294 + static char const * StateString(uint32_t aState); 1.295 +#endif 1.296 + 1.297 + enum EState { // transiting to: 1.298 + NOTLOADED = 0, // -> LOADING | EMPTY 1.299 + LOADING = 1, // -> EMPTY | READY 1.300 + EMPTY = 2, // -> WRITING 1.301 + WRITING = 3, // -> EMPTY | READY 1.302 + READY = 4, // -> REVALIDATING 1.303 + REVALIDATING = 5 // -> READY 1.304 + }; 1.305 + 1.306 + // State of this entry. 1.307 + EState mState; 1.308 + 1.309 + enum ERegistration { 1.310 + NEVERREGISTERED = 0, // The entry has never been registered 1.311 + REGISTERED = 1, // The entry is stored in the memory pool index 1.312 + DEREGISTERED = 2 // The entry has been removed from the pool 1.313 + }; 1.314 + 1.315 + // Accessed only on the management thread. Records the state of registration 1.316 + // this entry in the memory pool intermediate cache. 1.317 + ERegistration mRegistration; 1.318 + 1.319 + // If a new (empty) entry is requested to open an input stream before 1.320 + // output stream has been opened, we must open output stream internally 1.321 + // on CacheFile and hold until writer releases the entry or opens the output 1.322 + // stream for read (then we trade him mOutputStream). 1.323 + nsCOMPtr<nsIOutputStream> mOutputStream; 1.324 + 1.325 + // Weak reference to the current writter. There can be more then one 1.326 + // writer at a time and OnHandleClosed() must be processed only for the 1.327 + // current one. 1.328 + CacheEntryHandle* mWriter; 1.329 + 1.330 + // Background thread scheduled operation. Set (under the lock) one 1.331 + // of this flags to tell the background thread what to do. 1.332 + class Ops { 1.333 + public: 1.334 + static uint32_t const REGISTER = 1 << 0; 1.335 + static uint32_t const FRECENCYUPDATE = 1 << 1; 1.336 + static uint32_t const CALLBACKS = 1 << 2; 1.337 + static uint32_t const UNREGISTER = 1 << 3; 1.338 + 1.339 + Ops() : mFlags(0) { } 1.340 + uint32_t Grab() { uint32_t flags = mFlags; mFlags = 0; return flags; } 1.341 + bool Set(uint32_t aFlags) { if (mFlags & aFlags) return false; mFlags |= aFlags; return true; } 1.342 + private: 1.343 + uint32_t mFlags; 1.344 + } mBackgroundOperations; 1.345 + 1.346 + nsCOMPtr<nsISupports> mSecurityInfo; 1.347 + int64_t mPredictedDataSize; 1.348 + mozilla::TimeStamp mLoadStart; 1.349 + nsCOMPtr<nsIThread> mReleaseThread; 1.350 +}; 1.351 + 1.352 + 1.353 +class CacheEntryHandle : public nsICacheEntry 1.354 +{ 1.355 +public: 1.356 + CacheEntryHandle(CacheEntry* aEntry); 1.357 + virtual ~CacheEntryHandle(); 1.358 + CacheEntry* Entry() const { return mEntry; } 1.359 + 1.360 + NS_DECL_THREADSAFE_ISUPPORTS 1.361 + NS_FORWARD_NSICACHEENTRY(mEntry->) 1.362 +private: 1.363 + nsRefPtr<CacheEntry> mEntry; 1.364 +}; 1.365 + 1.366 + 1.367 +class CacheOutputCloseListener : public nsRunnable 1.368 +{ 1.369 +public: 1.370 + void OnOutputClosed(); 1.371 + virtual ~CacheOutputCloseListener(); 1.372 + 1.373 +private: 1.374 + friend class CacheEntry; 1.375 + 1.376 + NS_DECL_NSIRUNNABLE 1.377 + CacheOutputCloseListener(CacheEntry* aEntry); 1.378 + 1.379 +private: 1.380 + nsRefPtr<CacheEntry> mEntry; 1.381 +}; 1.382 + 1.383 +} // net 1.384 +} // mozilla 1.385 + 1.386 +#endif