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 CacheFileChunk__h__
6 #define CacheFileChunk__h__
7 
8 #include "CacheFileIOManager.h"
9 #include "CacheStorageService.h"
10 #include "CacheHashUtils.h"
11 #include "CacheFileUtils.h"
12 #include "mozilla/Mutex.h"
13 #include "mozilla/UniquePtr.h"
14 
15 namespace mozilla {
16 namespace net {
17 
18 constexpr int32_t kChunkSize = 256 * 1024;
19 constexpr size_t kEmptyChunkHash = 0x1826;
20 
21 class CacheFileChunk;
22 class CacheFile;
23 
24 class CacheFileChunkBuffer {
25  public:
26   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheFileChunkBuffer)
27 
28   explicit CacheFileChunkBuffer(CacheFileChunk* aChunk);
29 
30   nsresult EnsureBufSize(uint32_t aBufSize);
31   void CopyFrom(CacheFileChunkBuffer* aOther);
32   nsresult FillInvalidRanges(CacheFileChunkBuffer* aOther,
33                              CacheFileUtils::ValidityMap* aMap);
34   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
35 
Buf()36   char* Buf() const { return mBuf; }
37   void SetDataSize(uint32_t aDataSize);
DataSize()38   uint32_t DataSize() const { return mDataSize; }
ReadHandlesCount()39   uint32_t ReadHandlesCount() const { return mReadHandlesCount; }
WriteHandleExists()40   bool WriteHandleExists() const { return mWriteHandleExists; }
41 
42  private:
43   friend class CacheFileChunkHandle;
44   friend class CacheFileChunkReadHandle;
45   friend class CacheFileChunkWriteHandle;
46 
47   ~CacheFileChunkBuffer();
48 
49   void AssertOwnsLock() const;
50 
51   void RemoveReadHandle();
52   void RemoveWriteHandle();
53 
54   // We keep a weak reference to the chunk to not create a reference cycle. The
55   // buffer is referenced only by chunk and handles. Handles are always
56   // destroyed before the chunk so it is guaranteed that mChunk is a valid
57   // pointer for the whole buffer's lifetime.
58   CacheFileChunk* mChunk;
59   char* mBuf;
60   uint32_t mBufSize;
61   uint32_t mDataSize;
62   uint32_t mReadHandlesCount;
63   bool mWriteHandleExists;
64 };
65 
66 class CacheFileChunkHandle {
67  public:
68   uint32_t DataSize();
69   uint32_t Offset();
70 
71  protected:
72   RefPtr<CacheFileChunkBuffer> mBuf;
73 };
74 
75 class CacheFileChunkReadHandle : public CacheFileChunkHandle {
76  public:
77   explicit CacheFileChunkReadHandle(CacheFileChunkBuffer* aBuf);
78   ~CacheFileChunkReadHandle();
79 
80   const char* Buf();
81 };
82 
83 class CacheFileChunkWriteHandle : public CacheFileChunkHandle {
84  public:
85   explicit CacheFileChunkWriteHandle(CacheFileChunkBuffer* aBuf);
86   ~CacheFileChunkWriteHandle();
87 
88   char* Buf();
89   void UpdateDataSize(uint32_t aOffset, uint32_t aLen);
90 };
91 
92 #define CACHEFILECHUNKLISTENER_IID                   \
93   { /* baf16149-2ab5-499c-a9c2-5904eb95c288 */       \
94     0xbaf16149, 0x2ab5, 0x499c, {                    \
95       0xa9, 0xc2, 0x59, 0x04, 0xeb, 0x95, 0xc2, 0x88 \
96     }                                                \
97   }
98 
99 class CacheFileChunkListener : public nsISupports {
100  public:
101   NS_DECLARE_STATIC_IID_ACCESSOR(CACHEFILECHUNKLISTENER_IID)
102 
103   NS_IMETHOD OnChunkRead(nsresult aResult, CacheFileChunk* aChunk) = 0;
104   NS_IMETHOD OnChunkWritten(nsresult aResult, CacheFileChunk* aChunk) = 0;
105   NS_IMETHOD OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
106                               CacheFileChunk* aChunk) = 0;
107   NS_IMETHOD OnChunkUpdated(CacheFileChunk* aChunk) = 0;
108 };
109 
NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileChunkListener,CACHEFILECHUNKLISTENER_IID)110 NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileChunkListener,
111                               CACHEFILECHUNKLISTENER_IID)
112 
113 class ChunkListenerItem {
114  public:
115   MOZ_COUNTED_DEFAULT_CTOR(ChunkListenerItem)
116   MOZ_COUNTED_DTOR(ChunkListenerItem)
117 
118   nsCOMPtr<nsIEventTarget> mTarget;
119   nsCOMPtr<CacheFileChunkListener> mCallback;
120 };
121 
122 class ChunkListeners {
123  public:
124   MOZ_COUNTED_DEFAULT_CTOR(ChunkListeners)
125   MOZ_COUNTED_DTOR(ChunkListeners)
126 
127   nsTArray<ChunkListenerItem*> mItems;
128 };
129 
130 class CacheFileChunk final : public CacheFileIOListener,
131                              public CacheMemoryConsumer {
132  public:
133   NS_DECL_THREADSAFE_ISUPPORTS
134   bool DispatchRelease();
135 
136   CacheFileChunk(CacheFile* aFile, uint32_t aIndex, bool aInitByWriter);
137 
138   void InitNew();
139   nsresult Read(CacheFileHandle* aHandle, uint32_t aLen,
140                 CacheHash::Hash16_t aHash, CacheFileChunkListener* aCallback);
141   nsresult Write(CacheFileHandle* aHandle, CacheFileChunkListener* aCallback);
142   void WaitForUpdate(CacheFileChunkListener* aCallback);
143   void CancelWait(CacheFileChunkListener* aCallback);
144   nsresult NotifyUpdateListeners();
145 
146   uint32_t Index() const;
147   CacheHash::Hash16_t Hash() const;
148   uint32_t DataSize() const;
149 
150   NS_IMETHOD OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) override;
151   NS_IMETHOD OnDataWritten(CacheFileHandle* aHandle, const char* aBuf,
152                            nsresult aResult) override;
153   NS_IMETHOD OnDataRead(CacheFileHandle* aHandle, char* aBuf,
154                         nsresult aResult) override;
155   NS_IMETHOD OnFileDoomed(CacheFileHandle* aHandle, nsresult aResult) override;
156   NS_IMETHOD OnEOFSet(CacheFileHandle* aHandle, nsresult aResult) override;
157   NS_IMETHOD OnFileRenamed(CacheFileHandle* aHandle, nsresult aResult) override;
158   virtual bool IsKilled() override;
159 
160   bool IsReady() const;
161   bool IsDirty() const;
162 
163   nsresult GetStatus();
164   void SetError(nsresult aStatus);
165 
166   CacheFileChunkReadHandle GetReadHandle();
167   CacheFileChunkWriteHandle GetWriteHandle(uint32_t aEnsuredBufSize);
168 
169   // Memory reporting
170   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
171   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
172 
173  private:
174   friend class CacheFileChunkBuffer;
175   friend class CacheFileChunkWriteHandle;
176   friend class CacheFileInputStream;
177   friend class CacheFileOutputStream;
178   friend class CacheFile;
179 
180   virtual ~CacheFileChunk();
181 
182   void AssertOwnsLock() const;
183 
184   void UpdateDataSize(uint32_t aOffset, uint32_t aLen);
185   void Truncate(uint32_t aOffset);
186 
187   bool CanAllocate(uint32_t aSize) const;
188   void BuffersAllocationChanged(uint32_t aFreed, uint32_t aAllocated);
189 
190   mozilla::Atomic<uint32_t, ReleaseAcquire>& ChunksMemoryUsage() const;
191 
192   enum EState { INITIAL = 0, READING = 1, WRITING = 2, READY = 3 };
193 
194   uint32_t mIndex;
195   EState mState;
196   nsresult mStatus;
197 
198   Atomic<bool> mActiveChunk;  // Is true iff the chunk is in CacheFile::mChunks.
199                               // Adding/removing chunk to/from mChunks as well
200                               // as changing this member happens under the
201                               // CacheFile's lock.
202   bool mIsDirty : 1;
203   bool mDiscardedChunk : 1;
204 
205   uint32_t mBuffersSize;
206   bool const mLimitAllocation : 1;  // Whether this chunk respects limit for
207                                     // disk chunks memory usage.
208   bool const mIsPriority : 1;
209 
210   // Buffer containing the chunk data. Multiple read handles can access the same
211   // buffer. When write handle is created and some read handle exists a new copy
212   // of the buffer is created. This prevents invalidating the buffer when
213   // CacheFileInputStream::ReadSegments calls the handler outside the lock.
214   RefPtr<CacheFileChunkBuffer> mBuf;
215 
216   // We need to keep pointers of the old buffers for memory reporting.
217   nsTArray<RefPtr<CacheFileChunkBuffer>> mOldBufs;
218 
219   // Read handle that is used during writing the chunk to the disk.
220   UniquePtr<CacheFileChunkReadHandle> mWritingStateHandle;
221 
222   // Buffer that is used to read the chunk from the disk. It is allowed to write
223   // a new data to chunk while we wait for the data from the disk. In this case
224   // this buffer is merged with mBuf in OnDataRead().
225   RefPtr<CacheFileChunkBuffer> mReadingStateBuf;
226   CacheHash::Hash16_t mExpectedHash;
227 
228   RefPtr<CacheFile> mFile;  // is null if chunk is cached to
229                             // prevent reference cycles
230   nsCOMPtr<CacheFileChunkListener> mListener;
231   nsTArray<ChunkListenerItem*> mUpdateListeners;
232   CacheFileUtils::ValidityMap mValidityMap;
233 };
234 
235 }  // namespace net
236 }  // namespace mozilla
237 
238 #endif
239