|
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 CacheFileIOManager__h__ |
|
6 #define CacheFileIOManager__h__ |
|
7 |
|
8 #include "CacheIOThread.h" |
|
9 #include "nsIEventTarget.h" |
|
10 #include "nsITimer.h" |
|
11 #include "nsCOMPtr.h" |
|
12 #include "mozilla/SHA1.h" |
|
13 #include "mozilla/TimeStamp.h" |
|
14 #include "nsTArray.h" |
|
15 #include "nsString.h" |
|
16 #include "nsTHashtable.h" |
|
17 #include "prio.h" |
|
18 |
|
19 //#define DEBUG_HANDLES 1 |
|
20 |
|
21 class nsIFile; |
|
22 class nsITimer; |
|
23 class nsIDirectoryEnumerator; |
|
24 class nsILoadContextInfo; |
|
25 |
|
26 namespace mozilla { |
|
27 namespace net { |
|
28 |
|
29 class CacheFile; |
|
30 #ifdef DEBUG_HANDLES |
|
31 class CacheFileHandlesEntry; |
|
32 #endif |
|
33 |
|
34 const char kEntriesDir[] = "entries"; |
|
35 const char kDoomedDir[] = "doomed"; |
|
36 const char kTrashDir[] = "trash"; |
|
37 |
|
38 |
|
39 class CacheFileHandle : public nsISupports |
|
40 { |
|
41 public: |
|
42 NS_DECL_THREADSAFE_ISUPPORTS |
|
43 bool DispatchRelease(); |
|
44 |
|
45 CacheFileHandle(const SHA1Sum::Hash *aHash, bool aPriority); |
|
46 CacheFileHandle(const nsACString &aKey, bool aPriority); |
|
47 CacheFileHandle(const CacheFileHandle &aOther); |
|
48 void Log(); |
|
49 bool IsDoomed() const { return mIsDoomed; } |
|
50 const SHA1Sum::Hash *Hash() const { return mHash; } |
|
51 int64_t FileSize() const { return mFileSize; } |
|
52 uint32_t FileSizeInK() const; |
|
53 bool IsPriority() const { return mPriority; } |
|
54 bool FileExists() const { return mFileExists; } |
|
55 bool IsClosed() const { return mClosed; } |
|
56 bool IsSpecialFile() const { return !mHash; } |
|
57 nsCString & Key() { return mKey; } |
|
58 |
|
59 // Memory reporting |
|
60 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
61 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
62 |
|
63 private: |
|
64 friend class CacheFileIOManager; |
|
65 friend class CacheFileHandles; |
|
66 friend class ReleaseNSPRHandleEvent; |
|
67 |
|
68 virtual ~CacheFileHandle(); |
|
69 |
|
70 const SHA1Sum::Hash *mHash; |
|
71 bool mIsDoomed; |
|
72 bool mPriority; |
|
73 bool mClosed; |
|
74 bool mInvalid; |
|
75 bool mFileExists; // This means that the file should exists, |
|
76 // but it can be still deleted by OS/user |
|
77 // and then a subsequent OpenNSPRFileDesc() |
|
78 // will fail. |
|
79 nsCOMPtr<nsIFile> mFile; |
|
80 int64_t mFileSize; |
|
81 PRFileDesc *mFD; // if null then the file doesn't exists on the disk |
|
82 nsCString mKey; |
|
83 }; |
|
84 |
|
85 class CacheFileHandles { |
|
86 public: |
|
87 CacheFileHandles(); |
|
88 ~CacheFileHandles(); |
|
89 |
|
90 nsresult GetHandle(const SHA1Sum::Hash *aHash, bool aReturnDoomed, CacheFileHandle **_retval); |
|
91 nsresult NewHandle(const SHA1Sum::Hash *aHash, bool aPriority, CacheFileHandle **_retval); |
|
92 void RemoveHandle(CacheFileHandle *aHandlle); |
|
93 void GetAllHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval); |
|
94 void GetActiveHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval); |
|
95 void ClearAll(); |
|
96 uint32_t HandleCount(); |
|
97 |
|
98 #ifdef DEBUG_HANDLES |
|
99 void Log(CacheFileHandlesEntry *entry); |
|
100 #endif |
|
101 |
|
102 // Memory reporting |
|
103 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
104 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
105 |
|
106 class HandleHashKey : public PLDHashEntryHdr |
|
107 { |
|
108 public: |
|
109 typedef const SHA1Sum::Hash& KeyType; |
|
110 typedef const SHA1Sum::Hash* KeyTypePointer; |
|
111 |
|
112 HandleHashKey(KeyTypePointer aKey) |
|
113 { |
|
114 MOZ_COUNT_CTOR(HandleHashKey); |
|
115 mHash = (SHA1Sum::Hash*)new uint8_t[SHA1Sum::HashSize]; |
|
116 memcpy(mHash, aKey, sizeof(SHA1Sum::Hash)); |
|
117 } |
|
118 HandleHashKey(const HandleHashKey& aOther) |
|
119 { |
|
120 NS_NOTREACHED("HandleHashKey copy constructor is forbidden!"); |
|
121 } |
|
122 ~HandleHashKey() |
|
123 { |
|
124 MOZ_COUNT_DTOR(HandleHashKey); |
|
125 } |
|
126 |
|
127 bool KeyEquals(KeyTypePointer aKey) const |
|
128 { |
|
129 return memcmp(mHash, aKey, sizeof(SHA1Sum::Hash)) == 0; |
|
130 } |
|
131 static KeyTypePointer KeyToPointer(KeyType aKey) |
|
132 { |
|
133 return &aKey; |
|
134 } |
|
135 static PLDHashNumber HashKey(KeyTypePointer aKey) |
|
136 { |
|
137 return (reinterpret_cast<const uint32_t *>(aKey))[0]; |
|
138 } |
|
139 |
|
140 void AddHandle(CacheFileHandle* aHandle); |
|
141 void RemoveHandle(CacheFileHandle* aHandle); |
|
142 already_AddRefed<CacheFileHandle> GetNewestHandle(); |
|
143 void GetHandles(nsTArray<nsRefPtr<CacheFileHandle> > &aResult); |
|
144 |
|
145 SHA1Sum::Hash *Hash() const { return mHash; } |
|
146 bool IsEmpty() const { return mHandles.Length() == 0; } |
|
147 |
|
148 enum { ALLOW_MEMMOVE = true }; |
|
149 |
|
150 #ifdef DEBUG |
|
151 void AssertHandlesState(); |
|
152 #endif |
|
153 |
|
154 // Memory reporting |
|
155 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
156 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
|
157 |
|
158 private: |
|
159 nsAutoArrayPtr<SHA1Sum::Hash> mHash; |
|
160 // Use weak pointers since the hash table access is on a single thread |
|
161 // only and CacheFileHandle removes itself from this table in its dtor |
|
162 // that may only be called on the same thread as we work with the hashtable |
|
163 // since we dispatch its Release() to this thread. |
|
164 nsTArray<CacheFileHandle*> mHandles; |
|
165 }; |
|
166 |
|
167 private: |
|
168 nsTHashtable<HandleHashKey> mTable; |
|
169 }; |
|
170 |
|
171 //////////////////////////////////////////////////////////////////////////////// |
|
172 |
|
173 class OpenFileEvent; |
|
174 class CloseFileEvent; |
|
175 class ReadEvent; |
|
176 class WriteEvent; |
|
177 class MetadataWriteScheduleEvent; |
|
178 class CacheFileContextEvictor; |
|
179 |
|
180 #define CACHEFILEIOLISTENER_IID \ |
|
181 { /* dcaf2ddc-17cf-4242-bca1-8c86936375a5 */ \ |
|
182 0xdcaf2ddc, \ |
|
183 0x17cf, \ |
|
184 0x4242, \ |
|
185 {0xbc, 0xa1, 0x8c, 0x86, 0x93, 0x63, 0x75, 0xa5} \ |
|
186 } |
|
187 |
|
188 class CacheFileIOListener : public nsISupports |
|
189 { |
|
190 public: |
|
191 NS_DECLARE_STATIC_IID_ACCESSOR(CACHEFILEIOLISTENER_IID) |
|
192 |
|
193 NS_IMETHOD OnFileOpened(CacheFileHandle *aHandle, nsresult aResult) = 0; |
|
194 NS_IMETHOD OnDataWritten(CacheFileHandle *aHandle, const char *aBuf, |
|
195 nsresult aResult) = 0; |
|
196 NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, |
|
197 nsresult aResult) = 0; |
|
198 NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult) = 0; |
|
199 NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult) = 0; |
|
200 NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult) = 0; |
|
201 }; |
|
202 |
|
203 NS_DEFINE_STATIC_IID_ACCESSOR(CacheFileIOListener, CACHEFILEIOLISTENER_IID) |
|
204 |
|
205 |
|
206 class CacheFileIOManager : public nsITimerCallback |
|
207 { |
|
208 public: |
|
209 NS_DECL_THREADSAFE_ISUPPORTS |
|
210 NS_DECL_NSITIMERCALLBACK |
|
211 |
|
212 enum { |
|
213 OPEN = 0U, |
|
214 CREATE = 1U, |
|
215 CREATE_NEW = 2U, |
|
216 PRIORITY = 4U, |
|
217 SPECIAL_FILE = 8U |
|
218 }; |
|
219 |
|
220 CacheFileIOManager(); |
|
221 |
|
222 static nsresult Init(); |
|
223 static nsresult Shutdown(); |
|
224 static nsresult OnProfile(); |
|
225 static already_AddRefed<nsIEventTarget> IOTarget(); |
|
226 static already_AddRefed<CacheIOThread> IOThread(); |
|
227 static bool IsOnIOThread(); |
|
228 static bool IsOnIOThreadOrCeased(); |
|
229 static bool IsShutdown(); |
|
230 |
|
231 // Make aFile's WriteMetadataIfNeeded be called automatically after |
|
232 // a short interval. |
|
233 static nsresult ScheduleMetadataWrite(CacheFile * aFile); |
|
234 // Remove aFile from the scheduling registry array. |
|
235 // WriteMetadataIfNeeded will not be automatically called. |
|
236 static nsresult UnscheduleMetadataWrite(CacheFile * aFile); |
|
237 // Shuts the scheduling off and flushes all pending metadata writes. |
|
238 static nsresult ShutdownMetadataWriteScheduling(); |
|
239 |
|
240 static nsresult OpenFile(const nsACString &aKey, |
|
241 uint32_t aFlags, bool aResultOnAnyThread, |
|
242 CacheFileIOListener *aCallback); |
|
243 static nsresult Read(CacheFileHandle *aHandle, int64_t aOffset, |
|
244 char *aBuf, int32_t aCount, bool aResultOnAnyThread, |
|
245 CacheFileIOListener *aCallback); |
|
246 static nsresult Write(CacheFileHandle *aHandle, int64_t aOffset, |
|
247 const char *aBuf, int32_t aCount, bool aValidate, |
|
248 CacheFileIOListener *aCallback); |
|
249 static nsresult DoomFile(CacheFileHandle *aHandle, |
|
250 CacheFileIOListener *aCallback); |
|
251 static nsresult DoomFileByKey(const nsACString &aKey, |
|
252 CacheFileIOListener *aCallback); |
|
253 static nsresult ReleaseNSPRHandle(CacheFileHandle *aHandle); |
|
254 static nsresult TruncateSeekSetEOF(CacheFileHandle *aHandle, |
|
255 int64_t aTruncatePos, int64_t aEOFPos, |
|
256 CacheFileIOListener *aCallback); |
|
257 static nsresult RenameFile(CacheFileHandle *aHandle, |
|
258 const nsACString &aNewName, |
|
259 CacheFileIOListener *aCallback); |
|
260 static nsresult EvictIfOverLimit(); |
|
261 static nsresult EvictAll(); |
|
262 static nsresult EvictByContext(nsILoadContextInfo *aLoadContextInfo); |
|
263 |
|
264 static nsresult InitIndexEntry(CacheFileHandle *aHandle, |
|
265 uint32_t aAppId, |
|
266 bool aAnonymous, |
|
267 bool aInBrowser); |
|
268 static nsresult UpdateIndexEntry(CacheFileHandle *aHandle, |
|
269 const uint32_t *aFrecency, |
|
270 const uint32_t *aExpirationTime); |
|
271 |
|
272 static nsresult UpdateIndexEntry(); |
|
273 |
|
274 enum EEnumerateMode { |
|
275 ENTRIES, |
|
276 DOOMED |
|
277 }; |
|
278 |
|
279 static void GetCacheDirectory(nsIFile** result); |
|
280 |
|
281 // Memory reporting |
|
282 static size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); |
|
283 static size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); |
|
284 |
|
285 private: |
|
286 friend class CacheFileHandle; |
|
287 friend class CacheFileChunk; |
|
288 friend class CacheFile; |
|
289 friend class ShutdownEvent; |
|
290 friend class OpenFileEvent; |
|
291 friend class CloseHandleEvent; |
|
292 friend class ReadEvent; |
|
293 friend class WriteEvent; |
|
294 friend class DoomFileEvent; |
|
295 friend class DoomFileByKeyEvent; |
|
296 friend class ReleaseNSPRHandleEvent; |
|
297 friend class TruncateSeekSetEOFEvent; |
|
298 friend class RenameFileEvent; |
|
299 friend class CacheIndex; |
|
300 friend class MetadataWriteScheduleEvent; |
|
301 friend class CacheFileContextEvictor; |
|
302 |
|
303 virtual ~CacheFileIOManager(); |
|
304 |
|
305 nsresult InitInternal(); |
|
306 nsresult ShutdownInternal(); |
|
307 |
|
308 nsresult OpenFileInternal(const SHA1Sum::Hash *aHash, |
|
309 const nsACString &aKey, |
|
310 uint32_t aFlags, |
|
311 CacheFileHandle **_retval); |
|
312 nsresult OpenSpecialFileInternal(const nsACString &aKey, |
|
313 uint32_t aFlags, |
|
314 CacheFileHandle **_retval); |
|
315 nsresult CloseHandleInternal(CacheFileHandle *aHandle); |
|
316 nsresult ReadInternal(CacheFileHandle *aHandle, int64_t aOffset, |
|
317 char *aBuf, int32_t aCount); |
|
318 nsresult WriteInternal(CacheFileHandle *aHandle, int64_t aOffset, |
|
319 const char *aBuf, int32_t aCount, bool aValidate); |
|
320 nsresult DoomFileInternal(CacheFileHandle *aHandle); |
|
321 nsresult DoomFileByKeyInternal(const SHA1Sum::Hash *aHash); |
|
322 nsresult ReleaseNSPRHandleInternal(CacheFileHandle *aHandle); |
|
323 nsresult TruncateSeekSetEOFInternal(CacheFileHandle *aHandle, |
|
324 int64_t aTruncatePos, int64_t aEOFPos); |
|
325 nsresult RenameFileInternal(CacheFileHandle *aHandle, |
|
326 const nsACString &aNewName); |
|
327 nsresult EvictIfOverLimitInternal(); |
|
328 nsresult OverLimitEvictionInternal(); |
|
329 nsresult EvictAllInternal(); |
|
330 nsresult EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo); |
|
331 |
|
332 nsresult TrashDirectory(nsIFile *aFile); |
|
333 static void OnTrashTimer(nsITimer *aTimer, void *aClosure); |
|
334 nsresult StartRemovingTrash(); |
|
335 nsresult RemoveTrashInternal(); |
|
336 nsresult FindTrashDirToRemove(); |
|
337 |
|
338 nsresult CreateFile(CacheFileHandle *aHandle); |
|
339 static void HashToStr(const SHA1Sum::Hash *aHash, nsACString &_retval); |
|
340 static nsresult StrToHash(const nsACString &aHash, SHA1Sum::Hash *_retval); |
|
341 nsresult GetFile(const SHA1Sum::Hash *aHash, nsIFile **_retval); |
|
342 nsresult GetSpecialFile(const nsACString &aKey, nsIFile **_retval); |
|
343 nsresult GetDoomedFile(nsIFile **_retval); |
|
344 nsresult IsEmptyDirectory(nsIFile *aFile, bool *_retval); |
|
345 nsresult CheckAndCreateDir(nsIFile *aFile, const char *aDir, |
|
346 bool aEnsureEmptyDir); |
|
347 nsresult CreateCacheTree(); |
|
348 nsresult OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate = false); |
|
349 void NSPRHandleUsed(CacheFileHandle *aHandle); |
|
350 |
|
351 // Removing all cache files during shutdown |
|
352 nsresult SyncRemoveDir(nsIFile *aFile, const char *aDir); |
|
353 void SyncRemoveAllCacheFiles(); |
|
354 |
|
355 nsresult ScheduleMetadataWriteInternal(CacheFile * aFile); |
|
356 nsresult UnscheduleMetadataWriteInternal(CacheFile * aFile); |
|
357 nsresult ShutdownMetadataWriteSchedulingInternal(); |
|
358 |
|
359 static nsresult CacheIndexStateChanged(); |
|
360 nsresult CacheIndexStateChangedInternal(); |
|
361 |
|
362 // Smart size calculation. UpdateSmartCacheSize() must be called on IO thread. |
|
363 // It is called in EvictIfOverLimitInternal() just before we decide whether to |
|
364 // start overlimit eviction or not and also in OverLimitEvictionInternal() |
|
365 // before we start an eviction loop. |
|
366 nsresult UpdateSmartCacheSize(); |
|
367 |
|
368 // Memory reporting (private part) |
|
369 size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const; |
|
370 |
|
371 static CacheFileIOManager *gInstance; |
|
372 TimeStamp mStartTime; |
|
373 bool mShuttingDown; |
|
374 nsRefPtr<CacheIOThread> mIOThread; |
|
375 nsCOMPtr<nsIFile> mCacheDirectory; |
|
376 bool mTreeCreated; |
|
377 CacheFileHandles mHandles; |
|
378 nsTArray<CacheFileHandle *> mHandlesByLastUsed; |
|
379 nsTArray<CacheFileHandle *> mSpecialHandles; |
|
380 nsTArray<nsRefPtr<CacheFile> > mScheduledMetadataWrites; |
|
381 nsCOMPtr<nsITimer> mMetadataWritesTimer; |
|
382 bool mOverLimitEvicting; |
|
383 bool mRemovingTrashDirs; |
|
384 nsCOMPtr<nsITimer> mTrashTimer; |
|
385 nsCOMPtr<nsIFile> mTrashDir; |
|
386 nsCOMPtr<nsIDirectoryEnumerator> mTrashDirEnumerator; |
|
387 nsTArray<nsCString> mFailedTrashDirs; |
|
388 nsRefPtr<CacheFileContextEvictor> mContextEvictor; |
|
389 TimeStamp mLastSmartSizeTime; |
|
390 }; |
|
391 |
|
392 } // net |
|
393 } // mozilla |
|
394 |
|
395 #endif |