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/. */
5 #ifndef CacheEntry__h__
6 #define CacheEntry__h__
8 #include "nsICacheEntry.h"
11 #include "nsIRunnable.h"
12 #include "nsIOutputStream.h"
13 #include "nsICacheEntryOpenCallback.h"
14 #include "nsICacheEntryDoomCallback.h"
17 #include "nsRefPtrHashtable.h"
18 #include "nsDataHashtable.h"
19 #include "nsHashKeys.h"
21 #include "nsCOMArray.h"
22 #include "nsThreadUtils.h"
23 #include "mozilla/Attributes.h"
24 #include "mozilla/Mutex.h"
25 #include "mozilla/TimeStamp.h"
27 static inline uint32_t
28 PRTimeToSeconds(PRTime t_usec
)
30 PRTime usec_per_sec
= PR_USEC_PER_SEC
;
31 return uint32_t(t_usec
/= usec_per_sec
);
34 #define NowInSeconds() PRTimeToSeconds(PR_Now())
36 class nsIStorageStream
;
37 class nsIOutputStream
;
44 class CacheStorageService
;
46 class CacheFileOutputStream
;
47 class CacheOutputCloseListener
;
48 class CacheEntryHandle
;
50 class CacheEntry MOZ_FINAL
: public nsICacheEntry
52 , public CacheFileListener
55 NS_DECL_THREADSAFE_ISUPPORTS
59 CacheEntry(const nsACString
& aStorageID
, nsIURI
* aURI
, const nsACString
& aEnhanceID
,
62 void AsyncOpen(nsICacheEntryOpenCallback
* aCallback
, uint32_t aFlags
);
64 CacheEntryHandle
* NewHandle();
67 uint32_t GetMetadataMemoryConsumption();
68 nsCString
const &GetStorageID() const { return mStorageID
; }
69 nsCString
const &GetEnhanceID() const { return mEnhanceID
; }
70 nsIURI
* GetURI() const { return mURI
; }
71 // Accessible at any time
72 bool IsUsingDisk() const { return mUseDisk
; }
73 bool IsReferenced() const;
75 bool IsDoomed() const { return mIsDoomed
; }
77 // Methods for entry management (eviction from memory),
78 // called only on the management thread.
80 // TODO make these inline
81 double GetFrecency() const;
82 uint32_t GetExpirationTime() const;
83 uint32_t UseCount() const { return mUseCount
; }
85 bool IsRegistered() const;
86 bool CanRegister() const;
87 void SetRegistered(bool aRegistered
);
89 TimeStamp
const& LoadStart() const { return mLoadStart
; }
92 PURGE_DATA_ONLY_DISK_BACKED
,
93 PURGE_WHOLE_ONLY_DISK_BACKED
,
97 bool Purge(uint32_t aWhat
);
99 void DoomAlreadyRemoved();
101 nsresult
HashingKeyWithStorage(nsACString
&aResult
) const;
102 nsresult
HashingKey(nsACString
&aResult
) const;
104 static nsresult
HashingKey(nsCSubstring
const& aStorageID
,
105 nsCSubstring
const& aEnhanceID
,
107 nsACString
&aResult
);
109 static nsresult
HashingKey(nsCSubstring
const& aStorageID
,
110 nsCSubstring
const& aEnhanceID
,
111 nsCSubstring
const& aURISpec
,
112 nsACString
&aResult
);
114 // Accessed only on the service management thread
116 uint32_t mSortingExpirationTime
;
119 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
120 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
123 virtual ~CacheEntry();
126 NS_IMETHOD
OnFileReady(nsresult aResult
, bool aIsNew
);
127 NS_IMETHOD
OnFileDoomed(nsresult aResult
);
129 // Keep the service alive during life-time of an entry
130 nsRefPtr
<CacheStorageService
> mService
;
132 // We must monitor when a cache entry whose consumer is responsible
133 // for writing it the first time gets released. We must then invoke
134 // waiting callbacks to not break the chain.
138 Callback(CacheEntry
* aEntry
,
139 nsICacheEntryOpenCallback
*aCallback
,
140 bool aReadOnly
, bool aCheckOnAnyThread
);
141 Callback(Callback
const &aThat
);
144 // Called when this callback record changes it's owning entry,
145 // mainly during recreation.
146 void ExchangeEntry(CacheEntry
* aEntry
);
148 // We are raising reference count here to take into account the pending
149 // callback (that virtually holds a ref to this entry before it gets
151 nsRefPtr
<CacheEntry
> mEntry
;
152 nsCOMPtr
<nsICacheEntryOpenCallback
> mCallback
;
153 nsCOMPtr
<nsIThread
> mTargetThread
;
155 bool mCheckOnAnyThread
: 1;
156 bool mRecheckAfterWrite
: 1;
159 nsresult
OnCheckThread(bool *aOnCheckThread
) const;
160 nsresult
OnAvailThread(bool *aOnAvailThread
) const;
163 // Since OnCacheEntryAvailable must be invoked on the main thread
164 // we need a runnable for it...
165 class AvailableCallbackRunnable
: public nsRunnable
168 AvailableCallbackRunnable(CacheEntry
* aEntry
,
169 Callback
const &aCallback
)
171 , mCallback(aCallback
)
177 mEntry
->InvokeAvailableCallback(mCallback
);
181 nsRefPtr
<CacheEntry
> mEntry
;
185 // Since OnCacheEntryDoomed must be invoked on the main thread
186 // we need a runnable for it...
187 class DoomCallbackRunnable
: public nsRunnable
190 DoomCallbackRunnable(CacheEntry
* aEntry
, nsresult aRv
)
191 : mEntry(aEntry
), mRv(aRv
) {}
196 nsCOMPtr
<nsICacheEntryDoomCallback
> callback
;
198 mozilla::MutexAutoLock
lock(mEntry
->mLock
);
199 mEntry
->mDoomCallback
.swap(callback
);
203 callback
->OnCacheEntryDoomed(mRv
);
207 nsRefPtr
<CacheEntry
> mEntry
;
211 // Starts the load or just invokes the callback, bypasses (when required)
212 // if busy. Returns true on job done, false on bypass.
213 bool Open(Callback
& aCallback
, bool aTruncate
, bool aPriority
, bool aBypassIfBusy
);
214 // Loads from disk asynchronously
215 bool Load(bool aTruncate
, bool aPriority
);
218 void RememberCallback(Callback
& aCallback
);
219 void InvokeCallbacksLock();
220 void InvokeCallbacks();
221 bool InvokeCallbacks(bool aReadOnly
);
222 bool InvokeCallback(Callback
& aCallback
);
223 void InvokeAvailableCallback(Callback
const & aCallback
);
225 nsresult
OpenOutputStreamInternal(int64_t offset
, nsIOutputStream
* *_retval
);
227 // When this entry is new and recreated w/o a callback, we need to wrap it
228 // with a handle to detect writing consumer is gone.
229 CacheEntryHandle
* NewWriteHandle();
230 void OnHandleClosed(CacheEntryHandle
const* aHandle
);
233 friend class CacheEntryHandle
;
234 // Increment/decrements the number of handles keeping this entry.
235 void AddHandleRef() { ++mHandlesCount
; }
236 void ReleaseHandleRef() { --mHandlesCount
; }
237 // Current number of handles keeping this entry.
238 uint32_t HandlesCount() const { return mHandlesCount
; }
241 friend class CacheOutputCloseListener
;
242 void OnOutputClosed();
245 // Schedules a background operation on the management thread.
246 // When executed on the management thread directly, the operation(s)
247 // is (are) executed immediately.
248 void BackgroundOp(uint32_t aOperation
, bool aForceAsync
= false);
249 void StoreFrecency();
251 // Called only from DoomAlreadyRemoved()
254 already_AddRefed
<CacheEntryHandle
> ReopenTruncated(bool aMemoryOnly
,
255 nsICacheEntryOpenCallback
* aCallback
);
256 void TransferCallbacks(CacheEntry
& aFromEntry
);
258 mozilla::Mutex mLock
;
260 // Reflects the number of existing handles for this entry
261 ::mozilla::ThreadSafeAutoRefCnt mHandlesCount
;
263 nsTArray
<Callback
> mCallbacks
;
264 nsCOMPtr
<nsICacheEntryDoomCallback
> mDoomCallback
;
266 nsRefPtr
<CacheFile
> mFile
;
267 nsresult mFileStatus
;
268 nsCOMPtr
<nsIURI
> mURI
;
269 nsCString mEnhanceID
;
270 nsCString mStorageID
;
272 // Whether it's allowed to persist the data to disk
275 // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
276 // Left as a standalone flag to not bother with locking (there is no need).
279 // Following flags are all synchronized with the cache entry lock.
281 // Whether security info has already been looked up in metadata.
282 bool mSecurityInfoLoaded
: 1;
283 // Prevents any callback invocation
284 bool mPreventCallbacks
: 1;
285 // true: after load and an existing file, or after output stream has been opened.
286 // note - when opening an input stream, and this flag is false, output stream
287 // is open along ; this makes input streams on new entries behave correctly
288 // when EOF is reached (WOULD_BLOCK is returned).
289 // false: after load and a new file, or dropped to back to false when a writer
290 // fails to open an output stream.
294 static char const * StateString(uint32_t aState
);
297 enum EState
{ // transiting to:
298 NOTLOADED
= 0, // -> LOADING | EMPTY
299 LOADING
= 1, // -> EMPTY | READY
300 EMPTY
= 2, // -> WRITING
301 WRITING
= 3, // -> EMPTY | READY
302 READY
= 4, // -> REVALIDATING
303 REVALIDATING
= 5 // -> READY
306 // State of this entry.
310 NEVERREGISTERED
= 0, // The entry has never been registered
311 REGISTERED
= 1, // The entry is stored in the memory pool index
312 DEREGISTERED
= 2 // The entry has been removed from the pool
315 // Accessed only on the management thread. Records the state of registration
316 // this entry in the memory pool intermediate cache.
317 ERegistration mRegistration
;
319 // If a new (empty) entry is requested to open an input stream before
320 // output stream has been opened, we must open output stream internally
321 // on CacheFile and hold until writer releases the entry or opens the output
322 // stream for read (then we trade him mOutputStream).
323 nsCOMPtr
<nsIOutputStream
> mOutputStream
;
325 // Weak reference to the current writter. There can be more then one
326 // writer at a time and OnHandleClosed() must be processed only for the
328 CacheEntryHandle
* mWriter
;
330 // Background thread scheduled operation. Set (under the lock) one
331 // of this flags to tell the background thread what to do.
334 static uint32_t const REGISTER
= 1 << 0;
335 static uint32_t const FRECENCYUPDATE
= 1 << 1;
336 static uint32_t const CALLBACKS
= 1 << 2;
337 static uint32_t const UNREGISTER
= 1 << 3;
339 Ops() : mFlags(0) { }
340 uint32_t Grab() { uint32_t flags
= mFlags
; mFlags
= 0; return flags
; }
341 bool Set(uint32_t aFlags
) { if (mFlags
& aFlags
) return false; mFlags
|= aFlags
; return true; }
344 } mBackgroundOperations
;
346 nsCOMPtr
<nsISupports
> mSecurityInfo
;
347 int64_t mPredictedDataSize
;
348 mozilla::TimeStamp mLoadStart
;
350 nsCOMPtr
<nsIThread
> mReleaseThread
;
354 class CacheEntryHandle
: public nsICacheEntry
357 explicit CacheEntryHandle(CacheEntry
* aEntry
);
358 CacheEntry
* Entry() const { return mEntry
; }
360 NS_DECL_THREADSAFE_ISUPPORTS
361 NS_FORWARD_NSICACHEENTRY(mEntry
->)
363 virtual ~CacheEntryHandle();
364 nsRefPtr
<CacheEntry
> mEntry
;
368 class CacheOutputCloseListener MOZ_FINAL
: public nsRunnable
371 void OnOutputClosed();
374 friend class CacheEntry
;
376 virtual ~CacheOutputCloseListener();
379 explicit CacheOutputCloseListener(CacheEntry
* aEntry
);
382 nsRefPtr
<CacheEntry
> mEntry
;