CacheFile.h (11094B)
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 "Dictionary.h" 12 #include "nsRefPtrHashtable.h" 13 #include "nsClassHashtable.h" 14 #include "mozilla/Mutex.h" 15 16 class nsIAsyncOutputStream; 17 class nsICacheEntry; 18 class nsICacheEntryMetaDataVisitor; 19 class nsIInputStream; 20 class nsIOutputStream; 21 22 namespace mozilla { 23 namespace net { 24 25 class CacheFileInputStream; 26 class CacheFileOutputStream; 27 class CacheOutputCloseListener; 28 class MetadataWriteTimer; 29 30 namespace CacheFileUtils { 31 class CacheFileLock; 32 }; 33 34 #define CACHEFILELISTENER_IID \ 35 {/* 95e7f284-84ba-48f9-b1fc-3a7336b4c33c */ \ 36 0x95e7f284, \ 37 0x84ba, \ 38 0x48f9, \ 39 {0xb1, 0xfc, 0x3a, 0x73, 0x36, 0xb4, 0xc3, 0x3c}} 40 41 class CacheFileListener : public nsISupports { 42 public: 43 NS_INLINE_DECL_STATIC_IID(CACHEFILELISTENER_IID) 44 45 NS_IMETHOD OnFileReady(nsresult aResult, bool aIsNew) = 0; 46 NS_IMETHOD OnFileDoomed(nsresult aResult) = 0; 47 }; 48 49 class MOZ_CAPABILITY("mutex") CacheFile final 50 : 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 void SetDictionary(DictionaryCacheEntry* aDict); 130 131 // Memory reporting 132 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 133 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 134 135 private: 136 friend class CacheFileIOManager; 137 friend class CacheFileChunk; 138 friend class CacheFileInputStream; 139 friend class CacheFileOutputStream; 140 friend class CacheFileAutoLock; 141 friend class MetadataWriteTimer; 142 143 virtual ~CacheFile(); 144 145 void Lock() MOZ_CAPABILITY_ACQUIRE() { mLock->Lock().Lock(); } 146 void Unlock() MOZ_CAPABILITY_RELEASE() { 147 // move the elements out of mObjsToRelease 148 // so that they can be released after we unlock 149 nsTArray<RefPtr<nsISupports>> objs = std::move(mObjsToRelease); 150 151 mLock->Lock().Unlock(); 152 } 153 void AssertOwnsLock() const MOZ_ASSERT_CAPABILITY(this) { 154 mLock->Lock().AssertCurrentThreadOwns(); 155 } 156 void ReleaseOutsideLock(RefPtr<nsISupports> aObject); 157 158 enum ECallerType { READER = 0, WRITER = 1, PRELOADER = 2 }; 159 160 nsresult DoomLocked(CacheFileListener* aCallback); 161 162 nsresult GetChunkLocked(uint32_t aIndex, ECallerType aCaller, 163 CacheFileChunkListener* aCallback, 164 CacheFileChunk** _retval); 165 166 void PreloadChunks(uint32_t aIndex); 167 bool ShouldCacheChunk(uint32_t aIndex); 168 bool MustKeepCachedChunk(uint32_t aIndex); 169 170 nsresult DeactivateChunk(CacheFileChunk* aChunk); 171 void RemoveChunkInternal(CacheFileChunk* aChunk, bool aCacheChunk); 172 173 bool OutputStreamExists(bool aAlternativeData); 174 // Returns number of bytes that are available and can be read by input stream 175 // without waiting for the data. The amount is counted from the start of 176 // aIndex chunk and it is guaranteed that this data won't be released by 177 // CleanUpCachedChunks(). 178 int64_t BytesFromChunk(uint32_t aIndex, bool aAlternativeData); 179 nsresult Truncate(int64_t aOffset); 180 181 void RemoveInput(CacheFileInputStream* aInput, nsresult aStatus); 182 void RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus); 183 nsresult NotifyChunkListener(CacheFileChunkListener* aCallback, 184 nsIEventTarget* aTarget, nsresult aResult, 185 uint32_t aChunkIdx, CacheFileChunk* aChunk); 186 void QueueChunkListener(uint32_t aIndex, CacheFileChunkListener* aCallback); 187 nsresult NotifyChunkListeners(uint32_t aIndex, nsresult aResult, 188 CacheFileChunk* aChunk); 189 bool HaveChunkListeners(uint32_t aIndex); 190 void NotifyListenersAboutOutputRemoval(); 191 192 bool IsDirty() MOZ_REQUIRES(this); 193 void WriteMetadataIfNeeded(); 194 void WriteMetadataIfNeededLocked(bool aFireAndForget = false) 195 MOZ_REQUIRES(this); 196 void PostWriteTimer() MOZ_REQUIRES(this); 197 198 void CleanUpCachedChunks() MOZ_REQUIRES(this); 199 200 nsresult PadChunkWithZeroes(uint32_t aChunkIdx); 201 202 void SetError(nsresult aStatus); 203 nsresult SetAltMetadata(const char* aAltMetadata); 204 205 nsresult InitIndexEntry(); 206 207 bool mOpeningFile MOZ_GUARDED_BY(this){false}; 208 bool mReady MOZ_GUARDED_BY(this){false}; 209 bool mMemoryOnly MOZ_GUARDED_BY(this){false}; 210 bool mSkipSizeCheck MOZ_GUARDED_BY(this){false}; 211 bool mOpenAsMemoryOnly MOZ_GUARDED_BY(this){false}; 212 bool mPinned MOZ_GUARDED_BY(this){false}; 213 bool mPriority MOZ_GUARDED_BY(this){false}; 214 bool mDataAccessed MOZ_GUARDED_BY(this){false}; 215 bool mDataIsDirty MOZ_GUARDED_BY(this){false}; 216 bool mWritingMetadata MOZ_GUARDED_BY(this){false}; 217 bool mPreloadWithoutInputStreams MOZ_GUARDED_BY(this){true}; 218 uint32_t mPreloadChunkCount MOZ_GUARDED_BY(this){0}; 219 nsresult mStatus MOZ_GUARDED_BY(this){NS_OK}; 220 // Size of the whole data including eventual alternative data represenation. 221 int64_t mDataSize MOZ_GUARDED_BY(this){-1}; 222 223 // If there is alternative data present, it contains size of the original 224 // data, i.e. offset where alternative data starts. Otherwise it is -1. 225 int64_t mAltDataOffset MOZ_GUARDED_BY(this){-1}; 226 227 nsCString mKey MOZ_GUARDED_BY(this); 228 nsCString mAltDataType 229 MOZ_GUARDED_BY(this); // The type of the saved alt-data. May be empty. 230 231 RefPtr<DictionaryCacheEntry> mDict MOZ_GUARDED_BY(this); 232 233 RefPtr<CacheFileHandle> mHandle MOZ_GUARDED_BY(this); 234 RefPtr<CacheFileMetadata> mMetadata MOZ_GUARDED_BY(this); 235 nsCOMPtr<CacheFileListener> mListener MOZ_GUARDED_BY(this); 236 nsCOMPtr<CacheFileIOListener> mDoomAfterOpenListener MOZ_GUARDED_BY(this); 237 Atomic<bool, Relaxed> mKill{false}; 238 239 nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mChunks 240 MOZ_GUARDED_BY(this); 241 nsClassHashtable<nsUint32HashKey, ChunkListeners> mChunkListeners 242 MOZ_GUARDED_BY(this); 243 nsRefPtrHashtable<nsUint32HashKey, CacheFileChunk> mCachedChunks 244 MOZ_GUARDED_BY(this); 245 // We can truncate data only if there is no input/output stream beyond the 246 // truncate position, so only unused chunks can be thrown away. But it can 247 // happen that we need to throw away a chunk that is still in mChunks (i.e. 248 // an active chunk) because deactivation happens with a small delay. We cannot 249 // delete such chunk immediately but we need to ensure that such chunk won't 250 // be returned by GetChunkLocked, so we move this chunk into mDiscardedChunks 251 // and mark it as discarded. 252 nsTArray<RefPtr<CacheFileChunk>> mDiscardedChunks MOZ_GUARDED_BY(this); 253 254 nsTArray<CacheFileInputStream*> mInputs MOZ_GUARDED_BY(this); 255 CacheFileOutputStream* mOutput MOZ_GUARDED_BY(this){nullptr}; 256 257 nsTArray<RefPtr<nsISupports>> mObjsToRelease MOZ_GUARDED_BY(this); 258 RefPtr<CacheFileUtils::CacheFileLock> mLock; 259 }; 260 261 class MOZ_RAII MOZ_SCOPED_CAPABILITY CacheFileAutoLock { 262 public: 263 explicit CacheFileAutoLock(CacheFile* aFile) MOZ_CAPABILITY_ACQUIRE(aFile) 264 : mFile(aFile), mLocked(true) { 265 mFile->Lock(); 266 } 267 ~CacheFileAutoLock() MOZ_CAPABILITY_RELEASE() { 268 if (mLocked) { 269 mFile->Unlock(); 270 } 271 } 272 void Lock() MOZ_CAPABILITY_ACQUIRE() { 273 MOZ_ASSERT(!mLocked); 274 mFile->Lock(); 275 mLocked = true; 276 } 277 void Unlock() MOZ_CAPABILITY_RELEASE() { 278 MOZ_ASSERT(mLocked); 279 mFile->Unlock(); 280 mLocked = false; 281 } 282 283 private: 284 RefPtr<CacheFile> mFile; 285 bool mLocked; 286 }; 287 288 } // namespace net 289 } // namespace mozilla 290 291 #endif