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