CacheEntry.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #ifndef CacheEntry__h__
  5. #define CacheEntry__h__
  6. #include "nsICacheEntry.h"
  7. #include "CacheFile.h"
  8. #include "nsIRunnable.h"
  9. #include "nsIOutputStream.h"
  10. #include "nsICacheEntryOpenCallback.h"
  11. #include "nsICacheEntryDoomCallback.h"
  12. #include "nsCOMPtr.h"
  13. #include "nsRefPtrHashtable.h"
  14. #include "nsDataHashtable.h"
  15. #include "nsHashKeys.h"
  16. #include "nsString.h"
  17. #include "nsCOMArray.h"
  18. #include "nsThreadUtils.h"
  19. #include "mozilla/Attributes.h"
  20. #include "mozilla/Mutex.h"
  21. #include "mozilla/TimeStamp.h"
  22. static inline uint32_t
  23. PRTimeToSeconds(PRTime t_usec)
  24. {
  25. PRTime usec_per_sec = PR_USEC_PER_SEC;
  26. return uint32_t(t_usec /= usec_per_sec);
  27. }
  28. #define NowInSeconds() PRTimeToSeconds(PR_Now())
  29. class nsIOutputStream;
  30. class nsIURI;
  31. class nsIThread;
  32. namespace mozilla {
  33. namespace net {
  34. class CacheStorageService;
  35. class CacheStorage;
  36. class CacheOutputCloseListener;
  37. class CacheEntryHandle;
  38. class CacheEntry final : public nsICacheEntry
  39. , public nsIRunnable
  40. , public CacheFileListener
  41. {
  42. public:
  43. NS_DECL_THREADSAFE_ISUPPORTS
  44. NS_DECL_NSICACHEENTRY
  45. NS_DECL_NSIRUNNABLE
  46. CacheEntry(const nsACString& aStorageID, const nsACString& aURI, const nsACString& aEnhanceID,
  47. bool aUseDisk, bool aSkipSizeCheck, bool aPin);
  48. void AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags);
  49. CacheEntryHandle* NewHandle();
  50. // For a new and recreated entry w/o a callback, we need to wrap it
  51. // with a handle to detect writing consumer is gone.
  52. CacheEntryHandle* NewWriteHandle();
  53. public:
  54. uint32_t GetMetadataMemoryConsumption();
  55. nsCString const &GetStorageID() const { return mStorageID; }
  56. nsCString const &GetEnhanceID() const { return mEnhanceID; }
  57. nsCString const &GetURI() const { return mURI; }
  58. // Accessible at any time
  59. bool IsUsingDisk() const { return mUseDisk; }
  60. bool IsReferenced() const;
  61. bool IsFileDoomed();
  62. bool IsDoomed() const { return mIsDoomed; }
  63. bool IsPinned() const { return mPinned; }
  64. // Methods for entry management (eviction from memory),
  65. // called only on the management thread.
  66. // TODO make these inline
  67. double GetFrecency() const;
  68. uint32_t GetExpirationTime() const;
  69. uint32_t UseCount() const { return mUseCount; }
  70. bool IsRegistered() const;
  71. bool CanRegister() const;
  72. void SetRegistered(bool aRegistered);
  73. TimeStamp const& LoadStart() const { return mLoadStart; }
  74. enum EPurge {
  75. PURGE_DATA_ONLY_DISK_BACKED,
  76. PURGE_WHOLE_ONLY_DISK_BACKED,
  77. PURGE_WHOLE,
  78. };
  79. bool DeferOrBypassRemovalOnPinStatus(bool aPinned);
  80. bool Purge(uint32_t aWhat);
  81. void PurgeAndDoom();
  82. void DoomAlreadyRemoved();
  83. nsresult HashingKeyWithStorage(nsACString &aResult) const;
  84. nsresult HashingKey(nsACString &aResult) const;
  85. static nsresult HashingKey(nsCSubstring const& aStorageID,
  86. nsCSubstring const& aEnhanceID,
  87. nsIURI* aURI,
  88. nsACString &aResult);
  89. static nsresult HashingKey(nsCSubstring const& aStorageID,
  90. nsCSubstring const& aEnhanceID,
  91. nsCSubstring const& aURISpec,
  92. nsACString &aResult);
  93. // Accessed only on the service management thread
  94. double mFrecency;
  95. ::mozilla::Atomic<uint32_t, ::mozilla::Relaxed> mSortingExpirationTime;
  96. // Memory reporting
  97. size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
  98. size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
  99. private:
  100. virtual ~CacheEntry();
  101. // CacheFileListener
  102. NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew) override;
  103. NS_IMETHOD OnFileDoomed(nsresult aResult) override;
  104. // Keep the service alive during life-time of an entry
  105. RefPtr<CacheStorageService> mService;
  106. // We must monitor when a cache entry whose consumer is responsible
  107. // for writing it the first time gets released. We must then invoke
  108. // waiting callbacks to not break the chain.
  109. class Callback
  110. {
  111. public:
  112. Callback(CacheEntry* aEntry,
  113. nsICacheEntryOpenCallback *aCallback,
  114. bool aReadOnly, bool aCheckOnAnyThread, bool aSecret);
  115. // Special constructor for Callback objects added to the chain
  116. // just to ensure proper defer dooming (recreation) of this entry.
  117. Callback(CacheEntry* aEntry, bool aDoomWhenFoundInPinStatus);
  118. Callback(Callback const &aThat);
  119. ~Callback();
  120. // Called when this callback record changes it's owning entry,
  121. // mainly during recreation.
  122. void ExchangeEntry(CacheEntry* aEntry);
  123. // Returns true when an entry is about to be "defer" doomed and this is
  124. // a "defer" callback.
  125. bool DeferDoom(bool *aDoom) const;
  126. // We are raising reference count here to take into account the pending
  127. // callback (that virtually holds a ref to this entry before it gets
  128. // it's pointer).
  129. RefPtr<CacheEntry> mEntry;
  130. nsCOMPtr<nsICacheEntryOpenCallback> mCallback;
  131. nsCOMPtr<nsIThread> mTargetThread;
  132. bool mReadOnly : 1;
  133. bool mRevalidating : 1;
  134. bool mCheckOnAnyThread : 1;
  135. bool mRecheckAfterWrite : 1;
  136. bool mNotWanted : 1;
  137. bool mSecret : 1;
  138. // These are set only for the defer-doomer Callback instance inserted
  139. // to the callback chain. When any of these is set and also any of
  140. // the corressponding flags on the entry is set, this callback will
  141. // indicate (via DeferDoom()) the entry have to be recreated/doomed.
  142. bool mDoomWhenFoundPinned : 1;
  143. bool mDoomWhenFoundNonPinned : 1;
  144. nsresult OnCheckThread(bool *aOnCheckThread) const;
  145. nsresult OnAvailThread(bool *aOnAvailThread) const;
  146. };
  147. // Since OnCacheEntryAvailable must be invoked on the main thread
  148. // we need a runnable for it...
  149. class AvailableCallbackRunnable : public Runnable
  150. {
  151. public:
  152. AvailableCallbackRunnable(CacheEntry* aEntry,
  153. Callback const &aCallback)
  154. : mEntry(aEntry)
  155. , mCallback(aCallback)
  156. {}
  157. private:
  158. NS_IMETHOD Run() override
  159. {
  160. mEntry->InvokeAvailableCallback(mCallback);
  161. return NS_OK;
  162. }
  163. RefPtr<CacheEntry> mEntry;
  164. Callback mCallback;
  165. };
  166. // Since OnCacheEntryDoomed must be invoked on the main thread
  167. // we need a runnable for it...
  168. class DoomCallbackRunnable : public Runnable
  169. {
  170. public:
  171. DoomCallbackRunnable(CacheEntry* aEntry, nsresult aRv)
  172. : mEntry(aEntry), mRv(aRv) {}
  173. private:
  174. NS_IMETHOD Run() override
  175. {
  176. nsCOMPtr<nsICacheEntryDoomCallback> callback;
  177. {
  178. mozilla::MutexAutoLock lock(mEntry->mLock);
  179. mEntry->mDoomCallback.swap(callback);
  180. }
  181. if (callback)
  182. callback->OnCacheEntryDoomed(mRv);
  183. return NS_OK;
  184. }
  185. RefPtr<CacheEntry> mEntry;
  186. nsresult mRv;
  187. };
  188. // Starts the load or just invokes the callback, bypasses (when required)
  189. // if busy. Returns true on job done, false on bypass.
  190. bool Open(Callback & aCallback, bool aTruncate, bool aPriority, bool aBypassIfBusy);
  191. // Loads from disk asynchronously
  192. bool Load(bool aTruncate, bool aPriority);
  193. void RememberCallback(Callback & aCallback);
  194. void InvokeCallbacksLock();
  195. void InvokeCallbacks();
  196. bool InvokeCallbacks(bool aReadOnly);
  197. bool InvokeCallback(Callback & aCallback);
  198. void InvokeAvailableCallback(Callback const & aCallback);
  199. void OnFetched(Callback const & aCallback);
  200. nsresult OpenOutputStreamInternal(int64_t offset, nsIOutputStream * *_retval);
  201. nsresult OpenInputStreamInternal(int64_t offset, const char *aAltDataType, nsIInputStream * *_retval);
  202. void OnHandleClosed(CacheEntryHandle const* aHandle);
  203. private:
  204. friend class CacheEntryHandle;
  205. // Increment/decrements the number of handles keeping this entry.
  206. void AddHandleRef() { ++mHandlesCount; }
  207. void ReleaseHandleRef() { --mHandlesCount; }
  208. // Current number of handles keeping this entry.
  209. uint32_t HandlesCount() const { return mHandlesCount; }
  210. private:
  211. friend class CacheOutputCloseListener;
  212. void OnOutputClosed();
  213. private:
  214. // Schedules a background operation on the management thread.
  215. // When executed on the management thread directly, the operation(s)
  216. // is (are) executed immediately.
  217. void BackgroundOp(uint32_t aOperation, bool aForceAsync = false);
  218. void StoreFrecency(double aFrecency);
  219. // Called only from DoomAlreadyRemoved()
  220. void DoomFile();
  221. // When this entry is doomed the first time, this method removes
  222. // any force-valid timing info for this entry.
  223. void RemoveForcedValidity();
  224. already_AddRefed<CacheEntryHandle> ReopenTruncated(bool aMemoryOnly,
  225. nsICacheEntryOpenCallback* aCallback);
  226. void TransferCallbacks(CacheEntry & aFromEntry);
  227. mozilla::Mutex mLock;
  228. // Reflects the number of existing handles for this entry
  229. ::mozilla::ThreadSafeAutoRefCnt mHandlesCount;
  230. nsTArray<Callback> mCallbacks;
  231. nsCOMPtr<nsICacheEntryDoomCallback> mDoomCallback;
  232. RefPtr<CacheFile> mFile;
  233. // Using ReleaseAcquire since we only control access to mFile with this.
  234. // When mFileStatus is read and found success it is ensured there is mFile and
  235. // that it is after a successful call to Init().
  236. ::mozilla::Atomic<nsresult, ::mozilla::ReleaseAcquire> mFileStatus;
  237. nsCString mURI;
  238. nsCString mEnhanceID;
  239. nsCString mStorageID;
  240. // mUseDisk, mSkipSizeCheck, mIsDoomed are plain "bool", not "bool:1",
  241. // so as to avoid bitfield races with the byte containing
  242. // mSecurityInfoLoaded et al. See bug 1278524.
  243. //
  244. // Whether it's allowed to persist the data to disk
  245. bool const mUseDisk;
  246. // Whether it should skip max size check.
  247. bool const mSkipSizeCheck;
  248. // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
  249. bool mIsDoomed;
  250. // Following flags are all synchronized with the cache entry lock.
  251. // Whether security info has already been looked up in metadata.
  252. bool mSecurityInfoLoaded : 1;
  253. // Prevents any callback invocation
  254. bool mPreventCallbacks : 1;
  255. // true: after load and an existing file, or after output stream has been opened.
  256. // note - when opening an input stream, and this flag is false, output stream
  257. // is open along ; this makes input streams on new entries behave correctly
  258. // when EOF is reached (WOULD_BLOCK is returned).
  259. // false: after load and a new file, or dropped to back to false when a writer
  260. // fails to open an output stream.
  261. bool mHasData : 1;
  262. // The indication of pinning this entry was open with
  263. bool mPinned : 1;
  264. // Whether the pinning state of the entry is known (equals to the actual state
  265. // of the cache file)
  266. bool mPinningKnown : 1;
  267. static char const * StateString(uint32_t aState);
  268. enum EState { // transiting to:
  269. NOTLOADED = 0, // -> LOADING | EMPTY
  270. LOADING = 1, // -> EMPTY | READY
  271. EMPTY = 2, // -> WRITING
  272. WRITING = 3, // -> EMPTY | READY
  273. READY = 4, // -> REVALIDATING
  274. REVALIDATING = 5 // -> READY
  275. };
  276. // State of this entry.
  277. EState mState;
  278. enum ERegistration {
  279. NEVERREGISTERED = 0, // The entry has never been registered
  280. REGISTERED = 1, // The entry is stored in the memory pool index
  281. DEREGISTERED = 2 // The entry has been removed from the pool
  282. };
  283. // Accessed only on the management thread. Records the state of registration
  284. // this entry in the memory pool intermediate cache.
  285. ERegistration mRegistration;
  286. // If a new (empty) entry is requested to open an input stream before
  287. // output stream has been opened, we must open output stream internally
  288. // on CacheFile and hold until writer releases the entry or opens the output
  289. // stream for read (then we trade him mOutputStream).
  290. nsCOMPtr<nsIOutputStream> mOutputStream;
  291. // Weak reference to the current writter. There can be more then one
  292. // writer at a time and OnHandleClosed() must be processed only for the
  293. // current one.
  294. CacheEntryHandle* mWriter;
  295. // Background thread scheduled operation. Set (under the lock) one
  296. // of this flags to tell the background thread what to do.
  297. class Ops {
  298. public:
  299. static uint32_t const REGISTER = 1 << 0;
  300. static uint32_t const FRECENCYUPDATE = 1 << 1;
  301. static uint32_t const CALLBACKS = 1 << 2;
  302. static uint32_t const UNREGISTER = 1 << 3;
  303. Ops() : mFlags(0) { }
  304. uint32_t Grab() { uint32_t flags = mFlags; mFlags = 0; return flags; }
  305. bool Set(uint32_t aFlags) { if (mFlags & aFlags) return false; mFlags |= aFlags; return true; }
  306. private:
  307. uint32_t mFlags;
  308. } mBackgroundOperations;
  309. nsCOMPtr<nsISupports> mSecurityInfo;
  310. int64_t mPredictedDataSize;
  311. mozilla::TimeStamp mLoadStart;
  312. uint32_t mUseCount;
  313. };
  314. class CacheEntryHandle : public nsICacheEntry
  315. {
  316. public:
  317. explicit CacheEntryHandle(CacheEntry* aEntry);
  318. CacheEntry* Entry() const { return mEntry; }
  319. NS_DECL_THREADSAFE_ISUPPORTS
  320. NS_FORWARD_NSICACHEENTRY(mEntry->)
  321. private:
  322. virtual ~CacheEntryHandle();
  323. RefPtr<CacheEntry> mEntry;
  324. };
  325. class CacheOutputCloseListener final : public Runnable
  326. {
  327. public:
  328. void OnOutputClosed();
  329. private:
  330. friend class CacheEntry;
  331. virtual ~CacheOutputCloseListener();
  332. NS_DECL_NSIRUNNABLE
  333. explicit CacheOutputCloseListener(CacheEntry* aEntry);
  334. private:
  335. RefPtr<CacheEntry> mEntry;
  336. };
  337. } // namespace net
  338. } // namespace mozilla
  339. #endif