Line data Source code
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 :
5 : #ifndef CacheFile__h__
6 : #define CacheFile__h__
7 :
8 : #include "CacheFileChunk.h"
9 : #include "CacheFileIOManager.h"
10 : #include "CacheFileMetadata.h"
11 : #include "nsRefPtrHashtable.h"
12 : #include "nsClassHashtable.h"
13 : #include "mozilla/Mutex.h"
14 :
15 : class nsIInputStream;
16 : class nsIOutputStream;
17 : class nsICacheEntryMetaDataVisitor;
18 :
19 : namespace mozilla {
20 : namespace net {
21 :
22 : class CacheFileInputStream;
23 : class CacheFileOutputStream;
24 : class CacheOutputCloseListener;
25 : class MetadataWriteTimer;
26 :
27 : #define CACHEFILELISTENER_IID \
28 : { /* 95e7f284-84ba-48f9-b1fc-3a7336b4c33c */ \
29 : 0x95e7f284, \
30 : 0x84ba, \
31 : 0x48f9, \
32 : {0xb1, 0xfc, 0x3a, 0x73, 0x36, 0xb4, 0xc3, 0x3c} \
33 : }
34 :
35 5 : class CacheFileListener : public nsISupports
36 : {
37 : public:
38 : NS_DECLARE_STATIC_IID_ACCESSOR(CACHEFILELISTENER_IID)
39 :
40 : NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew) = 0;
41 : NS_IMETHOD OnFileDoomed(nsresult aResult) = 0;
42 : };
43 :
44 : NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileListener, CACHEFILELISTENER_IID)
45 :
46 :
47 : class CacheFile final : public CacheFileChunkListener
48 : , public CacheFileIOListener
49 : , public CacheFileMetadataListener
50 : {
51 : public:
52 : NS_DECL_THREADSAFE_ISUPPORTS
53 :
54 : CacheFile();
55 :
56 : nsresult Init(const nsACString &aKey,
57 : bool aCreateNew,
58 : bool aMemoryOnly,
59 : bool aSkipSizeCheck,
60 : bool aPriority,
61 : bool aPinned,
62 : CacheFileListener *aCallback);
63 :
64 : NS_IMETHOD OnChunkRead(nsresult aResult, CacheFileChunk *aChunk) override;
65 : NS_IMETHOD OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk) override;
66 : NS_IMETHOD OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
67 : CacheFileChunk *aChunk) override;
68 : NS_IMETHOD OnChunkUpdated(CacheFileChunk *aChunk) override;
69 :
70 : NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) override;
71 : NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
72 : nsresult aResult) override;
73 : NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult) override;
74 : NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) override;
75 : NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) override;
76 : NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) override;
77 : virtual bool IsKilled() override;
78 :
79 : NS_IMETHOD OnMetadataRead(nsresult aResult) override;
80 : NS_IMETHOD OnMetadataWritten(nsresult aResult) override;
81 :
82 : NS_IMETHOD OpenInputStream(nsICacheEntry *aCacheEntryHandle, nsIInputStream **_retval);
83 : NS_IMETHOD OpenAlternativeInputStream(nsICacheEntry *aCacheEntryHandle,
84 : const char *aAltDataType, nsIInputStream **_retval);
85 : NS_IMETHOD OpenOutputStream(CacheOutputCloseListener *aCloseListener, nsIOutputStream **_retval);
86 : NS_IMETHOD OpenAlternativeOutputStream(CacheOutputCloseListener *aCloseListener,
87 : const char *aAltDataType, nsIOutputStream **_retval);
88 : NS_IMETHOD SetMemoryOnly();
89 : NS_IMETHOD Doom(CacheFileListener *aCallback);
90 :
91 0 : void Kill() { mKill = true; }
92 : nsresult ThrowMemoryCachedData();
93 :
94 : nsresult GetAltDataSize(int64_t *aSize);
95 :
96 : // metadata forwarders
97 : nsresult GetElement(const char *aKey, char **_retval);
98 : nsresult SetElement(const char *aKey, const char *aValue);
99 : nsresult VisitMetaData(nsICacheEntryMetaDataVisitor *aVisitor);
100 : nsresult ElementsSize(uint32_t *_retval);
101 : nsresult SetExpirationTime(uint32_t aExpirationTime);
102 : nsresult GetExpirationTime(uint32_t *_retval);
103 : nsresult SetFrecency(uint32_t aFrecency);
104 : nsresult GetFrecency(uint32_t *_retval);
105 : nsresult SetNetworkTimes(uint64_t aOnStartTime, uint64_t aOnStopTime);
106 : nsresult GetOnStartTime(uint64_t *_retval);
107 : nsresult GetOnStopTime(uint64_t *_retval);
108 : nsresult GetLastModified(uint32_t *_retval);
109 : nsresult GetLastFetched(uint32_t *_retval);
110 : nsresult GetFetchCount(uint32_t *_retval);
111 : nsresult GetDiskStorageSizeInKB(uint32_t *aDiskStorageSize);
112 : // Called by upper layers to indicated the entry has been fetched,
113 : // i.e. delivered to the consumer.
114 : nsresult OnFetched();
115 :
116 : bool DataSize(int64_t* aSize);
117 : void Key(nsACString& aKey) { aKey = mKey; }
118 : bool IsDoomed();
119 5 : bool IsPinned() const { return mPinned; }
120 : bool IsWriteInProgress();
121 :
122 : // Memory reporting
123 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
124 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
125 :
126 : private:
127 : friend class CacheFileIOManager;
128 : friend class CacheFileChunk;
129 : friend class CacheFileInputStream;
130 : friend class CacheFileOutputStream;
131 : friend class CacheFileAutoLock;
132 : friend class MetadataWriteTimer;
133 :
134 : virtual ~CacheFile();
135 :
136 : void Lock();
137 : void Unlock();
138 : void AssertOwnsLock() const;
139 : void ReleaseOutsideLock(RefPtr<nsISupports> aObject);
140 :
141 : enum ECallerType {
142 : READER = 0,
143 : WRITER = 1,
144 : PRELOADER = 2
145 : };
146 :
147 : nsresult DoomLocked(CacheFileListener *aCallback);
148 :
149 : nsresult GetChunkLocked(uint32_t aIndex, ECallerType aCaller,
150 : CacheFileChunkListener *aCallback,
151 : CacheFileChunk **_retval);
152 :
153 : void PreloadChunks(uint32_t aIndex);
154 : bool ShouldCacheChunk(uint32_t aIndex);
155 : bool MustKeepCachedChunk(uint32_t aIndex);
156 :
157 : nsresult DeactivateChunk(CacheFileChunk *aChunk);
158 : void RemoveChunkInternal(CacheFileChunk *aChunk, bool aCacheChunk);
159 :
160 : bool OutputStreamExists(bool aAlternativeData);
161 : // Returns number of bytes that are available and can be read by input stream
162 : // without waiting for the data. The amount is counted from the start of
163 : // aIndex chunk and it is guaranteed that this data won't be released by
164 : // CleanUpCachedChunks().
165 : int64_t BytesFromChunk(uint32_t aIndex, bool aAlternativeData);
166 : nsresult Truncate(int64_t aOffset);
167 :
168 : nsresult RemoveInput(CacheFileInputStream *aInput, nsresult aStatus);
169 : nsresult RemoveOutput(CacheFileOutputStream *aOutput, nsresult aStatus);
170 : nsresult NotifyChunkListener(CacheFileChunkListener *aCallback,
171 : nsIEventTarget *aTarget,
172 : nsresult aResult,
173 : uint32_t aChunkIdx,
174 : CacheFileChunk *aChunk);
175 : nsresult QueueChunkListener(uint32_t aIndex,
176 : CacheFileChunkListener *aCallback);
177 : nsresult NotifyChunkListeners(uint32_t aIndex, nsresult aResult,
178 : CacheFileChunk *aChunk);
179 : bool HaveChunkListeners(uint32_t aIndex);
180 : void NotifyListenersAboutOutputRemoval();
181 :
182 : bool IsDirty();
183 : void WriteMetadataIfNeeded();
184 : void WriteMetadataIfNeededLocked(bool aFireAndForget = false);
185 : void PostWriteTimer();
186 :
187 : void CleanUpCachedChunks();
188 :
189 : nsresult PadChunkWithZeroes(uint32_t aChunkIdx);
190 :
191 : void SetError(nsresult aStatus);
192 : nsresult SetAltMetadata(const char* aAltMetadata);
193 :
194 : nsresult InitIndexEntry();
195 :
196 : mozilla::Mutex mLock;
197 : bool mOpeningFile;
198 : bool mReady;
199 : bool mMemoryOnly;
200 : bool mSkipSizeCheck;
201 : bool mOpenAsMemoryOnly;
202 : bool mPinned;
203 : bool mPriority;
204 : bool mDataAccessed;
205 : bool mDataIsDirty;
206 : bool mWritingMetadata;
207 : bool mPreloadWithoutInputStreams;
208 : uint32_t mPreloadChunkCount;
209 : nsresult mStatus;
210 : int64_t mDataSize; // Size of the whole data including eventual
211 : // alternative data represenation.
212 : int64_t mAltDataOffset; // If there is alternative data present, it
213 : // contains size of the original data, i.e.
214 : // offset where alternative data starts.
215 : // Otherwise it is -1.
216 : nsCString mKey;
217 :
218 : RefPtr<CacheFileHandle> mHandle;
219 : RefPtr<CacheFileMetadata> mMetadata;
220 : nsCOMPtr<CacheFileListener> mListener;
221 : nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener;
222 : Atomic<bool, Relaxed> mKill;
223 :
224 : nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mChunks;
225 : nsClassHashtable<nsUint32HashKey, ChunkListeners> mChunkListeners;
226 : nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mCachedChunks;
227 : // We can truncate data only if there is no input/output stream beyond the
228 : // truncate position, so only unused chunks can be thrown away. But it can
229 : // happen that we need to throw away a chunk that is still in mChunks (i.e.
230 : // an active chunk) because deactivation happens with a small delay. We cannot
231 : // delete such chunk immediately but we need to ensure that such chunk won't
232 : // be returned by GetChunkLocked, so we move this chunk into mDiscardedChunks
233 : // and mark it as discarded.
234 : nsTArray<RefPtr<CacheFileChunk> > mDiscardedChunks;
235 :
236 : nsTArray<CacheFileInputStream*> mInputs;
237 : CacheFileOutputStream *mOutput;
238 :
239 : nsTArray<RefPtr<nsISupports>> mObjsToRelease;
240 : };
241 :
242 : class CacheFileAutoLock {
243 : public:
244 185 : explicit CacheFileAutoLock(CacheFile *aFile)
245 185 : : mFile(aFile)
246 185 : , mLocked(true)
247 : {
248 185 : mFile->Lock();
249 185 : }
250 185 : ~CacheFileAutoLock()
251 185 : {
252 185 : if (mLocked)
253 185 : mFile->Unlock();
254 185 : }
255 6 : void Lock()
256 : {
257 6 : MOZ_ASSERT(!mLocked);
258 6 : mFile->Lock();
259 6 : mLocked = true;
260 6 : }
261 6 : void Unlock()
262 : {
263 6 : MOZ_ASSERT(mLocked);
264 6 : mFile->Unlock();
265 6 : mLocked = false;
266 6 : }
267 :
268 : private:
269 : RefPtr<CacheFile> mFile;
270 : bool mLocked;
271 : };
272 :
273 : } // namespace net
274 : } // namespace mozilla
275 :
276 : #endif
|