|
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 #include "CacheLog.h" |
|
6 #include "CacheFileIOManager.h" |
|
7 |
|
8 #include "../cache/nsCacheUtils.h" |
|
9 #include "CacheHashUtils.h" |
|
10 #include "CacheStorageService.h" |
|
11 #include "CacheIndex.h" |
|
12 #include "CacheFileUtils.h" |
|
13 #include "nsThreadUtils.h" |
|
14 #include "CacheFile.h" |
|
15 #include "CacheObserver.h" |
|
16 #include "nsIFile.h" |
|
17 #include "CacheFileContextEvictor.h" |
|
18 #include "nsITimer.h" |
|
19 #include "nsISimpleEnumerator.h" |
|
20 #include "nsIDirectoryEnumerator.h" |
|
21 #include "nsIObserverService.h" |
|
22 #include "nsISizeOf.h" |
|
23 #include "mozilla/Telemetry.h" |
|
24 #include "mozilla/DebugOnly.h" |
|
25 #include "mozilla/Services.h" |
|
26 #include "nsDirectoryServiceUtils.h" |
|
27 #include "nsAppDirectoryServiceDefs.h" |
|
28 #include "private/pprio.h" |
|
29 #include "mozilla/VisualEventTracer.h" |
|
30 #include "mozilla/Preferences.h" |
|
31 |
|
32 // include files for ftruncate (or equivalent) |
|
33 #if defined(XP_UNIX) |
|
34 #include <unistd.h> |
|
35 #elif defined(XP_WIN) |
|
36 #include <windows.h> |
|
37 #undef CreateFile |
|
38 #undef CREATE_NEW |
|
39 #else |
|
40 // XXX add necessary include file for ftruncate (or equivalent) |
|
41 #endif |
|
42 |
|
43 |
|
44 namespace mozilla { |
|
45 namespace net { |
|
46 |
|
47 #define kOpenHandlesLimit 64 |
|
48 #define kMetadataWriteDelay 5000 |
|
49 #define kRemoveTrashStartDelay 60000 // in milliseconds |
|
50 #define kSmartSizeUpdateInterval 60000 // in milliseconds |
|
51 |
|
52 #ifdef ANDROID |
|
53 const uint32_t kMaxCacheSizeKB = 200*1024; // 200 MB |
|
54 #else |
|
55 const uint32_t kMaxCacheSizeKB = 350*1024; // 350 MB |
|
56 #endif |
|
57 |
|
58 bool |
|
59 CacheFileHandle::DispatchRelease() |
|
60 { |
|
61 if (CacheFileIOManager::IsOnIOThreadOrCeased()) { |
|
62 return false; |
|
63 } |
|
64 |
|
65 nsCOMPtr<nsIEventTarget> ioTarget = CacheFileIOManager::IOTarget(); |
|
66 if (!ioTarget) { |
|
67 return false; |
|
68 } |
|
69 |
|
70 nsRefPtr<nsRunnableMethod<CacheFileHandle, MozExternalRefCountType, false> > event = |
|
71 NS_NewNonOwningRunnableMethod(this, &CacheFileHandle::Release); |
|
72 nsresult rv = ioTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); |
|
73 if (NS_FAILED(rv)) { |
|
74 return false; |
|
75 } |
|
76 |
|
77 return true; |
|
78 } |
|
79 |
|
80 NS_IMPL_ADDREF(CacheFileHandle) |
|
81 NS_IMETHODIMP_(MozExternalRefCountType) |
|
82 CacheFileHandle::Release() |
|
83 { |
|
84 nsrefcnt count = mRefCnt - 1; |
|
85 if (DispatchRelease()) { |
|
86 // Redispatched to the IO thread. |
|
87 return count; |
|
88 } |
|
89 |
|
90 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
91 |
|
92 LOG(("CacheFileHandle::Release() [this=%p, refcnt=%d]", this, mRefCnt.get())); |
|
93 NS_PRECONDITION(0 != mRefCnt, "dup release"); |
|
94 count = --mRefCnt; |
|
95 NS_LOG_RELEASE(this, count, "CacheFileHandle"); |
|
96 |
|
97 if (0 == count) { |
|
98 mRefCnt = 1; |
|
99 delete (this); |
|
100 return 0; |
|
101 } |
|
102 |
|
103 return count; |
|
104 } |
|
105 |
|
106 NS_INTERFACE_MAP_BEGIN(CacheFileHandle) |
|
107 NS_INTERFACE_MAP_ENTRY(nsISupports) |
|
108 NS_INTERFACE_MAP_END_THREADSAFE |
|
109 |
|
110 CacheFileHandle::CacheFileHandle(const SHA1Sum::Hash *aHash, bool aPriority) |
|
111 : mHash(aHash) |
|
112 , mIsDoomed(false) |
|
113 , mPriority(aPriority) |
|
114 , mClosed(false) |
|
115 , mInvalid(false) |
|
116 , mFileExists(false) |
|
117 , mFileSize(-1) |
|
118 , mFD(nullptr) |
|
119 { |
|
120 LOG(("CacheFileHandle::CacheFileHandle() [this=%p, hash=%08x%08x%08x%08x%08x]" |
|
121 , this, LOGSHA1(aHash))); |
|
122 } |
|
123 |
|
124 CacheFileHandle::CacheFileHandle(const nsACString &aKey, bool aPriority) |
|
125 : mHash(nullptr) |
|
126 , mIsDoomed(false) |
|
127 , mPriority(aPriority) |
|
128 , mClosed(false) |
|
129 , mInvalid(false) |
|
130 , mFileExists(false) |
|
131 , mFileSize(-1) |
|
132 , mFD(nullptr) |
|
133 , mKey(aKey) |
|
134 { |
|
135 LOG(("CacheFileHandle::CacheFileHandle() [this=%p, key=%s]", this, |
|
136 PromiseFlatCString(aKey).get())); |
|
137 } |
|
138 |
|
139 CacheFileHandle::~CacheFileHandle() |
|
140 { |
|
141 LOG(("CacheFileHandle::~CacheFileHandle() [this=%p]", this)); |
|
142 |
|
143 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
144 |
|
145 nsRefPtr<CacheFileIOManager> ioMan = CacheFileIOManager::gInstance; |
|
146 if (ioMan) { |
|
147 ioMan->CloseHandleInternal(this); |
|
148 } |
|
149 } |
|
150 |
|
151 void |
|
152 CacheFileHandle::Log() |
|
153 { |
|
154 nsAutoCString leafName; |
|
155 if (mFile) { |
|
156 mFile->GetNativeLeafName(leafName); |
|
157 } |
|
158 |
|
159 if (!mHash) { |
|
160 // special file |
|
161 LOG(("CacheFileHandle::Log() [this=%p, hash=nullptr, isDoomed=%d, " |
|
162 "priority=%d, closed=%d, invalid=%d, " |
|
163 "fileExists=%d, fileSize=%lld, leafName=%s, key=%s]", |
|
164 this, mIsDoomed, mPriority, mClosed, mInvalid, |
|
165 mFileExists, mFileSize, leafName.get(), mKey.get())); |
|
166 } else { |
|
167 LOG(("CacheFileHandle::Log() [this=%p, hash=%08x%08x%08x%08x%08x, " |
|
168 "isDoomed=%d, priority=%d, closed=%d, invalid=%d, " |
|
169 "fileExists=%d, fileSize=%lld, leafName=%s, key=%s]", |
|
170 this, LOGSHA1(mHash), mIsDoomed, mPriority, mClosed, |
|
171 mInvalid, mFileExists, mFileSize, leafName.get(), mKey.get())); |
|
172 } |
|
173 } |
|
174 |
|
175 uint32_t |
|
176 CacheFileHandle::FileSizeInK() const |
|
177 { |
|
178 MOZ_ASSERT(mFileSize != -1); |
|
179 uint64_t size64 = mFileSize; |
|
180 |
|
181 size64 += 0x3FF; |
|
182 size64 >>= 10; |
|
183 |
|
184 uint32_t size; |
|
185 if (size64 >> 32) { |
|
186 NS_WARNING("CacheFileHandle::FileSizeInK() - FileSize is too large, " |
|
187 "truncating to PR_UINT32_MAX"); |
|
188 size = PR_UINT32_MAX; |
|
189 } else { |
|
190 size = static_cast<uint32_t>(size64); |
|
191 } |
|
192 |
|
193 return size; |
|
194 } |
|
195 |
|
196 // Memory reporting |
|
197 |
|
198 size_t |
|
199 CacheFileHandle::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
|
200 { |
|
201 size_t n = 0; |
|
202 nsCOMPtr<nsISizeOf> sizeOf; |
|
203 |
|
204 sizeOf = do_QueryInterface(mFile); |
|
205 if (sizeOf) { |
|
206 n += sizeOf->SizeOfIncludingThis(mallocSizeOf); |
|
207 } |
|
208 |
|
209 n += mallocSizeOf(mFD); |
|
210 n += mKey.SizeOfExcludingThisIfUnshared(mallocSizeOf); |
|
211 return n; |
|
212 } |
|
213 |
|
214 size_t |
|
215 CacheFileHandle::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
|
216 { |
|
217 return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf); |
|
218 } |
|
219 |
|
220 /****************************************************************************** |
|
221 * CacheFileHandles::HandleHashKey |
|
222 *****************************************************************************/ |
|
223 |
|
224 void |
|
225 CacheFileHandles::HandleHashKey::AddHandle(CacheFileHandle* aHandle) |
|
226 { |
|
227 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
228 |
|
229 mHandles.InsertElementAt(0, aHandle); |
|
230 } |
|
231 |
|
232 void |
|
233 CacheFileHandles::HandleHashKey::RemoveHandle(CacheFileHandle* aHandle) |
|
234 { |
|
235 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
236 |
|
237 DebugOnly<bool> found; |
|
238 found = mHandles.RemoveElement(aHandle); |
|
239 MOZ_ASSERT(found); |
|
240 } |
|
241 |
|
242 already_AddRefed<CacheFileHandle> |
|
243 CacheFileHandles::HandleHashKey::GetNewestHandle() |
|
244 { |
|
245 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
246 |
|
247 nsRefPtr<CacheFileHandle> handle; |
|
248 if (mHandles.Length()) { |
|
249 handle = mHandles[0]; |
|
250 } |
|
251 |
|
252 return handle.forget(); |
|
253 } |
|
254 |
|
255 void |
|
256 CacheFileHandles::HandleHashKey::GetHandles(nsTArray<nsRefPtr<CacheFileHandle> > &aResult) |
|
257 { |
|
258 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
259 |
|
260 for (uint32_t i = 0; i < mHandles.Length(); ++i) { |
|
261 CacheFileHandle* handle = mHandles[i]; |
|
262 aResult.AppendElement(handle); |
|
263 } |
|
264 } |
|
265 |
|
266 #ifdef DEBUG |
|
267 |
|
268 void |
|
269 CacheFileHandles::HandleHashKey::AssertHandlesState() |
|
270 { |
|
271 for (uint32_t i = 0; i < mHandles.Length(); ++i) { |
|
272 CacheFileHandle* handle = mHandles[i]; |
|
273 MOZ_ASSERT(handle->IsDoomed()); |
|
274 } |
|
275 } |
|
276 |
|
277 #endif |
|
278 |
|
279 size_t |
|
280 CacheFileHandles::HandleHashKey::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
|
281 { |
|
282 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
283 |
|
284 size_t n = 0; |
|
285 n += mallocSizeOf(mHash); |
|
286 for (uint32_t i = 0; i < mHandles.Length(); ++i) { |
|
287 n += mHandles[i]->SizeOfIncludingThis(mallocSizeOf); |
|
288 } |
|
289 |
|
290 return n; |
|
291 } |
|
292 |
|
293 /****************************************************************************** |
|
294 * CacheFileHandles |
|
295 *****************************************************************************/ |
|
296 |
|
297 CacheFileHandles::CacheFileHandles() |
|
298 { |
|
299 LOG(("CacheFileHandles::CacheFileHandles() [this=%p]", this)); |
|
300 MOZ_COUNT_CTOR(CacheFileHandles); |
|
301 } |
|
302 |
|
303 CacheFileHandles::~CacheFileHandles() |
|
304 { |
|
305 LOG(("CacheFileHandles::~CacheFileHandles() [this=%p]", this)); |
|
306 MOZ_COUNT_DTOR(CacheFileHandles); |
|
307 } |
|
308 |
|
309 nsresult |
|
310 CacheFileHandles::GetHandle(const SHA1Sum::Hash *aHash, |
|
311 bool aReturnDoomed, |
|
312 CacheFileHandle **_retval) |
|
313 { |
|
314 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
315 MOZ_ASSERT(aHash); |
|
316 |
|
317 #ifdef DEBUG_HANDLES |
|
318 LOG(("CacheFileHandles::GetHandle() [hash=%08x%08x%08x%08x%08x]", |
|
319 LOGSHA1(aHash))); |
|
320 #endif |
|
321 |
|
322 // find hash entry for key |
|
323 HandleHashKey *entry = mTable.GetEntry(*aHash); |
|
324 if (!entry) { |
|
325 LOG(("CacheFileHandles::GetHandle() hash=%08x%08x%08x%08x%08x " |
|
326 "no handle entries found", LOGSHA1(aHash))); |
|
327 return NS_ERROR_NOT_AVAILABLE; |
|
328 } |
|
329 |
|
330 #ifdef DEBUG_HANDLES |
|
331 Log(entry); |
|
332 #endif |
|
333 |
|
334 // Check if the entry is doomed |
|
335 nsRefPtr<CacheFileHandle> handle = entry->GetNewestHandle(); |
|
336 if (!handle) { |
|
337 LOG(("CacheFileHandles::GetHandle() hash=%08x%08x%08x%08x%08x " |
|
338 "no handle found %p, entry %p", LOGSHA1(aHash), handle.get(), entry)); |
|
339 return NS_ERROR_NOT_AVAILABLE; |
|
340 } |
|
341 |
|
342 if (handle->IsDoomed()) { |
|
343 LOG(("CacheFileHandles::GetHandle() hash=%08x%08x%08x%08x%08x " |
|
344 "found doomed handle %p, entry %p", LOGSHA1(aHash), handle.get(), entry)); |
|
345 |
|
346 // If the consumer doesn't want doomed handles, exit with NOT_AVAIL. |
|
347 if (!aReturnDoomed) { |
|
348 return NS_ERROR_NOT_AVAILABLE; |
|
349 } |
|
350 } else { |
|
351 LOG(("CacheFileHandles::GetHandle() hash=%08x%08x%08x%08x%08x " |
|
352 "found handle %p, entry %p", LOGSHA1(aHash), handle.get(), entry)); |
|
353 } |
|
354 |
|
355 handle.forget(_retval); |
|
356 return NS_OK; |
|
357 } |
|
358 |
|
359 |
|
360 nsresult |
|
361 CacheFileHandles::NewHandle(const SHA1Sum::Hash *aHash, |
|
362 bool aPriority, |
|
363 CacheFileHandle **_retval) |
|
364 { |
|
365 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
366 MOZ_ASSERT(aHash); |
|
367 |
|
368 #ifdef DEBUG_HANDLES |
|
369 LOG(("CacheFileHandles::NewHandle() [hash=%08x%08x%08x%08x%08x]", LOGSHA1(aHash))); |
|
370 #endif |
|
371 |
|
372 // find hash entry for key |
|
373 HandleHashKey *entry = mTable.PutEntry(*aHash); |
|
374 |
|
375 #ifdef DEBUG_HANDLES |
|
376 Log(entry); |
|
377 #endif |
|
378 |
|
379 #ifdef DEBUG |
|
380 entry->AssertHandlesState(); |
|
381 #endif |
|
382 |
|
383 nsRefPtr<CacheFileHandle> handle = new CacheFileHandle(entry->Hash(), aPriority); |
|
384 entry->AddHandle(handle); |
|
385 |
|
386 LOG(("CacheFileHandles::NewHandle() hash=%08x%08x%08x%08x%08x " |
|
387 "created new handle %p, entry=%p", LOGSHA1(aHash), handle.get(), entry)); |
|
388 |
|
389 handle.forget(_retval); |
|
390 return NS_OK; |
|
391 } |
|
392 |
|
393 void |
|
394 CacheFileHandles::RemoveHandle(CacheFileHandle *aHandle) |
|
395 { |
|
396 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
397 MOZ_ASSERT(aHandle); |
|
398 |
|
399 if (!aHandle) { |
|
400 return; |
|
401 } |
|
402 |
|
403 #ifdef DEBUG_HANDLES |
|
404 LOG(("CacheFileHandles::RemoveHandle() [handle=%p, hash=%08x%08x%08x%08x%08x]" |
|
405 , aHandle, LOGSHA1(aHandle->Hash()))); |
|
406 #endif |
|
407 |
|
408 // find hash entry for key |
|
409 HandleHashKey *entry = mTable.GetEntry(*aHandle->Hash()); |
|
410 if (!entry) { |
|
411 MOZ_ASSERT(CacheFileIOManager::IsShutdown(), |
|
412 "Should find entry when removing a handle before shutdown"); |
|
413 |
|
414 LOG(("CacheFileHandles::RemoveHandle() hash=%08x%08x%08x%08x%08x " |
|
415 "no entries found", LOGSHA1(aHandle->Hash()))); |
|
416 return; |
|
417 } |
|
418 |
|
419 #ifdef DEBUG_HANDLES |
|
420 Log(entry); |
|
421 #endif |
|
422 |
|
423 LOG(("CacheFileHandles::RemoveHandle() hash=%08x%08x%08x%08x%08x " |
|
424 "removing handle %p", LOGSHA1(entry->Hash()), aHandle)); |
|
425 entry->RemoveHandle(aHandle); |
|
426 |
|
427 if (entry->IsEmpty()) { |
|
428 LOG(("CacheFileHandles::RemoveHandle() hash=%08x%08x%08x%08x%08x " |
|
429 "list is empty, removing entry %p", LOGSHA1(entry->Hash()), entry)); |
|
430 mTable.RemoveEntry(*entry->Hash()); |
|
431 } |
|
432 } |
|
433 |
|
434 static PLDHashOperator |
|
435 GetAllHandlesEnum(CacheFileHandles::HandleHashKey* aEntry, void *aClosure) |
|
436 { |
|
437 nsTArray<nsRefPtr<CacheFileHandle> > *array = |
|
438 static_cast<nsTArray<nsRefPtr<CacheFileHandle> > *>(aClosure); |
|
439 |
|
440 aEntry->GetHandles(*array); |
|
441 return PL_DHASH_NEXT; |
|
442 } |
|
443 |
|
444 void |
|
445 CacheFileHandles::GetAllHandles(nsTArray<nsRefPtr<CacheFileHandle> > *_retval) |
|
446 { |
|
447 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
448 mTable.EnumerateEntries(&GetAllHandlesEnum, _retval); |
|
449 } |
|
450 |
|
451 static PLDHashOperator |
|
452 GetActiveHandlesEnum(CacheFileHandles::HandleHashKey* aEntry, void *aClosure) |
|
453 { |
|
454 nsTArray<nsRefPtr<CacheFileHandle> > *array = |
|
455 static_cast<nsTArray<nsRefPtr<CacheFileHandle> > *>(aClosure); |
|
456 |
|
457 nsRefPtr<CacheFileHandle> handle = aEntry->GetNewestHandle(); |
|
458 MOZ_ASSERT(handle); |
|
459 |
|
460 if (!handle->IsDoomed()) { |
|
461 array->AppendElement(handle); |
|
462 } |
|
463 |
|
464 return PL_DHASH_NEXT; |
|
465 } |
|
466 |
|
467 void |
|
468 CacheFileHandles::GetActiveHandles( |
|
469 nsTArray<nsRefPtr<CacheFileHandle> > *_retval) |
|
470 { |
|
471 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
472 mTable.EnumerateEntries(&GetActiveHandlesEnum, _retval); |
|
473 } |
|
474 |
|
475 void |
|
476 CacheFileHandles::ClearAll() |
|
477 { |
|
478 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
479 mTable.Clear(); |
|
480 } |
|
481 |
|
482 uint32_t |
|
483 CacheFileHandles::HandleCount() |
|
484 { |
|
485 return mTable.Count(); |
|
486 } |
|
487 |
|
488 #ifdef DEBUG_HANDLES |
|
489 void |
|
490 CacheFileHandles::Log(CacheFileHandlesEntry *entry) |
|
491 { |
|
492 LOG(("CacheFileHandles::Log() BEGIN [entry=%p]", entry)); |
|
493 |
|
494 nsTArray<nsRefPtr<CacheFileHandle> > array; |
|
495 aEntry->GetHandles(array); |
|
496 |
|
497 for (uint32_t i = 0; i < array.Length(); ++i) { |
|
498 CacheFileHandle *handle = array[i]; |
|
499 handle->Log(); |
|
500 } |
|
501 |
|
502 LOG(("CacheFileHandles::Log() END [entry=%p]", entry)); |
|
503 } |
|
504 #endif |
|
505 |
|
506 // Memory reporting |
|
507 |
|
508 namespace { // anon |
|
509 |
|
510 size_t |
|
511 CollectHandlesMemory(CacheFileHandles::HandleHashKey* key, |
|
512 mozilla::MallocSizeOf mallocSizeOf, |
|
513 void *arg) |
|
514 { |
|
515 return key->SizeOfExcludingThis(mallocSizeOf); |
|
516 } |
|
517 |
|
518 } // anon |
|
519 |
|
520 size_t |
|
521 CacheFileHandles::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
|
522 { |
|
523 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
524 |
|
525 return mTable.SizeOfExcludingThis(&CollectHandlesMemory, mallocSizeOf); |
|
526 } |
|
527 |
|
528 // Events |
|
529 |
|
530 class ShutdownEvent : public nsRunnable { |
|
531 public: |
|
532 ShutdownEvent(mozilla::Mutex *aLock, mozilla::CondVar *aCondVar) |
|
533 : mLock(aLock) |
|
534 , mCondVar(aCondVar) |
|
535 { |
|
536 MOZ_COUNT_CTOR(ShutdownEvent); |
|
537 } |
|
538 |
|
539 ~ShutdownEvent() |
|
540 { |
|
541 MOZ_COUNT_DTOR(ShutdownEvent); |
|
542 } |
|
543 |
|
544 NS_IMETHOD Run() |
|
545 { |
|
546 MutexAutoLock lock(*mLock); |
|
547 |
|
548 CacheFileIOManager::gInstance->ShutdownInternal(); |
|
549 |
|
550 mCondVar->Notify(); |
|
551 return NS_OK; |
|
552 } |
|
553 |
|
554 protected: |
|
555 mozilla::Mutex *mLock; |
|
556 mozilla::CondVar *mCondVar; |
|
557 }; |
|
558 |
|
559 class OpenFileEvent : public nsRunnable { |
|
560 public: |
|
561 OpenFileEvent(const nsACString &aKey, |
|
562 uint32_t aFlags, bool aResultOnAnyThread, |
|
563 CacheFileIOListener *aCallback) |
|
564 : mFlags(aFlags) |
|
565 , mResultOnAnyThread(aResultOnAnyThread) |
|
566 , mCallback(aCallback) |
|
567 , mRV(NS_ERROR_FAILURE) |
|
568 , mKey(aKey) |
|
569 { |
|
570 MOZ_COUNT_CTOR(OpenFileEvent); |
|
571 |
|
572 if (!aResultOnAnyThread) { |
|
573 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
574 MOZ_ASSERT(mTarget); |
|
575 } |
|
576 |
|
577 mIOMan = CacheFileIOManager::gInstance; |
|
578 |
|
579 MOZ_EVENT_TRACER_NAME_OBJECT(static_cast<nsIRunnable*>(this), aKey.BeginReading()); |
|
580 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::open-background"); |
|
581 } |
|
582 |
|
583 ~OpenFileEvent() |
|
584 { |
|
585 MOZ_COUNT_DTOR(OpenFileEvent); |
|
586 } |
|
587 |
|
588 NS_IMETHOD Run() |
|
589 { |
|
590 if (mResultOnAnyThread || mTarget) { |
|
591 mRV = NS_OK; |
|
592 |
|
593 if (!(mFlags & CacheFileIOManager::SPECIAL_FILE)) { |
|
594 SHA1Sum sum; |
|
595 sum.update(mKey.BeginReading(), mKey.Length()); |
|
596 sum.finish(mHash); |
|
597 } |
|
598 |
|
599 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), |
|
600 "net::cache::open-background"); |
|
601 if (NS_SUCCEEDED(mRV)) { |
|
602 if (!mIOMan) { |
|
603 mRV = NS_ERROR_NOT_INITIALIZED; |
|
604 } else { |
|
605 if (mFlags & CacheFileIOManager::SPECIAL_FILE) { |
|
606 mRV = mIOMan->OpenSpecialFileInternal(mKey, mFlags, |
|
607 getter_AddRefs(mHandle)); |
|
608 } else { |
|
609 mRV = mIOMan->OpenFileInternal(&mHash, mKey, mFlags, |
|
610 getter_AddRefs(mHandle)); |
|
611 } |
|
612 mIOMan = nullptr; |
|
613 if (mHandle) { |
|
614 MOZ_EVENT_TRACER_NAME_OBJECT(mHandle.get(), mKey.get()); |
|
615 if (mHandle->Key().IsEmpty()) { |
|
616 mHandle->Key() = mKey; |
|
617 } |
|
618 } |
|
619 } |
|
620 } |
|
621 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::open-background"); |
|
622 |
|
623 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::open-result"); |
|
624 |
|
625 if (mTarget) { |
|
626 nsCOMPtr<nsIEventTarget> target; |
|
627 mTarget.swap(target); |
|
628 return target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
629 } |
|
630 } |
|
631 |
|
632 if (!mTarget) { |
|
633 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::open-result"); |
|
634 mCallback->OnFileOpened(mHandle, mRV); |
|
635 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::open-result"); |
|
636 } |
|
637 |
|
638 return NS_OK; |
|
639 } |
|
640 |
|
641 protected: |
|
642 SHA1Sum::Hash mHash; |
|
643 uint32_t mFlags; |
|
644 bool mResultOnAnyThread; |
|
645 nsCOMPtr<CacheFileIOListener> mCallback; |
|
646 nsCOMPtr<nsIEventTarget> mTarget; |
|
647 nsRefPtr<CacheFileIOManager> mIOMan; |
|
648 nsRefPtr<CacheFileHandle> mHandle; |
|
649 nsresult mRV; |
|
650 nsCString mKey; |
|
651 }; |
|
652 |
|
653 class ReadEvent : public nsRunnable { |
|
654 public: |
|
655 ReadEvent(CacheFileHandle *aHandle, int64_t aOffset, char *aBuf, |
|
656 int32_t aCount, bool aResultOnAnyThread, CacheFileIOListener *aCallback) |
|
657 : mHandle(aHandle) |
|
658 , mOffset(aOffset) |
|
659 , mBuf(aBuf) |
|
660 , mCount(aCount) |
|
661 , mResultOnAnyThread(aResultOnAnyThread) |
|
662 , mCallback(aCallback) |
|
663 , mRV(NS_ERROR_FAILURE) |
|
664 { |
|
665 MOZ_COUNT_CTOR(ReadEvent); |
|
666 |
|
667 if (!aResultOnAnyThread) { |
|
668 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
669 } |
|
670 |
|
671 MOZ_EVENT_TRACER_NAME_OBJECT(static_cast<nsIRunnable*>(this), aHandle->Key().get()); |
|
672 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::read-background"); |
|
673 } |
|
674 |
|
675 ~ReadEvent() |
|
676 { |
|
677 MOZ_COUNT_DTOR(ReadEvent); |
|
678 } |
|
679 |
|
680 NS_IMETHOD Run() |
|
681 { |
|
682 if (mResultOnAnyThread || mTarget) { |
|
683 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::read-background"); |
|
684 if (mHandle->IsClosed()) { |
|
685 mRV = NS_ERROR_NOT_INITIALIZED; |
|
686 } else { |
|
687 mRV = CacheFileIOManager::gInstance->ReadInternal( |
|
688 mHandle, mOffset, mBuf, mCount); |
|
689 } |
|
690 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::read-background"); |
|
691 |
|
692 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::read-result"); |
|
693 |
|
694 if (mTarget) { |
|
695 nsCOMPtr<nsIEventTarget> target; |
|
696 mTarget.swap(target); |
|
697 return target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
698 } |
|
699 } |
|
700 |
|
701 if (!mTarget && mCallback) { |
|
702 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::read-result"); |
|
703 mCallback->OnDataRead(mHandle, mBuf, mRV); |
|
704 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::read-result"); |
|
705 } |
|
706 |
|
707 return NS_OK; |
|
708 } |
|
709 |
|
710 protected: |
|
711 nsRefPtr<CacheFileHandle> mHandle; |
|
712 int64_t mOffset; |
|
713 char *mBuf; |
|
714 int32_t mCount; |
|
715 bool mResultOnAnyThread; |
|
716 nsCOMPtr<CacheFileIOListener> mCallback; |
|
717 nsCOMPtr<nsIEventTarget> mTarget; |
|
718 nsresult mRV; |
|
719 }; |
|
720 |
|
721 class WriteEvent : public nsRunnable { |
|
722 public: |
|
723 WriteEvent(CacheFileHandle *aHandle, int64_t aOffset, const char *aBuf, |
|
724 int32_t aCount, bool aValidate, CacheFileIOListener *aCallback) |
|
725 : mHandle(aHandle) |
|
726 , mOffset(aOffset) |
|
727 , mBuf(aBuf) |
|
728 , mCount(aCount) |
|
729 , mValidate(aValidate) |
|
730 , mCallback(aCallback) |
|
731 , mRV(NS_ERROR_FAILURE) |
|
732 { |
|
733 MOZ_COUNT_CTOR(WriteEvent); |
|
734 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
735 |
|
736 MOZ_EVENT_TRACER_NAME_OBJECT(static_cast<nsIRunnable*>(this), aHandle->Key().get()); |
|
737 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::write-background"); |
|
738 } |
|
739 |
|
740 ~WriteEvent() |
|
741 { |
|
742 MOZ_COUNT_DTOR(WriteEvent); |
|
743 |
|
744 if (!mCallback && mBuf) { |
|
745 free(const_cast<char *>(mBuf)); |
|
746 } |
|
747 } |
|
748 |
|
749 NS_IMETHOD Run() |
|
750 { |
|
751 if (mTarget) { |
|
752 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-background"); |
|
753 if (mHandle->IsClosed()) { |
|
754 mRV = NS_ERROR_NOT_INITIALIZED; |
|
755 } else { |
|
756 mRV = CacheFileIOManager::gInstance->WriteInternal( |
|
757 mHandle, mOffset, mBuf, mCount, mValidate); |
|
758 } |
|
759 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::write-background"); |
|
760 |
|
761 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::write-result"); |
|
762 nsCOMPtr<nsIEventTarget> target; |
|
763 mTarget.swap(target); |
|
764 target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
765 } else { |
|
766 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-result"); |
|
767 if (mCallback) { |
|
768 mCallback->OnDataWritten(mHandle, mBuf, mRV); |
|
769 } else { |
|
770 free(const_cast<char *>(mBuf)); |
|
771 mBuf = nullptr; |
|
772 } |
|
773 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::write-result"); |
|
774 } |
|
775 return NS_OK; |
|
776 } |
|
777 |
|
778 protected: |
|
779 nsRefPtr<CacheFileHandle> mHandle; |
|
780 int64_t mOffset; |
|
781 const char *mBuf; |
|
782 int32_t mCount; |
|
783 bool mValidate; |
|
784 nsCOMPtr<CacheFileIOListener> mCallback; |
|
785 nsCOMPtr<nsIEventTarget> mTarget; |
|
786 nsresult mRV; |
|
787 }; |
|
788 |
|
789 class DoomFileEvent : public nsRunnable { |
|
790 public: |
|
791 DoomFileEvent(CacheFileHandle *aHandle, |
|
792 CacheFileIOListener *aCallback) |
|
793 : mCallback(aCallback) |
|
794 , mHandle(aHandle) |
|
795 , mRV(NS_ERROR_FAILURE) |
|
796 { |
|
797 MOZ_COUNT_CTOR(DoomFileEvent); |
|
798 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
799 |
|
800 MOZ_EVENT_TRACER_NAME_OBJECT(static_cast<nsIRunnable*>(this), aHandle->Key().get()); |
|
801 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::doom-background"); |
|
802 } |
|
803 |
|
804 ~DoomFileEvent() |
|
805 { |
|
806 MOZ_COUNT_DTOR(DoomFileEvent); |
|
807 } |
|
808 |
|
809 NS_IMETHOD Run() |
|
810 { |
|
811 if (mTarget) { |
|
812 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::doom-background"); |
|
813 if (mHandle->IsClosed()) { |
|
814 mRV = NS_ERROR_NOT_INITIALIZED; |
|
815 } else { |
|
816 mRV = CacheFileIOManager::gInstance->DoomFileInternal(mHandle); |
|
817 } |
|
818 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::doom-background"); |
|
819 |
|
820 MOZ_EVENT_TRACER_WAIT(static_cast<nsIRunnable*>(this), "net::cache::doom-result"); |
|
821 nsCOMPtr<nsIEventTarget> target; |
|
822 mTarget.swap(target); |
|
823 target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
824 } else { |
|
825 MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::doom-result"); |
|
826 if (mCallback) { |
|
827 mCallback->OnFileDoomed(mHandle, mRV); |
|
828 } |
|
829 MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::doom-result"); |
|
830 } |
|
831 return NS_OK; |
|
832 } |
|
833 |
|
834 protected: |
|
835 nsCOMPtr<CacheFileIOListener> mCallback; |
|
836 nsCOMPtr<nsIEventTarget> mTarget; |
|
837 nsRefPtr<CacheFileHandle> mHandle; |
|
838 nsresult mRV; |
|
839 }; |
|
840 |
|
841 class DoomFileByKeyEvent : public nsRunnable { |
|
842 public: |
|
843 DoomFileByKeyEvent(const nsACString &aKey, |
|
844 CacheFileIOListener *aCallback) |
|
845 : mCallback(aCallback) |
|
846 , mRV(NS_ERROR_FAILURE) |
|
847 { |
|
848 MOZ_COUNT_CTOR(DoomFileByKeyEvent); |
|
849 |
|
850 SHA1Sum sum; |
|
851 sum.update(aKey.BeginReading(), aKey.Length()); |
|
852 sum.finish(mHash); |
|
853 |
|
854 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
855 mIOMan = CacheFileIOManager::gInstance; |
|
856 MOZ_ASSERT(mTarget); |
|
857 } |
|
858 |
|
859 ~DoomFileByKeyEvent() |
|
860 { |
|
861 MOZ_COUNT_DTOR(DoomFileByKeyEvent); |
|
862 } |
|
863 |
|
864 NS_IMETHOD Run() |
|
865 { |
|
866 if (mTarget) { |
|
867 if (!mIOMan) { |
|
868 mRV = NS_ERROR_NOT_INITIALIZED; |
|
869 } else { |
|
870 mRV = mIOMan->DoomFileByKeyInternal(&mHash); |
|
871 mIOMan = nullptr; |
|
872 } |
|
873 |
|
874 nsCOMPtr<nsIEventTarget> target; |
|
875 mTarget.swap(target); |
|
876 target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
877 } else { |
|
878 if (mCallback) { |
|
879 mCallback->OnFileDoomed(nullptr, mRV); |
|
880 } |
|
881 } |
|
882 return NS_OK; |
|
883 } |
|
884 |
|
885 protected: |
|
886 SHA1Sum::Hash mHash; |
|
887 nsCOMPtr<CacheFileIOListener> mCallback; |
|
888 nsCOMPtr<nsIEventTarget> mTarget; |
|
889 nsRefPtr<CacheFileIOManager> mIOMan; |
|
890 nsresult mRV; |
|
891 }; |
|
892 |
|
893 class ReleaseNSPRHandleEvent : public nsRunnable { |
|
894 public: |
|
895 ReleaseNSPRHandleEvent(CacheFileHandle *aHandle) |
|
896 : mHandle(aHandle) |
|
897 { |
|
898 MOZ_COUNT_CTOR(ReleaseNSPRHandleEvent); |
|
899 } |
|
900 |
|
901 ~ReleaseNSPRHandleEvent() |
|
902 { |
|
903 MOZ_COUNT_DTOR(ReleaseNSPRHandleEvent); |
|
904 } |
|
905 |
|
906 NS_IMETHOD Run() |
|
907 { |
|
908 if (mHandle->mFD && !mHandle->IsClosed()) { |
|
909 CacheFileIOManager::gInstance->ReleaseNSPRHandleInternal(mHandle); |
|
910 } |
|
911 |
|
912 return NS_OK; |
|
913 } |
|
914 |
|
915 protected: |
|
916 nsRefPtr<CacheFileHandle> mHandle; |
|
917 }; |
|
918 |
|
919 class TruncateSeekSetEOFEvent : public nsRunnable { |
|
920 public: |
|
921 TruncateSeekSetEOFEvent(CacheFileHandle *aHandle, int64_t aTruncatePos, |
|
922 int64_t aEOFPos, CacheFileIOListener *aCallback) |
|
923 : mHandle(aHandle) |
|
924 , mTruncatePos(aTruncatePos) |
|
925 , mEOFPos(aEOFPos) |
|
926 , mCallback(aCallback) |
|
927 , mRV(NS_ERROR_FAILURE) |
|
928 { |
|
929 MOZ_COUNT_CTOR(TruncateSeekSetEOFEvent); |
|
930 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
931 } |
|
932 |
|
933 ~TruncateSeekSetEOFEvent() |
|
934 { |
|
935 MOZ_COUNT_DTOR(TruncateSeekSetEOFEvent); |
|
936 } |
|
937 |
|
938 NS_IMETHOD Run() |
|
939 { |
|
940 if (mTarget) { |
|
941 if (mHandle->IsClosed()) { |
|
942 mRV = NS_ERROR_NOT_INITIALIZED; |
|
943 } else { |
|
944 mRV = CacheFileIOManager::gInstance->TruncateSeekSetEOFInternal( |
|
945 mHandle, mTruncatePos, mEOFPos); |
|
946 } |
|
947 |
|
948 nsCOMPtr<nsIEventTarget> target; |
|
949 mTarget.swap(target); |
|
950 target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
951 } else { |
|
952 if (mCallback) { |
|
953 mCallback->OnEOFSet(mHandle, mRV); |
|
954 } |
|
955 } |
|
956 return NS_OK; |
|
957 } |
|
958 |
|
959 protected: |
|
960 nsRefPtr<CacheFileHandle> mHandle; |
|
961 int64_t mTruncatePos; |
|
962 int64_t mEOFPos; |
|
963 nsCOMPtr<CacheFileIOListener> mCallback; |
|
964 nsCOMPtr<nsIEventTarget> mTarget; |
|
965 nsresult mRV; |
|
966 }; |
|
967 |
|
968 class RenameFileEvent : public nsRunnable { |
|
969 public: |
|
970 RenameFileEvent(CacheFileHandle *aHandle, const nsACString &aNewName, |
|
971 CacheFileIOListener *aCallback) |
|
972 : mHandle(aHandle) |
|
973 , mNewName(aNewName) |
|
974 , mCallback(aCallback) |
|
975 , mRV(NS_ERROR_FAILURE) |
|
976 { |
|
977 MOZ_COUNT_CTOR(RenameFileEvent); |
|
978 mTarget = static_cast<nsIEventTarget*>(NS_GetCurrentThread()); |
|
979 } |
|
980 |
|
981 ~RenameFileEvent() |
|
982 { |
|
983 MOZ_COUNT_DTOR(RenameFileEvent); |
|
984 } |
|
985 |
|
986 NS_IMETHOD Run() |
|
987 { |
|
988 if (mTarget) { |
|
989 if (mHandle->IsClosed()) { |
|
990 mRV = NS_ERROR_NOT_INITIALIZED; |
|
991 } else { |
|
992 mRV = CacheFileIOManager::gInstance->RenameFileInternal(mHandle, |
|
993 mNewName); |
|
994 } |
|
995 |
|
996 nsCOMPtr<nsIEventTarget> target; |
|
997 mTarget.swap(target); |
|
998 target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
999 } else { |
|
1000 if (mCallback) { |
|
1001 mCallback->OnFileRenamed(mHandle, mRV); |
|
1002 } |
|
1003 } |
|
1004 return NS_OK; |
|
1005 } |
|
1006 |
|
1007 protected: |
|
1008 nsRefPtr<CacheFileHandle> mHandle; |
|
1009 nsCString mNewName; |
|
1010 nsCOMPtr<CacheFileIOListener> mCallback; |
|
1011 nsCOMPtr<nsIEventTarget> mTarget; |
|
1012 nsresult mRV; |
|
1013 }; |
|
1014 |
|
1015 class InitIndexEntryEvent : public nsRunnable { |
|
1016 public: |
|
1017 InitIndexEntryEvent(CacheFileHandle *aHandle, uint32_t aAppId, |
|
1018 bool aAnonymous, bool aInBrowser) |
|
1019 : mHandle(aHandle) |
|
1020 , mAppId(aAppId) |
|
1021 , mAnonymous(aAnonymous) |
|
1022 , mInBrowser(aInBrowser) |
|
1023 { |
|
1024 MOZ_COUNT_CTOR(InitIndexEntryEvent); |
|
1025 } |
|
1026 |
|
1027 ~InitIndexEntryEvent() |
|
1028 { |
|
1029 MOZ_COUNT_DTOR(InitIndexEntryEvent); |
|
1030 } |
|
1031 |
|
1032 NS_IMETHOD Run() |
|
1033 { |
|
1034 if (mHandle->IsClosed() || mHandle->IsDoomed()) { |
|
1035 return NS_OK; |
|
1036 } |
|
1037 |
|
1038 CacheIndex::InitEntry(mHandle->Hash(), mAppId, mAnonymous, mInBrowser); |
|
1039 |
|
1040 // We cannot set the filesize before we init the entry. If we're opening |
|
1041 // an existing entry file, frecency and expiration time will be set after |
|
1042 // parsing the entry file, but we must set the filesize here since nobody is |
|
1043 // going to set it if there is no write to the file. |
|
1044 uint32_t sizeInK = mHandle->FileSizeInK(); |
|
1045 CacheIndex::UpdateEntry(mHandle->Hash(), nullptr, nullptr, &sizeInK); |
|
1046 |
|
1047 return NS_OK; |
|
1048 } |
|
1049 |
|
1050 protected: |
|
1051 nsRefPtr<CacheFileHandle> mHandle; |
|
1052 uint32_t mAppId; |
|
1053 bool mAnonymous; |
|
1054 bool mInBrowser; |
|
1055 }; |
|
1056 |
|
1057 class UpdateIndexEntryEvent : public nsRunnable { |
|
1058 public: |
|
1059 UpdateIndexEntryEvent(CacheFileHandle *aHandle, const uint32_t *aFrecency, |
|
1060 const uint32_t *aExpirationTime) |
|
1061 : mHandle(aHandle) |
|
1062 , mHasFrecency(false) |
|
1063 , mHasExpirationTime(false) |
|
1064 { |
|
1065 MOZ_COUNT_CTOR(UpdateIndexEntryEvent); |
|
1066 if (aFrecency) { |
|
1067 mHasFrecency = true; |
|
1068 mFrecency = *aFrecency; |
|
1069 } |
|
1070 if (aExpirationTime) { |
|
1071 mHasExpirationTime = true; |
|
1072 mExpirationTime = *aExpirationTime; |
|
1073 } |
|
1074 } |
|
1075 |
|
1076 ~UpdateIndexEntryEvent() |
|
1077 { |
|
1078 MOZ_COUNT_DTOR(UpdateIndexEntryEvent); |
|
1079 } |
|
1080 |
|
1081 NS_IMETHOD Run() |
|
1082 { |
|
1083 if (mHandle->IsClosed() || mHandle->IsDoomed()) { |
|
1084 return NS_OK; |
|
1085 } |
|
1086 |
|
1087 CacheIndex::UpdateEntry(mHandle->Hash(), |
|
1088 mHasFrecency ? &mFrecency : nullptr, |
|
1089 mHasExpirationTime ? &mExpirationTime : nullptr, |
|
1090 nullptr); |
|
1091 return NS_OK; |
|
1092 } |
|
1093 |
|
1094 protected: |
|
1095 nsRefPtr<CacheFileHandle> mHandle; |
|
1096 bool mHasFrecency; |
|
1097 bool mHasExpirationTime; |
|
1098 uint32_t mFrecency; |
|
1099 uint32_t mExpirationTime; |
|
1100 }; |
|
1101 |
|
1102 class MetadataWriteScheduleEvent : public nsRunnable |
|
1103 { |
|
1104 public: |
|
1105 enum EMode { |
|
1106 SCHEDULE, |
|
1107 UNSCHEDULE, |
|
1108 SHUTDOWN |
|
1109 } mMode; |
|
1110 |
|
1111 nsRefPtr<CacheFile> mFile; |
|
1112 nsRefPtr<CacheFileIOManager> mIOMan; |
|
1113 |
|
1114 MetadataWriteScheduleEvent(CacheFileIOManager * aManager, |
|
1115 CacheFile * aFile, |
|
1116 EMode aMode) |
|
1117 : mMode(aMode) |
|
1118 , mFile(aFile) |
|
1119 , mIOMan(aManager) |
|
1120 { } |
|
1121 |
|
1122 virtual ~MetadataWriteScheduleEvent() { } |
|
1123 |
|
1124 NS_IMETHOD Run() |
|
1125 { |
|
1126 nsRefPtr<CacheFileIOManager> ioMan = CacheFileIOManager::gInstance; |
|
1127 if (!ioMan) { |
|
1128 NS_WARNING("CacheFileIOManager already gone in MetadataWriteScheduleEvent::Run()"); |
|
1129 return NS_OK; |
|
1130 } |
|
1131 |
|
1132 switch (mMode) |
|
1133 { |
|
1134 case SCHEDULE: |
|
1135 ioMan->ScheduleMetadataWriteInternal(mFile); |
|
1136 break; |
|
1137 case UNSCHEDULE: |
|
1138 ioMan->UnscheduleMetadataWriteInternal(mFile); |
|
1139 break; |
|
1140 case SHUTDOWN: |
|
1141 ioMan->ShutdownMetadataWriteSchedulingInternal(); |
|
1142 break; |
|
1143 } |
|
1144 return NS_OK; |
|
1145 } |
|
1146 }; |
|
1147 |
|
1148 CacheFileIOManager * CacheFileIOManager::gInstance = nullptr; |
|
1149 |
|
1150 NS_IMPL_ISUPPORTS(CacheFileIOManager, nsITimerCallback) |
|
1151 |
|
1152 CacheFileIOManager::CacheFileIOManager() |
|
1153 : mShuttingDown(false) |
|
1154 , mTreeCreated(false) |
|
1155 , mOverLimitEvicting(false) |
|
1156 , mRemovingTrashDirs(false) |
|
1157 { |
|
1158 LOG(("CacheFileIOManager::CacheFileIOManager [this=%p]", this)); |
|
1159 MOZ_COUNT_CTOR(CacheFileIOManager); |
|
1160 MOZ_ASSERT(!gInstance, "multiple CacheFileIOManager instances!"); |
|
1161 } |
|
1162 |
|
1163 CacheFileIOManager::~CacheFileIOManager() |
|
1164 { |
|
1165 LOG(("CacheFileIOManager::~CacheFileIOManager [this=%p]", this)); |
|
1166 MOZ_COUNT_DTOR(CacheFileIOManager); |
|
1167 } |
|
1168 |
|
1169 // static |
|
1170 nsresult |
|
1171 CacheFileIOManager::Init() |
|
1172 { |
|
1173 LOG(("CacheFileIOManager::Init()")); |
|
1174 |
|
1175 MOZ_ASSERT(NS_IsMainThread()); |
|
1176 |
|
1177 if (gInstance) { |
|
1178 return NS_ERROR_ALREADY_INITIALIZED; |
|
1179 } |
|
1180 |
|
1181 nsRefPtr<CacheFileIOManager> ioMan = new CacheFileIOManager(); |
|
1182 |
|
1183 nsresult rv = ioMan->InitInternal(); |
|
1184 NS_ENSURE_SUCCESS(rv, rv); |
|
1185 |
|
1186 ioMan.swap(gInstance); |
|
1187 return NS_OK; |
|
1188 } |
|
1189 |
|
1190 nsresult |
|
1191 CacheFileIOManager::InitInternal() |
|
1192 { |
|
1193 nsresult rv; |
|
1194 |
|
1195 mIOThread = new CacheIOThread(); |
|
1196 |
|
1197 rv = mIOThread->Init(); |
|
1198 MOZ_ASSERT(NS_SUCCEEDED(rv), "Can't create background thread"); |
|
1199 NS_ENSURE_SUCCESS(rv, rv); |
|
1200 |
|
1201 mStartTime = TimeStamp::NowLoRes(); |
|
1202 |
|
1203 return NS_OK; |
|
1204 } |
|
1205 |
|
1206 // static |
|
1207 nsresult |
|
1208 CacheFileIOManager::Shutdown() |
|
1209 { |
|
1210 LOG(("CacheFileIOManager::Shutdown() [gInstance=%p]", gInstance)); |
|
1211 |
|
1212 MOZ_ASSERT(NS_IsMainThread()); |
|
1213 |
|
1214 if (!gInstance) { |
|
1215 return NS_ERROR_NOT_INITIALIZED; |
|
1216 } |
|
1217 |
|
1218 Telemetry::AutoTimer<Telemetry::NETWORK_DISK_CACHE_SHUTDOWN_V2> shutdownTimer; |
|
1219 |
|
1220 CacheIndex::PreShutdown(); |
|
1221 |
|
1222 ShutdownMetadataWriteScheduling(); |
|
1223 |
|
1224 { |
|
1225 mozilla::Mutex lock("CacheFileIOManager::Shutdown() lock"); |
|
1226 mozilla::CondVar condVar(lock, "CacheFileIOManager::Shutdown() condVar"); |
|
1227 |
|
1228 MutexAutoLock autoLock(lock); |
|
1229 nsRefPtr<ShutdownEvent> ev = new ShutdownEvent(&lock, &condVar); |
|
1230 DebugOnly<nsresult> rv; |
|
1231 rv = gInstance->mIOThread->Dispatch(ev, CacheIOThread::CLOSE); |
|
1232 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
1233 condVar.Wait(); |
|
1234 } |
|
1235 |
|
1236 MOZ_ASSERT(gInstance->mHandles.HandleCount() == 0); |
|
1237 MOZ_ASSERT(gInstance->mHandlesByLastUsed.Length() == 0); |
|
1238 |
|
1239 if (gInstance->mIOThread) { |
|
1240 gInstance->mIOThread->Shutdown(); |
|
1241 } |
|
1242 |
|
1243 CacheIndex::Shutdown(); |
|
1244 |
|
1245 if (CacheObserver::ClearCacheOnShutdown()) { |
|
1246 gInstance->SyncRemoveAllCacheFiles(); |
|
1247 } |
|
1248 |
|
1249 nsRefPtr<CacheFileIOManager> ioMan; |
|
1250 ioMan.swap(gInstance); |
|
1251 |
|
1252 return NS_OK; |
|
1253 } |
|
1254 |
|
1255 nsresult |
|
1256 CacheFileIOManager::ShutdownInternal() |
|
1257 { |
|
1258 LOG(("CacheFileIOManager::ShutdownInternal() [this=%p]", this)); |
|
1259 |
|
1260 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
1261 |
|
1262 // No new handles can be created after this flag is set |
|
1263 mShuttingDown = true; |
|
1264 |
|
1265 // close all handles and delete all associated files |
|
1266 nsTArray<nsRefPtr<CacheFileHandle> > handles; |
|
1267 mHandles.GetAllHandles(&handles); |
|
1268 handles.AppendElements(mSpecialHandles); |
|
1269 |
|
1270 for (uint32_t i=0 ; i<handles.Length() ; i++) { |
|
1271 CacheFileHandle *h = handles[i]; |
|
1272 h->mClosed = true; |
|
1273 |
|
1274 h->Log(); |
|
1275 |
|
1276 // Close file handle |
|
1277 if (h->mFD) { |
|
1278 ReleaseNSPRHandleInternal(h); |
|
1279 } |
|
1280 |
|
1281 // Remove file if entry is doomed or invalid |
|
1282 if (h->mFileExists && (h->mIsDoomed || h->mInvalid)) { |
|
1283 LOG(("CacheFileIOManager::ShutdownInternal() - Removing file from disk")); |
|
1284 h->mFile->Remove(false); |
|
1285 } |
|
1286 |
|
1287 if (!h->IsSpecialFile() && !h->mIsDoomed && |
|
1288 (h->mInvalid || !h->mFileExists)) { |
|
1289 CacheIndex::RemoveEntry(h->Hash()); |
|
1290 } |
|
1291 |
|
1292 // Remove the handle from mHandles/mSpecialHandles |
|
1293 if (h->IsSpecialFile()) { |
|
1294 mSpecialHandles.RemoveElement(h); |
|
1295 } else { |
|
1296 mHandles.RemoveHandle(h); |
|
1297 } |
|
1298 } |
|
1299 |
|
1300 // Assert the table is empty. When we are here, no new handles can be added |
|
1301 // and handles will no longer remove them self from this table and we don't |
|
1302 // want to keep invalid handles here. Also, there is no lookup after this |
|
1303 // point to happen. |
|
1304 MOZ_ASSERT(mHandles.HandleCount() == 0); |
|
1305 |
|
1306 // Release trash directory enumerator |
|
1307 if (mTrashDirEnumerator) { |
|
1308 mTrashDirEnumerator->Close(); |
|
1309 mTrashDirEnumerator = nullptr; |
|
1310 } |
|
1311 |
|
1312 return NS_OK; |
|
1313 } |
|
1314 |
|
1315 // static |
|
1316 nsresult |
|
1317 CacheFileIOManager::OnProfile() |
|
1318 { |
|
1319 LOG(("CacheFileIOManager::OnProfile() [gInstance=%p]", gInstance)); |
|
1320 |
|
1321 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1322 if (!ioMan) { |
|
1323 // CacheFileIOManager::Init() failed, probably could not create the IO |
|
1324 // thread, just go with it... |
|
1325 return NS_ERROR_NOT_INITIALIZED; |
|
1326 } |
|
1327 |
|
1328 nsresult rv; |
|
1329 |
|
1330 nsCOMPtr<nsIFile> directory; |
|
1331 |
|
1332 CacheObserver::ParentDirOverride(getter_AddRefs(directory)); |
|
1333 |
|
1334 #if defined(MOZ_WIDGET_ANDROID) |
|
1335 char* cachePath = getenv("CACHE_DIRECTORY"); |
|
1336 if (!directory && cachePath && *cachePath) { |
|
1337 rv = NS_NewNativeLocalFile(nsDependentCString(cachePath), |
|
1338 true, getter_AddRefs(directory)); |
|
1339 } |
|
1340 #endif |
|
1341 |
|
1342 if (!directory) { |
|
1343 rv = NS_GetSpecialDirectory(NS_APP_CACHE_PARENT_DIR, |
|
1344 getter_AddRefs(directory)); |
|
1345 } |
|
1346 |
|
1347 if (!directory) { |
|
1348 rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, |
|
1349 getter_AddRefs(directory)); |
|
1350 } |
|
1351 |
|
1352 if (directory) { |
|
1353 rv = directory->Append(NS_LITERAL_STRING("cache2")); |
|
1354 NS_ENSURE_SUCCESS(rv, rv); |
|
1355 } |
|
1356 |
|
1357 // All functions return a clone. |
|
1358 ioMan->mCacheDirectory.swap(directory); |
|
1359 |
|
1360 if (ioMan->mCacheDirectory) { |
|
1361 CacheIndex::Init(ioMan->mCacheDirectory); |
|
1362 } |
|
1363 |
|
1364 return NS_OK; |
|
1365 } |
|
1366 |
|
1367 // static |
|
1368 already_AddRefed<nsIEventTarget> |
|
1369 CacheFileIOManager::IOTarget() |
|
1370 { |
|
1371 nsCOMPtr<nsIEventTarget> target; |
|
1372 if (gInstance && gInstance->mIOThread) { |
|
1373 target = gInstance->mIOThread->Target(); |
|
1374 } |
|
1375 |
|
1376 return target.forget(); |
|
1377 } |
|
1378 |
|
1379 // static |
|
1380 already_AddRefed<CacheIOThread> |
|
1381 CacheFileIOManager::IOThread() |
|
1382 { |
|
1383 nsRefPtr<CacheIOThread> thread; |
|
1384 if (gInstance) { |
|
1385 thread = gInstance->mIOThread; |
|
1386 } |
|
1387 |
|
1388 return thread.forget(); |
|
1389 } |
|
1390 |
|
1391 // static |
|
1392 bool |
|
1393 CacheFileIOManager::IsOnIOThread() |
|
1394 { |
|
1395 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1396 if (ioMan && ioMan->mIOThread) { |
|
1397 return ioMan->mIOThread->IsCurrentThread(); |
|
1398 } |
|
1399 |
|
1400 return false; |
|
1401 } |
|
1402 |
|
1403 // static |
|
1404 bool |
|
1405 CacheFileIOManager::IsOnIOThreadOrCeased() |
|
1406 { |
|
1407 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1408 if (ioMan && ioMan->mIOThread) { |
|
1409 return ioMan->mIOThread->IsCurrentThread(); |
|
1410 } |
|
1411 |
|
1412 // Ceased... |
|
1413 return true; |
|
1414 } |
|
1415 |
|
1416 // static |
|
1417 bool |
|
1418 CacheFileIOManager::IsShutdown() |
|
1419 { |
|
1420 if (!gInstance) { |
|
1421 return true; |
|
1422 } |
|
1423 return gInstance->mShuttingDown; |
|
1424 } |
|
1425 |
|
1426 // static |
|
1427 nsresult |
|
1428 CacheFileIOManager::ScheduleMetadataWrite(CacheFile * aFile) |
|
1429 { |
|
1430 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1431 NS_ENSURE_TRUE(ioMan, NS_ERROR_NOT_INITIALIZED); |
|
1432 |
|
1433 NS_ENSURE_TRUE(!ioMan->mShuttingDown, NS_ERROR_NOT_INITIALIZED); |
|
1434 |
|
1435 nsRefPtr<MetadataWriteScheduleEvent> event = new MetadataWriteScheduleEvent( |
|
1436 ioMan, aFile, MetadataWriteScheduleEvent::SCHEDULE); |
|
1437 nsCOMPtr<nsIEventTarget> target = ioMan->IOTarget(); |
|
1438 NS_ENSURE_TRUE(target, NS_ERROR_UNEXPECTED); |
|
1439 return target->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); |
|
1440 } |
|
1441 |
|
1442 nsresult |
|
1443 CacheFileIOManager::ScheduleMetadataWriteInternal(CacheFile * aFile) |
|
1444 { |
|
1445 MOZ_ASSERT(IsOnIOThreadOrCeased()); |
|
1446 |
|
1447 nsresult rv; |
|
1448 |
|
1449 if (!mMetadataWritesTimer) { |
|
1450 mMetadataWritesTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); |
|
1451 NS_ENSURE_SUCCESS(rv, rv); |
|
1452 |
|
1453 rv = mMetadataWritesTimer->InitWithCallback( |
|
1454 this, kMetadataWriteDelay, nsITimer::TYPE_ONE_SHOT); |
|
1455 NS_ENSURE_SUCCESS(rv, rv); |
|
1456 } |
|
1457 |
|
1458 if (mScheduledMetadataWrites.IndexOf(aFile) != |
|
1459 mScheduledMetadataWrites.NoIndex) { |
|
1460 return NS_OK; |
|
1461 } |
|
1462 |
|
1463 mScheduledMetadataWrites.AppendElement(aFile); |
|
1464 |
|
1465 return NS_OK; |
|
1466 } |
|
1467 |
|
1468 // static |
|
1469 nsresult |
|
1470 CacheFileIOManager::UnscheduleMetadataWrite(CacheFile * aFile) |
|
1471 { |
|
1472 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1473 NS_ENSURE_TRUE(ioMan, NS_ERROR_NOT_INITIALIZED); |
|
1474 |
|
1475 NS_ENSURE_TRUE(!ioMan->mShuttingDown, NS_ERROR_NOT_INITIALIZED); |
|
1476 |
|
1477 nsRefPtr<MetadataWriteScheduleEvent> event = new MetadataWriteScheduleEvent( |
|
1478 ioMan, aFile, MetadataWriteScheduleEvent::UNSCHEDULE); |
|
1479 nsCOMPtr<nsIEventTarget> target = ioMan->IOTarget(); |
|
1480 NS_ENSURE_TRUE(target, NS_ERROR_UNEXPECTED); |
|
1481 return target->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); |
|
1482 } |
|
1483 |
|
1484 nsresult |
|
1485 CacheFileIOManager::UnscheduleMetadataWriteInternal(CacheFile * aFile) |
|
1486 { |
|
1487 MOZ_ASSERT(IsOnIOThreadOrCeased()); |
|
1488 |
|
1489 mScheduledMetadataWrites.RemoveElement(aFile); |
|
1490 |
|
1491 if (mScheduledMetadataWrites.Length() == 0 && |
|
1492 mMetadataWritesTimer) { |
|
1493 mMetadataWritesTimer->Cancel(); |
|
1494 mMetadataWritesTimer = nullptr; |
|
1495 } |
|
1496 |
|
1497 return NS_OK; |
|
1498 } |
|
1499 |
|
1500 // static |
|
1501 nsresult |
|
1502 CacheFileIOManager::ShutdownMetadataWriteScheduling() |
|
1503 { |
|
1504 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1505 NS_ENSURE_TRUE(ioMan, NS_ERROR_NOT_INITIALIZED); |
|
1506 |
|
1507 nsRefPtr<MetadataWriteScheduleEvent> event = new MetadataWriteScheduleEvent( |
|
1508 ioMan, nullptr, MetadataWriteScheduleEvent::SHUTDOWN); |
|
1509 nsCOMPtr<nsIEventTarget> target = ioMan->IOTarget(); |
|
1510 NS_ENSURE_TRUE(target, NS_ERROR_UNEXPECTED); |
|
1511 return target->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); |
|
1512 } |
|
1513 |
|
1514 nsresult |
|
1515 CacheFileIOManager::ShutdownMetadataWriteSchedulingInternal() |
|
1516 { |
|
1517 MOZ_ASSERT(IsOnIOThreadOrCeased()); |
|
1518 |
|
1519 nsTArray<nsRefPtr<CacheFile> > files; |
|
1520 files.SwapElements(mScheduledMetadataWrites); |
|
1521 for (uint32_t i = 0; i < files.Length(); ++i) { |
|
1522 CacheFile * file = files[i]; |
|
1523 file->WriteMetadataIfNeeded(); |
|
1524 } |
|
1525 |
|
1526 if (mMetadataWritesTimer) { |
|
1527 mMetadataWritesTimer->Cancel(); |
|
1528 mMetadataWritesTimer = nullptr; |
|
1529 } |
|
1530 |
|
1531 return NS_OK; |
|
1532 } |
|
1533 |
|
1534 NS_IMETHODIMP |
|
1535 CacheFileIOManager::Notify(nsITimer * aTimer) |
|
1536 { |
|
1537 MOZ_ASSERT(IsOnIOThreadOrCeased()); |
|
1538 MOZ_ASSERT(mMetadataWritesTimer == aTimer); |
|
1539 |
|
1540 mMetadataWritesTimer = nullptr; |
|
1541 |
|
1542 nsTArray<nsRefPtr<CacheFile> > files; |
|
1543 files.SwapElements(mScheduledMetadataWrites); |
|
1544 for (uint32_t i = 0; i < files.Length(); ++i) { |
|
1545 CacheFile * file = files[i]; |
|
1546 file->WriteMetadataIfNeeded(); |
|
1547 } |
|
1548 |
|
1549 return NS_OK; |
|
1550 } |
|
1551 |
|
1552 // static |
|
1553 nsresult |
|
1554 CacheFileIOManager::OpenFile(const nsACString &aKey, |
|
1555 uint32_t aFlags, bool aResultOnAnyThread, |
|
1556 CacheFileIOListener *aCallback) |
|
1557 { |
|
1558 LOG(("CacheFileIOManager::OpenFile() [key=%s, flags=%d, listener=%p]", |
|
1559 PromiseFlatCString(aKey).get(), aFlags, aCallback)); |
|
1560 |
|
1561 nsresult rv; |
|
1562 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1563 |
|
1564 if (!ioMan) { |
|
1565 return NS_ERROR_NOT_INITIALIZED; |
|
1566 } |
|
1567 |
|
1568 bool priority = aFlags & CacheFileIOManager::PRIORITY; |
|
1569 nsRefPtr<OpenFileEvent> ev = new OpenFileEvent(aKey, aFlags, aResultOnAnyThread, aCallback); |
|
1570 rv = ioMan->mIOThread->Dispatch(ev, priority |
|
1571 ? CacheIOThread::OPEN_PRIORITY |
|
1572 : CacheIOThread::OPEN); |
|
1573 NS_ENSURE_SUCCESS(rv, rv); |
|
1574 |
|
1575 return NS_OK; |
|
1576 } |
|
1577 |
|
1578 nsresult |
|
1579 CacheFileIOManager::OpenFileInternal(const SHA1Sum::Hash *aHash, |
|
1580 const nsACString &aKey, |
|
1581 uint32_t aFlags, |
|
1582 CacheFileHandle **_retval) |
|
1583 { |
|
1584 LOG(("CacheFileIOManager::OpenFileInternal() [hash=%08x%08x%08x%08x%08x, " |
|
1585 "key=%s, flags=%d]", LOGSHA1(aHash), PromiseFlatCString(aKey).get(), |
|
1586 aFlags)); |
|
1587 |
|
1588 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
1589 |
|
1590 nsresult rv; |
|
1591 |
|
1592 if (mShuttingDown) { |
|
1593 return NS_ERROR_NOT_INITIALIZED; |
|
1594 } |
|
1595 |
|
1596 if (!mTreeCreated) { |
|
1597 rv = CreateCacheTree(); |
|
1598 if (NS_FAILED(rv)) return rv; |
|
1599 } |
|
1600 |
|
1601 nsCOMPtr<nsIFile> file; |
|
1602 rv = GetFile(aHash, getter_AddRefs(file)); |
|
1603 NS_ENSURE_SUCCESS(rv, rv); |
|
1604 |
|
1605 nsRefPtr<CacheFileHandle> handle; |
|
1606 mHandles.GetHandle(aHash, false, getter_AddRefs(handle)); |
|
1607 |
|
1608 if ((aFlags & (OPEN | CREATE | CREATE_NEW)) == CREATE_NEW) { |
|
1609 if (handle) { |
|
1610 rv = DoomFileInternal(handle); |
|
1611 NS_ENSURE_SUCCESS(rv, rv); |
|
1612 handle = nullptr; |
|
1613 } |
|
1614 |
|
1615 rv = mHandles.NewHandle(aHash, aFlags & PRIORITY, getter_AddRefs(handle)); |
|
1616 NS_ENSURE_SUCCESS(rv, rv); |
|
1617 |
|
1618 bool exists; |
|
1619 rv = file->Exists(&exists); |
|
1620 NS_ENSURE_SUCCESS(rv, rv); |
|
1621 |
|
1622 if (exists) { |
|
1623 CacheIndex::RemoveEntry(aHash); |
|
1624 |
|
1625 LOG(("CacheFileIOManager::OpenFileInternal() - Removing old file from " |
|
1626 "disk")); |
|
1627 rv = file->Remove(false); |
|
1628 if (NS_FAILED(rv)) { |
|
1629 NS_WARNING("Cannot remove old entry from the disk"); |
|
1630 LOG(("CacheFileIOManager::OpenFileInternal() - Removing old file failed" |
|
1631 ". [rv=0x%08x]", rv)); |
|
1632 } |
|
1633 } |
|
1634 |
|
1635 CacheIndex::AddEntry(aHash); |
|
1636 handle->mFile.swap(file); |
|
1637 handle->mFileSize = 0; |
|
1638 } |
|
1639 |
|
1640 if (handle) { |
|
1641 handle.swap(*_retval); |
|
1642 return NS_OK; |
|
1643 } |
|
1644 |
|
1645 bool exists; |
|
1646 rv = file->Exists(&exists); |
|
1647 NS_ENSURE_SUCCESS(rv, rv); |
|
1648 |
|
1649 if (exists && mContextEvictor) { |
|
1650 if (mContextEvictor->ContextsCount() == 0) { |
|
1651 mContextEvictor = nullptr; |
|
1652 } else { |
|
1653 bool wasEvicted = false; |
|
1654 mContextEvictor->WasEvicted(aKey, file, &wasEvicted); |
|
1655 if (wasEvicted) { |
|
1656 LOG(("CacheFileIOManager::OpenFileInternal() - Removing file since the " |
|
1657 "entry was evicted by EvictByContext()")); |
|
1658 exists = false; |
|
1659 file->Remove(false); |
|
1660 CacheIndex::RemoveEntry(aHash); |
|
1661 } |
|
1662 } |
|
1663 } |
|
1664 |
|
1665 if (!exists && (aFlags & (OPEN | CREATE | CREATE_NEW)) == OPEN) { |
|
1666 return NS_ERROR_NOT_AVAILABLE; |
|
1667 } |
|
1668 |
|
1669 rv = mHandles.NewHandle(aHash, aFlags & PRIORITY, getter_AddRefs(handle)); |
|
1670 NS_ENSURE_SUCCESS(rv, rv); |
|
1671 |
|
1672 if (exists) { |
|
1673 rv = file->GetFileSize(&handle->mFileSize); |
|
1674 NS_ENSURE_SUCCESS(rv, rv); |
|
1675 |
|
1676 handle->mFileExists = true; |
|
1677 |
|
1678 CacheIndex::EnsureEntryExists(aHash); |
|
1679 } else { |
|
1680 handle->mFileSize = 0; |
|
1681 |
|
1682 CacheIndex::AddEntry(aHash); |
|
1683 } |
|
1684 |
|
1685 handle->mFile.swap(file); |
|
1686 handle.swap(*_retval); |
|
1687 return NS_OK; |
|
1688 } |
|
1689 |
|
1690 nsresult |
|
1691 CacheFileIOManager::OpenSpecialFileInternal(const nsACString &aKey, |
|
1692 uint32_t aFlags, |
|
1693 CacheFileHandle **_retval) |
|
1694 { |
|
1695 LOG(("CacheFileIOManager::OpenSpecialFileInternal() [key=%s, flags=%d]", |
|
1696 PromiseFlatCString(aKey).get(), aFlags)); |
|
1697 |
|
1698 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
1699 |
|
1700 nsresult rv; |
|
1701 |
|
1702 if (mShuttingDown) { |
|
1703 return NS_ERROR_NOT_INITIALIZED; |
|
1704 } |
|
1705 |
|
1706 if (!mTreeCreated) { |
|
1707 rv = CreateCacheTree(); |
|
1708 if (NS_FAILED(rv)) return rv; |
|
1709 } |
|
1710 |
|
1711 nsCOMPtr<nsIFile> file; |
|
1712 rv = GetSpecialFile(aKey, getter_AddRefs(file)); |
|
1713 NS_ENSURE_SUCCESS(rv, rv); |
|
1714 |
|
1715 nsRefPtr<CacheFileHandle> handle; |
|
1716 for (uint32_t i = 0 ; i < mSpecialHandles.Length() ; i++) { |
|
1717 if (!mSpecialHandles[i]->IsDoomed() && mSpecialHandles[i]->Key() == aKey) { |
|
1718 handle = mSpecialHandles[i]; |
|
1719 break; |
|
1720 } |
|
1721 } |
|
1722 |
|
1723 if ((aFlags & (OPEN | CREATE | CREATE_NEW)) == CREATE_NEW) { |
|
1724 if (handle) { |
|
1725 rv = DoomFileInternal(handle); |
|
1726 NS_ENSURE_SUCCESS(rv, rv); |
|
1727 handle = nullptr; |
|
1728 } |
|
1729 |
|
1730 handle = new CacheFileHandle(aKey, aFlags & PRIORITY); |
|
1731 mSpecialHandles.AppendElement(handle); |
|
1732 |
|
1733 bool exists; |
|
1734 rv = file->Exists(&exists); |
|
1735 NS_ENSURE_SUCCESS(rv, rv); |
|
1736 |
|
1737 if (exists) { |
|
1738 LOG(("CacheFileIOManager::OpenSpecialFileInternal() - Removing file from " |
|
1739 "disk")); |
|
1740 rv = file->Remove(false); |
|
1741 if (NS_FAILED(rv)) { |
|
1742 NS_WARNING("Cannot remove old entry from the disk"); |
|
1743 LOG(("CacheFileIOManager::OpenSpecialFileInternal() - Removing file " |
|
1744 "failed. [rv=0x%08x]", rv)); |
|
1745 } |
|
1746 } |
|
1747 |
|
1748 handle->mFile.swap(file); |
|
1749 handle->mFileSize = 0; |
|
1750 } |
|
1751 |
|
1752 if (handle) { |
|
1753 handle.swap(*_retval); |
|
1754 return NS_OK; |
|
1755 } |
|
1756 |
|
1757 bool exists; |
|
1758 rv = file->Exists(&exists); |
|
1759 NS_ENSURE_SUCCESS(rv, rv); |
|
1760 |
|
1761 if (!exists && (aFlags & (OPEN | CREATE | CREATE_NEW)) == OPEN) { |
|
1762 return NS_ERROR_NOT_AVAILABLE; |
|
1763 } |
|
1764 |
|
1765 handle = new CacheFileHandle(aKey, aFlags & PRIORITY); |
|
1766 mSpecialHandles.AppendElement(handle); |
|
1767 |
|
1768 if (exists) { |
|
1769 rv = file->GetFileSize(&handle->mFileSize); |
|
1770 NS_ENSURE_SUCCESS(rv, rv); |
|
1771 |
|
1772 handle->mFileExists = true; |
|
1773 } else { |
|
1774 handle->mFileSize = 0; |
|
1775 } |
|
1776 |
|
1777 handle->mFile.swap(file); |
|
1778 handle.swap(*_retval); |
|
1779 return NS_OK; |
|
1780 } |
|
1781 |
|
1782 nsresult |
|
1783 CacheFileIOManager::CloseHandleInternal(CacheFileHandle *aHandle) |
|
1784 { |
|
1785 LOG(("CacheFileIOManager::CloseHandleInternal() [handle=%p]", aHandle)); |
|
1786 aHandle->Log(); |
|
1787 |
|
1788 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
1789 |
|
1790 // Close file handle |
|
1791 if (aHandle->mFD) { |
|
1792 ReleaseNSPRHandleInternal(aHandle); |
|
1793 } |
|
1794 |
|
1795 // Delete the file if the entry was doomed or invalid |
|
1796 if (aHandle->mIsDoomed || aHandle->mInvalid) { |
|
1797 LOG(("CacheFileIOManager::CloseHandleInternal() - Removing file from " |
|
1798 "disk")); |
|
1799 aHandle->mFile->Remove(false); |
|
1800 } |
|
1801 |
|
1802 if (!aHandle->IsSpecialFile() && !aHandle->mIsDoomed && |
|
1803 (aHandle->mInvalid || !aHandle->mFileExists)) { |
|
1804 CacheIndex::RemoveEntry(aHandle->Hash()); |
|
1805 } |
|
1806 |
|
1807 // Don't remove handles after shutdown |
|
1808 if (!mShuttingDown) { |
|
1809 if (aHandle->IsSpecialFile()) { |
|
1810 mSpecialHandles.RemoveElement(aHandle); |
|
1811 } else { |
|
1812 mHandles.RemoveHandle(aHandle); |
|
1813 } |
|
1814 } |
|
1815 |
|
1816 return NS_OK; |
|
1817 } |
|
1818 |
|
1819 // static |
|
1820 nsresult |
|
1821 CacheFileIOManager::Read(CacheFileHandle *aHandle, int64_t aOffset, |
|
1822 char *aBuf, int32_t aCount, bool aResultOnAnyThread, |
|
1823 CacheFileIOListener *aCallback) |
|
1824 { |
|
1825 LOG(("CacheFileIOManager::Read() [handle=%p, offset=%lld, count=%d, " |
|
1826 "listener=%p]", aHandle, aOffset, aCount, aCallback)); |
|
1827 |
|
1828 nsresult rv; |
|
1829 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1830 |
|
1831 if (aHandle->IsClosed() || !ioMan) { |
|
1832 return NS_ERROR_NOT_INITIALIZED; |
|
1833 } |
|
1834 |
|
1835 nsRefPtr<ReadEvent> ev = new ReadEvent(aHandle, aOffset, aBuf, aCount, |
|
1836 aResultOnAnyThread, aCallback); |
|
1837 rv = ioMan->mIOThread->Dispatch(ev, aHandle->IsPriority() |
|
1838 ? CacheIOThread::READ_PRIORITY |
|
1839 : CacheIOThread::READ); |
|
1840 NS_ENSURE_SUCCESS(rv, rv); |
|
1841 |
|
1842 return NS_OK; |
|
1843 } |
|
1844 |
|
1845 nsresult |
|
1846 CacheFileIOManager::ReadInternal(CacheFileHandle *aHandle, int64_t aOffset, |
|
1847 char *aBuf, int32_t aCount) |
|
1848 { |
|
1849 LOG(("CacheFileIOManager::ReadInternal() [handle=%p, offset=%lld, count=%d]", |
|
1850 aHandle, aOffset, aCount)); |
|
1851 |
|
1852 nsresult rv; |
|
1853 |
|
1854 if (!aHandle->mFileExists) { |
|
1855 NS_WARNING("Trying to read from non-existent file"); |
|
1856 return NS_ERROR_NOT_AVAILABLE; |
|
1857 } |
|
1858 |
|
1859 if (!aHandle->mFD) { |
|
1860 rv = OpenNSPRHandle(aHandle); |
|
1861 NS_ENSURE_SUCCESS(rv, rv); |
|
1862 } else { |
|
1863 NSPRHandleUsed(aHandle); |
|
1864 } |
|
1865 |
|
1866 // Check again, OpenNSPRHandle could figure out the file was gone. |
|
1867 if (!aHandle->mFileExists) { |
|
1868 NS_WARNING("Trying to read from non-existent file"); |
|
1869 return NS_ERROR_NOT_AVAILABLE; |
|
1870 } |
|
1871 |
|
1872 int64_t offset = PR_Seek64(aHandle->mFD, aOffset, PR_SEEK_SET); |
|
1873 if (offset == -1) { |
|
1874 return NS_ERROR_FAILURE; |
|
1875 } |
|
1876 |
|
1877 int32_t bytesRead = PR_Read(aHandle->mFD, aBuf, aCount); |
|
1878 if (bytesRead != aCount) { |
|
1879 return NS_ERROR_FAILURE; |
|
1880 } |
|
1881 |
|
1882 return NS_OK; |
|
1883 } |
|
1884 |
|
1885 // static |
|
1886 nsresult |
|
1887 CacheFileIOManager::Write(CacheFileHandle *aHandle, int64_t aOffset, |
|
1888 const char *aBuf, int32_t aCount, bool aValidate, |
|
1889 CacheFileIOListener *aCallback) |
|
1890 { |
|
1891 LOG(("CacheFileIOManager::Write() [handle=%p, offset=%lld, count=%d, " |
|
1892 "validate=%d, listener=%p]", aHandle, aOffset, aCount, aValidate, |
|
1893 aCallback)); |
|
1894 |
|
1895 nsresult rv; |
|
1896 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1897 |
|
1898 if (aHandle->IsClosed() || !ioMan) { |
|
1899 return NS_ERROR_NOT_INITIALIZED; |
|
1900 } |
|
1901 |
|
1902 nsRefPtr<WriteEvent> ev = new WriteEvent(aHandle, aOffset, aBuf, aCount, |
|
1903 aValidate, aCallback); |
|
1904 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); |
|
1905 NS_ENSURE_SUCCESS(rv, rv); |
|
1906 |
|
1907 return NS_OK; |
|
1908 } |
|
1909 |
|
1910 nsresult |
|
1911 CacheFileIOManager::WriteInternal(CacheFileHandle *aHandle, int64_t aOffset, |
|
1912 const char *aBuf, int32_t aCount, |
|
1913 bool aValidate) |
|
1914 { |
|
1915 LOG(("CacheFileIOManager::WriteInternal() [handle=%p, offset=%lld, count=%d, " |
|
1916 "validate=%d]", aHandle, aOffset, aCount, aValidate)); |
|
1917 |
|
1918 nsresult rv; |
|
1919 |
|
1920 if (!aHandle->mFileExists) { |
|
1921 rv = CreateFile(aHandle); |
|
1922 NS_ENSURE_SUCCESS(rv, rv); |
|
1923 } |
|
1924 |
|
1925 if (!aHandle->mFD) { |
|
1926 rv = OpenNSPRHandle(aHandle); |
|
1927 NS_ENSURE_SUCCESS(rv, rv); |
|
1928 } else { |
|
1929 NSPRHandleUsed(aHandle); |
|
1930 } |
|
1931 |
|
1932 // Check again, OpenNSPRHandle could figure out the file was gone. |
|
1933 if (!aHandle->mFileExists) { |
|
1934 return NS_ERROR_NOT_AVAILABLE; |
|
1935 } |
|
1936 |
|
1937 // Write invalidates the entry by default |
|
1938 aHandle->mInvalid = true; |
|
1939 |
|
1940 int64_t offset = PR_Seek64(aHandle->mFD, aOffset, PR_SEEK_SET); |
|
1941 if (offset == -1) { |
|
1942 return NS_ERROR_FAILURE; |
|
1943 } |
|
1944 |
|
1945 int32_t bytesWritten = PR_Write(aHandle->mFD, aBuf, aCount); |
|
1946 |
|
1947 if (bytesWritten != -1 && aHandle->mFileSize < aOffset+bytesWritten) { |
|
1948 aHandle->mFileSize = aOffset+bytesWritten; |
|
1949 |
|
1950 if (!aHandle->IsDoomed() && !aHandle->IsSpecialFile()) { |
|
1951 uint32_t size = aHandle->FileSizeInK(); |
|
1952 CacheIndex::UpdateEntry(aHandle->Hash(), nullptr, nullptr, &size); |
|
1953 EvictIfOverLimitInternal(); |
|
1954 } |
|
1955 } |
|
1956 |
|
1957 if (bytesWritten != aCount) { |
|
1958 return NS_ERROR_FAILURE; |
|
1959 } |
|
1960 |
|
1961 // Write was successful and this write validates the entry (i.e. metadata) |
|
1962 if (aValidate) { |
|
1963 aHandle->mInvalid = false; |
|
1964 } |
|
1965 |
|
1966 return NS_OK; |
|
1967 } |
|
1968 |
|
1969 // static |
|
1970 nsresult |
|
1971 CacheFileIOManager::DoomFile(CacheFileHandle *aHandle, |
|
1972 CacheFileIOListener *aCallback) |
|
1973 { |
|
1974 LOG(("CacheFileIOManager::DoomFile() [handle=%p, listener=%p]", |
|
1975 aHandle, aCallback)); |
|
1976 |
|
1977 nsresult rv; |
|
1978 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
1979 |
|
1980 if (aHandle->IsClosed() || !ioMan) { |
|
1981 return NS_ERROR_NOT_INITIALIZED; |
|
1982 } |
|
1983 |
|
1984 nsRefPtr<DoomFileEvent> ev = new DoomFileEvent(aHandle, aCallback); |
|
1985 rv = ioMan->mIOThread->Dispatch(ev, aHandle->IsPriority() |
|
1986 ? CacheIOThread::OPEN_PRIORITY |
|
1987 : CacheIOThread::OPEN); |
|
1988 NS_ENSURE_SUCCESS(rv, rv); |
|
1989 |
|
1990 return NS_OK; |
|
1991 } |
|
1992 |
|
1993 nsresult |
|
1994 CacheFileIOManager::DoomFileInternal(CacheFileHandle *aHandle) |
|
1995 { |
|
1996 LOG(("CacheFileIOManager::DoomFileInternal() [handle=%p]", aHandle)); |
|
1997 aHandle->Log(); |
|
1998 |
|
1999 nsresult rv; |
|
2000 |
|
2001 if (aHandle->IsDoomed()) { |
|
2002 return NS_OK; |
|
2003 } |
|
2004 |
|
2005 if (aHandle->mFileExists) { |
|
2006 // we need to move the current file to the doomed directory |
|
2007 if (aHandle->mFD) { |
|
2008 ReleaseNSPRHandleInternal(aHandle); |
|
2009 } |
|
2010 |
|
2011 // find unused filename |
|
2012 nsCOMPtr<nsIFile> file; |
|
2013 rv = GetDoomedFile(getter_AddRefs(file)); |
|
2014 NS_ENSURE_SUCCESS(rv, rv); |
|
2015 |
|
2016 nsCOMPtr<nsIFile> parentDir; |
|
2017 rv = file->GetParent(getter_AddRefs(parentDir)); |
|
2018 NS_ENSURE_SUCCESS(rv, rv); |
|
2019 |
|
2020 nsAutoCString leafName; |
|
2021 rv = file->GetNativeLeafName(leafName); |
|
2022 NS_ENSURE_SUCCESS(rv, rv); |
|
2023 |
|
2024 rv = aHandle->mFile->MoveToNative(parentDir, leafName); |
|
2025 if (NS_ERROR_FILE_NOT_FOUND == rv || NS_ERROR_FILE_TARGET_DOES_NOT_EXIST == rv) { |
|
2026 LOG((" file already removed under our hands")); |
|
2027 aHandle->mFileExists = false; |
|
2028 rv = NS_OK; |
|
2029 } else { |
|
2030 NS_ENSURE_SUCCESS(rv, rv); |
|
2031 aHandle->mFile.swap(file); |
|
2032 } |
|
2033 } |
|
2034 |
|
2035 if (!aHandle->IsSpecialFile()) { |
|
2036 CacheIndex::RemoveEntry(aHandle->Hash()); |
|
2037 } |
|
2038 |
|
2039 aHandle->mIsDoomed = true; |
|
2040 |
|
2041 if (!aHandle->IsSpecialFile()) { |
|
2042 nsRefPtr<CacheStorageService> storageService = CacheStorageService::Self(); |
|
2043 if (storageService) { |
|
2044 nsAutoCString idExtension, url; |
|
2045 nsCOMPtr<nsILoadContextInfo> info = |
|
2046 CacheFileUtils::ParseKey(aHandle->Key(), &idExtension, &url); |
|
2047 MOZ_ASSERT(info); |
|
2048 if (info) { |
|
2049 storageService->CacheFileDoomed(info, idExtension, url); |
|
2050 } |
|
2051 } |
|
2052 } |
|
2053 |
|
2054 return NS_OK; |
|
2055 } |
|
2056 |
|
2057 // static |
|
2058 nsresult |
|
2059 CacheFileIOManager::DoomFileByKey(const nsACString &aKey, |
|
2060 CacheFileIOListener *aCallback) |
|
2061 { |
|
2062 LOG(("CacheFileIOManager::DoomFileByKey() [key=%s, listener=%p]", |
|
2063 PromiseFlatCString(aKey).get(), aCallback)); |
|
2064 |
|
2065 nsresult rv; |
|
2066 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2067 |
|
2068 if (!ioMan) { |
|
2069 return NS_ERROR_NOT_INITIALIZED; |
|
2070 } |
|
2071 |
|
2072 nsRefPtr<DoomFileByKeyEvent> ev = new DoomFileByKeyEvent(aKey, aCallback); |
|
2073 rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); |
|
2074 NS_ENSURE_SUCCESS(rv, rv); |
|
2075 |
|
2076 return NS_OK; |
|
2077 } |
|
2078 |
|
2079 nsresult |
|
2080 CacheFileIOManager::DoomFileByKeyInternal(const SHA1Sum::Hash *aHash) |
|
2081 { |
|
2082 LOG(("CacheFileIOManager::DoomFileByKeyInternal() [hash=%08x%08x%08x%08x%08x]" |
|
2083 , LOGSHA1(aHash))); |
|
2084 |
|
2085 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
2086 |
|
2087 nsresult rv; |
|
2088 |
|
2089 if (mShuttingDown) { |
|
2090 return NS_ERROR_NOT_INITIALIZED; |
|
2091 } |
|
2092 |
|
2093 if (!mCacheDirectory) { |
|
2094 return NS_ERROR_FILE_INVALID_PATH; |
|
2095 } |
|
2096 |
|
2097 // Find active handle |
|
2098 nsRefPtr<CacheFileHandle> handle; |
|
2099 mHandles.GetHandle(aHash, true, getter_AddRefs(handle)); |
|
2100 |
|
2101 if (handle) { |
|
2102 handle->Log(); |
|
2103 |
|
2104 if (handle->IsDoomed()) { |
|
2105 return NS_OK; |
|
2106 } |
|
2107 |
|
2108 return DoomFileInternal(handle); |
|
2109 } |
|
2110 |
|
2111 // There is no handle for this file, delete the file if exists |
|
2112 nsCOMPtr<nsIFile> file; |
|
2113 rv = GetFile(aHash, getter_AddRefs(file)); |
|
2114 NS_ENSURE_SUCCESS(rv, rv); |
|
2115 |
|
2116 bool exists; |
|
2117 rv = file->Exists(&exists); |
|
2118 NS_ENSURE_SUCCESS(rv, rv); |
|
2119 |
|
2120 if (!exists) { |
|
2121 return NS_ERROR_NOT_AVAILABLE; |
|
2122 } |
|
2123 |
|
2124 LOG(("CacheFileIOManager::DoomFileByKeyInternal() - Removing file from " |
|
2125 "disk")); |
|
2126 rv = file->Remove(false); |
|
2127 if (NS_FAILED(rv)) { |
|
2128 NS_WARNING("Cannot remove old entry from the disk"); |
|
2129 LOG(("CacheFileIOManager::DoomFileByKeyInternal() - Removing file failed. " |
|
2130 "[rv=0x%08x]", rv)); |
|
2131 } |
|
2132 |
|
2133 CacheIndex::RemoveEntry(aHash); |
|
2134 |
|
2135 return NS_OK; |
|
2136 } |
|
2137 |
|
2138 // static |
|
2139 nsresult |
|
2140 CacheFileIOManager::ReleaseNSPRHandle(CacheFileHandle *aHandle) |
|
2141 { |
|
2142 LOG(("CacheFileIOManager::ReleaseNSPRHandle() [handle=%p]", aHandle)); |
|
2143 |
|
2144 nsresult rv; |
|
2145 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2146 |
|
2147 if (aHandle->IsClosed() || !ioMan) { |
|
2148 return NS_ERROR_NOT_INITIALIZED; |
|
2149 } |
|
2150 |
|
2151 nsRefPtr<ReleaseNSPRHandleEvent> ev = new ReleaseNSPRHandleEvent(aHandle); |
|
2152 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::CLOSE); |
|
2153 NS_ENSURE_SUCCESS(rv, rv); |
|
2154 |
|
2155 return NS_OK; |
|
2156 } |
|
2157 |
|
2158 nsresult |
|
2159 CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle) |
|
2160 { |
|
2161 LOG(("CacheFileIOManager::ReleaseNSPRHandleInternal() [handle=%p]", aHandle)); |
|
2162 |
|
2163 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
2164 MOZ_ASSERT(aHandle->mFD); |
|
2165 |
|
2166 DebugOnly<bool> found; |
|
2167 found = mHandlesByLastUsed.RemoveElement(aHandle); |
|
2168 MOZ_ASSERT(found); |
|
2169 |
|
2170 PR_Close(aHandle->mFD); |
|
2171 aHandle->mFD = nullptr; |
|
2172 |
|
2173 return NS_OK; |
|
2174 } |
|
2175 |
|
2176 // static |
|
2177 nsresult |
|
2178 CacheFileIOManager::TruncateSeekSetEOF(CacheFileHandle *aHandle, |
|
2179 int64_t aTruncatePos, int64_t aEOFPos, |
|
2180 CacheFileIOListener *aCallback) |
|
2181 { |
|
2182 LOG(("CacheFileIOManager::TruncateSeekSetEOF() [handle=%p, truncatePos=%lld, " |
|
2183 "EOFPos=%lld, listener=%p]", aHandle, aTruncatePos, aEOFPos, aCallback)); |
|
2184 |
|
2185 nsresult rv; |
|
2186 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2187 |
|
2188 if (aHandle->IsClosed() || !ioMan) { |
|
2189 return NS_ERROR_NOT_INITIALIZED; |
|
2190 } |
|
2191 |
|
2192 nsRefPtr<TruncateSeekSetEOFEvent> ev = new TruncateSeekSetEOFEvent( |
|
2193 aHandle, aTruncatePos, aEOFPos, |
|
2194 aCallback); |
|
2195 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); |
|
2196 NS_ENSURE_SUCCESS(rv, rv); |
|
2197 |
|
2198 return NS_OK; |
|
2199 } |
|
2200 |
|
2201 // static |
|
2202 void CacheFileIOManager::GetCacheDirectory(nsIFile** result) |
|
2203 { |
|
2204 *result = nullptr; |
|
2205 |
|
2206 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2207 if (!ioMan) { |
|
2208 return; |
|
2209 } |
|
2210 |
|
2211 nsCOMPtr<nsIFile> file = ioMan->mCacheDirectory; |
|
2212 file.forget(result); |
|
2213 } |
|
2214 |
|
2215 static nsresult |
|
2216 TruncFile(PRFileDesc *aFD, uint32_t aEOF) |
|
2217 { |
|
2218 #if defined(XP_UNIX) |
|
2219 if (ftruncate(PR_FileDesc2NativeHandle(aFD), aEOF) != 0) { |
|
2220 NS_ERROR("ftruncate failed"); |
|
2221 return NS_ERROR_FAILURE; |
|
2222 } |
|
2223 #elif defined(XP_WIN) |
|
2224 int32_t cnt = PR_Seek(aFD, aEOF, PR_SEEK_SET); |
|
2225 if (cnt == -1) { |
|
2226 return NS_ERROR_FAILURE; |
|
2227 } |
|
2228 if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(aFD))) { |
|
2229 NS_ERROR("SetEndOfFile failed"); |
|
2230 return NS_ERROR_FAILURE; |
|
2231 } |
|
2232 #else |
|
2233 MOZ_ASSERT(false, "Not implemented!"); |
|
2234 #endif |
|
2235 |
|
2236 return NS_OK; |
|
2237 } |
|
2238 |
|
2239 nsresult |
|
2240 CacheFileIOManager::TruncateSeekSetEOFInternal(CacheFileHandle *aHandle, |
|
2241 int64_t aTruncatePos, |
|
2242 int64_t aEOFPos) |
|
2243 { |
|
2244 LOG(("CacheFileIOManager::TruncateSeekSetEOFInternal() [handle=%p, " |
|
2245 "truncatePos=%lld, EOFPos=%lld]", aHandle, aTruncatePos, aEOFPos)); |
|
2246 |
|
2247 nsresult rv; |
|
2248 |
|
2249 if (!aHandle->mFileExists) { |
|
2250 rv = CreateFile(aHandle); |
|
2251 NS_ENSURE_SUCCESS(rv, rv); |
|
2252 } |
|
2253 |
|
2254 if (!aHandle->mFD) { |
|
2255 rv = OpenNSPRHandle(aHandle); |
|
2256 NS_ENSURE_SUCCESS(rv, rv); |
|
2257 } else { |
|
2258 NSPRHandleUsed(aHandle); |
|
2259 } |
|
2260 |
|
2261 // Check again, OpenNSPRHandle could figure out the file was gone. |
|
2262 if (!aHandle->mFileExists) { |
|
2263 return NS_ERROR_NOT_AVAILABLE; |
|
2264 } |
|
2265 |
|
2266 // This operation always invalidates the entry |
|
2267 aHandle->mInvalid = true; |
|
2268 |
|
2269 rv = TruncFile(aHandle->mFD, static_cast<uint32_t>(aTruncatePos)); |
|
2270 NS_ENSURE_SUCCESS(rv, rv); |
|
2271 |
|
2272 rv = TruncFile(aHandle->mFD, static_cast<uint32_t>(aEOFPos)); |
|
2273 NS_ENSURE_SUCCESS(rv, rv); |
|
2274 |
|
2275 return NS_OK; |
|
2276 } |
|
2277 |
|
2278 // static |
|
2279 nsresult |
|
2280 CacheFileIOManager::RenameFile(CacheFileHandle *aHandle, |
|
2281 const nsACString &aNewName, |
|
2282 CacheFileIOListener *aCallback) |
|
2283 { |
|
2284 LOG(("CacheFileIOManager::RenameFile() [handle=%p, newName=%s, listener=%p]", |
|
2285 aHandle, PromiseFlatCString(aNewName).get(), aCallback)); |
|
2286 |
|
2287 nsresult rv; |
|
2288 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2289 |
|
2290 if (aHandle->IsClosed() || !ioMan) { |
|
2291 return NS_ERROR_NOT_INITIALIZED; |
|
2292 } |
|
2293 |
|
2294 if (!aHandle->IsSpecialFile()) { |
|
2295 return NS_ERROR_UNEXPECTED; |
|
2296 } |
|
2297 |
|
2298 nsRefPtr<RenameFileEvent> ev = new RenameFileEvent(aHandle, aNewName, |
|
2299 aCallback); |
|
2300 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); |
|
2301 NS_ENSURE_SUCCESS(rv, rv); |
|
2302 |
|
2303 return NS_OK; |
|
2304 } |
|
2305 |
|
2306 nsresult |
|
2307 CacheFileIOManager::RenameFileInternal(CacheFileHandle *aHandle, |
|
2308 const nsACString &aNewName) |
|
2309 { |
|
2310 LOG(("CacheFileIOManager::RenameFileInternal() [handle=%p, newName=%s]", |
|
2311 aHandle, PromiseFlatCString(aNewName).get())); |
|
2312 |
|
2313 nsresult rv; |
|
2314 |
|
2315 MOZ_ASSERT(aHandle->IsSpecialFile()); |
|
2316 |
|
2317 if (aHandle->IsDoomed()) { |
|
2318 return NS_ERROR_NOT_AVAILABLE; |
|
2319 } |
|
2320 |
|
2321 // Doom old handle if it exists and is not doomed |
|
2322 for (uint32_t i = 0 ; i < mSpecialHandles.Length() ; i++) { |
|
2323 if (!mSpecialHandles[i]->IsDoomed() && |
|
2324 mSpecialHandles[i]->Key() == aNewName) { |
|
2325 MOZ_ASSERT(aHandle != mSpecialHandles[i]); |
|
2326 rv = DoomFileInternal(mSpecialHandles[i]); |
|
2327 NS_ENSURE_SUCCESS(rv, rv); |
|
2328 break; |
|
2329 } |
|
2330 } |
|
2331 |
|
2332 nsCOMPtr<nsIFile> file; |
|
2333 rv = GetSpecialFile(aNewName, getter_AddRefs(file)); |
|
2334 NS_ENSURE_SUCCESS(rv, rv); |
|
2335 |
|
2336 bool exists; |
|
2337 rv = file->Exists(&exists); |
|
2338 NS_ENSURE_SUCCESS(rv, rv); |
|
2339 |
|
2340 if (exists) { |
|
2341 LOG(("CacheFileIOManager::RenameFileInternal() - Removing old file from " |
|
2342 "disk")); |
|
2343 rv = file->Remove(false); |
|
2344 if (NS_FAILED(rv)) { |
|
2345 NS_WARNING("Cannot remove file from the disk"); |
|
2346 LOG(("CacheFileIOManager::RenameFileInternal() - Removing old file failed" |
|
2347 ". [rv=0x%08x]", rv)); |
|
2348 } |
|
2349 } |
|
2350 |
|
2351 if (!aHandle->FileExists()) { |
|
2352 aHandle->mKey = aNewName; |
|
2353 return NS_OK; |
|
2354 } |
|
2355 |
|
2356 if (aHandle->mFD) { |
|
2357 ReleaseNSPRHandleInternal(aHandle); |
|
2358 } |
|
2359 |
|
2360 rv = aHandle->mFile->MoveToNative(nullptr, aNewName); |
|
2361 NS_ENSURE_SUCCESS(rv, rv); |
|
2362 |
|
2363 aHandle->mKey = aNewName; |
|
2364 return NS_OK; |
|
2365 } |
|
2366 |
|
2367 // static |
|
2368 nsresult |
|
2369 CacheFileIOManager::EvictIfOverLimit() |
|
2370 { |
|
2371 LOG(("CacheFileIOManager::EvictIfOverLimit()")); |
|
2372 |
|
2373 nsresult rv; |
|
2374 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2375 |
|
2376 if (!ioMan) { |
|
2377 return NS_ERROR_NOT_INITIALIZED; |
|
2378 } |
|
2379 |
|
2380 nsCOMPtr<nsIRunnable> ev; |
|
2381 ev = NS_NewRunnableMethod(ioMan, |
|
2382 &CacheFileIOManager::EvictIfOverLimitInternal); |
|
2383 |
|
2384 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::EVICT); |
|
2385 NS_ENSURE_SUCCESS(rv, rv); |
|
2386 |
|
2387 return NS_OK; |
|
2388 } |
|
2389 |
|
2390 nsresult |
|
2391 CacheFileIOManager::EvictIfOverLimitInternal() |
|
2392 { |
|
2393 LOG(("CacheFileIOManager::EvictIfOverLimitInternal()")); |
|
2394 |
|
2395 nsresult rv; |
|
2396 |
|
2397 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2398 |
|
2399 if (mShuttingDown) { |
|
2400 return NS_ERROR_NOT_INITIALIZED; |
|
2401 } |
|
2402 |
|
2403 if (mOverLimitEvicting) { |
|
2404 LOG(("CacheFileIOManager::EvictIfOverLimitInternal() - Eviction already " |
|
2405 "running.")); |
|
2406 return NS_OK; |
|
2407 } |
|
2408 |
|
2409 UpdateSmartCacheSize(); |
|
2410 |
|
2411 uint32_t cacheUsage; |
|
2412 rv = CacheIndex::GetCacheSize(&cacheUsage); |
|
2413 NS_ENSURE_SUCCESS(rv, rv); |
|
2414 |
|
2415 uint32_t cacheLimit = CacheObserver::DiskCacheCapacity() >> 10; |
|
2416 if (cacheUsage <= cacheLimit) { |
|
2417 LOG(("CacheFileIOManager::EvictIfOverLimitInternal() - Cache size under " |
|
2418 "limit. [cacheSize=%u, limit=%u]", cacheUsage, cacheLimit)); |
|
2419 return NS_OK; |
|
2420 } |
|
2421 |
|
2422 LOG(("CacheFileIOManager::EvictIfOverLimitInternal() - Cache size exceeded " |
|
2423 "limit. Starting overlimit eviction. [cacheSize=%u, limit=%u]", |
|
2424 cacheUsage, cacheLimit)); |
|
2425 |
|
2426 nsCOMPtr<nsIRunnable> ev; |
|
2427 ev = NS_NewRunnableMethod(this, |
|
2428 &CacheFileIOManager::OverLimitEvictionInternal); |
|
2429 |
|
2430 rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); |
|
2431 NS_ENSURE_SUCCESS(rv, rv); |
|
2432 |
|
2433 mOverLimitEvicting = true; |
|
2434 return NS_OK; |
|
2435 } |
|
2436 |
|
2437 nsresult |
|
2438 CacheFileIOManager::OverLimitEvictionInternal() |
|
2439 { |
|
2440 LOG(("CacheFileIOManager::OverLimitEvictionInternal()")); |
|
2441 |
|
2442 nsresult rv; |
|
2443 |
|
2444 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2445 |
|
2446 // mOverLimitEvicting is accessed only on IO thread, so we can set it to false |
|
2447 // here and set it to true again once we dispatch another event that will |
|
2448 // continue with the eviction. The reason why we do so is that we can fail |
|
2449 // early anywhere in this method and the variable will contain a correct |
|
2450 // value. Otherwise we would need to set it to false on every failing place. |
|
2451 mOverLimitEvicting = false; |
|
2452 |
|
2453 if (mShuttingDown) { |
|
2454 return NS_ERROR_NOT_INITIALIZED; |
|
2455 } |
|
2456 |
|
2457 UpdateSmartCacheSize(); |
|
2458 |
|
2459 while (true) { |
|
2460 uint32_t cacheUsage; |
|
2461 rv = CacheIndex::GetCacheSize(&cacheUsage); |
|
2462 NS_ENSURE_SUCCESS(rv, rv); |
|
2463 |
|
2464 uint32_t cacheLimit = CacheObserver::DiskCacheCapacity() >> 10; |
|
2465 if (cacheUsage <= cacheLimit) { |
|
2466 LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Cache size under " |
|
2467 "limit. [cacheSize=%u, limit=%u]", cacheUsage, cacheLimit)); |
|
2468 return NS_OK; |
|
2469 } |
|
2470 |
|
2471 LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Cache size over " |
|
2472 "limit. [cacheSize=%u, limit=%u]", cacheUsage, cacheLimit)); |
|
2473 |
|
2474 if (CacheIOThread::YieldAndRerun()) { |
|
2475 LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Breaking loop " |
|
2476 "for higher level events.")); |
|
2477 mOverLimitEvicting = true; |
|
2478 return NS_OK; |
|
2479 } |
|
2480 |
|
2481 SHA1Sum::Hash hash; |
|
2482 uint32_t cnt; |
|
2483 static uint32_t consecutiveFailures = 0; |
|
2484 rv = CacheIndex::GetEntryForEviction(&hash, &cnt); |
|
2485 NS_ENSURE_SUCCESS(rv, rv); |
|
2486 |
|
2487 rv = DoomFileByKeyInternal(&hash); |
|
2488 if (NS_SUCCEEDED(rv)) { |
|
2489 consecutiveFailures = 0; |
|
2490 } else if (rv == NS_ERROR_NOT_AVAILABLE) { |
|
2491 LOG(("CacheFileIOManager::OverLimitEvictionInternal() - " |
|
2492 "DoomFileByKeyInternal() failed. [rv=0x%08x]", rv)); |
|
2493 // TODO index is outdated, start update |
|
2494 |
|
2495 // Make sure index won't return the same entry again |
|
2496 CacheIndex::RemoveEntry(&hash); |
|
2497 consecutiveFailures = 0; |
|
2498 } else { |
|
2499 // This shouldn't normally happen, but the eviction must not fail |
|
2500 // completely if we ever encounter this problem. |
|
2501 NS_WARNING("CacheFileIOManager::OverLimitEvictionInternal() - Unexpected " |
|
2502 "failure of DoomFileByKeyInternal()"); |
|
2503 |
|
2504 LOG(("CacheFileIOManager::OverLimitEvictionInternal() - " |
|
2505 "DoomFileByKeyInternal() failed. [rv=0x%08x]", rv)); |
|
2506 |
|
2507 // Normally, CacheIndex::UpdateEntry() is called only to update newly |
|
2508 // created/opened entries which are always fresh and UpdateEntry() expects |
|
2509 // and checks this flag. The way we use UpdateEntry() here is a kind of |
|
2510 // hack and we must make sure the flag is set by calling |
|
2511 // EnsureEntryExists(). |
|
2512 rv = CacheIndex::EnsureEntryExists(&hash); |
|
2513 NS_ENSURE_SUCCESS(rv, rv); |
|
2514 |
|
2515 // Move the entry at the end of both lists to make sure we won't end up |
|
2516 // failing on one entry forever. |
|
2517 uint32_t frecency = 0; |
|
2518 uint32_t expTime = nsICacheEntry::NO_EXPIRATION_TIME; |
|
2519 rv = CacheIndex::UpdateEntry(&hash, &frecency, &expTime, nullptr); |
|
2520 NS_ENSURE_SUCCESS(rv, rv); |
|
2521 |
|
2522 consecutiveFailures++; |
|
2523 if (consecutiveFailures >= cnt) { |
|
2524 // This doesn't necessarily mean that we've tried to doom every entry |
|
2525 // but we've reached a sane number of tries. It is likely that another |
|
2526 // eviction will start soon. And as said earlier, this normally doesn't |
|
2527 // happen at all. |
|
2528 return NS_OK; |
|
2529 } |
|
2530 } |
|
2531 } |
|
2532 |
|
2533 NS_NOTREACHED("We should never get here"); |
|
2534 return NS_OK; |
|
2535 } |
|
2536 |
|
2537 // static |
|
2538 nsresult |
|
2539 CacheFileIOManager::EvictAll() |
|
2540 { |
|
2541 LOG(("CacheFileIOManager::EvictAll()")); |
|
2542 |
|
2543 nsresult rv; |
|
2544 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2545 |
|
2546 if (!ioMan) { |
|
2547 return NS_ERROR_NOT_INITIALIZED; |
|
2548 } |
|
2549 |
|
2550 nsCOMPtr<nsIRunnable> ev; |
|
2551 ev = NS_NewRunnableMethod(ioMan, &CacheFileIOManager::EvictAllInternal); |
|
2552 |
|
2553 rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); |
|
2554 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2555 return rv; |
|
2556 } |
|
2557 |
|
2558 return NS_OK; |
|
2559 } |
|
2560 |
|
2561 namespace { |
|
2562 |
|
2563 class EvictionNotifierRunnable : public nsRunnable |
|
2564 { |
|
2565 public: |
|
2566 NS_DECL_NSIRUNNABLE |
|
2567 }; |
|
2568 |
|
2569 NS_IMETHODIMP |
|
2570 EvictionNotifierRunnable::Run() |
|
2571 { |
|
2572 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService(); |
|
2573 if (obsSvc) { |
|
2574 obsSvc->NotifyObservers(nullptr, "cacheservice:empty-cache", nullptr); |
|
2575 } |
|
2576 return NS_OK; |
|
2577 } |
|
2578 |
|
2579 } // anonymous namespace |
|
2580 |
|
2581 nsresult |
|
2582 CacheFileIOManager::EvictAllInternal() |
|
2583 { |
|
2584 LOG(("CacheFileIOManager::EvictAllInternal()")); |
|
2585 |
|
2586 nsresult rv; |
|
2587 |
|
2588 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2589 |
|
2590 nsRefPtr<EvictionNotifierRunnable> r = new EvictionNotifierRunnable(); |
|
2591 |
|
2592 if (!mCacheDirectory) { |
|
2593 // This is a kind of hack. Somebody called EvictAll() without a profile. |
|
2594 // This happens in xpcshell tests that use cache without profile. We need |
|
2595 // to notify observers in this case since the tests are waiting for it. |
|
2596 NS_DispatchToMainThread(r); |
|
2597 return NS_ERROR_FILE_INVALID_PATH; |
|
2598 } |
|
2599 |
|
2600 if (mShuttingDown) { |
|
2601 return NS_ERROR_NOT_INITIALIZED; |
|
2602 } |
|
2603 |
|
2604 if (!mTreeCreated) { |
|
2605 rv = CreateCacheTree(); |
|
2606 if (NS_FAILED(rv)) { |
|
2607 return rv; |
|
2608 } |
|
2609 } |
|
2610 |
|
2611 // Doom all active handles |
|
2612 nsTArray<nsRefPtr<CacheFileHandle> > handles; |
|
2613 mHandles.GetActiveHandles(&handles); |
|
2614 |
|
2615 for (uint32_t i = 0; i < handles.Length(); ++i) { |
|
2616 rv = DoomFileInternal(handles[i]); |
|
2617 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2618 LOG(("CacheFileIOManager::EvictAllInternal() - Cannot doom handle " |
|
2619 "[handle=%p]", handles[i].get())); |
|
2620 } |
|
2621 } |
|
2622 |
|
2623 nsCOMPtr<nsIFile> file; |
|
2624 rv = mCacheDirectory->Clone(getter_AddRefs(file)); |
|
2625 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2626 return rv; |
|
2627 } |
|
2628 |
|
2629 rv = file->AppendNative(NS_LITERAL_CSTRING(kEntriesDir)); |
|
2630 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2631 return rv; |
|
2632 } |
|
2633 |
|
2634 // Trash current entries directory |
|
2635 rv = TrashDirectory(file); |
|
2636 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2637 return rv; |
|
2638 } |
|
2639 |
|
2640 // Files are now inaccessible in entries directory, notify observers. |
|
2641 NS_DispatchToMainThread(r); |
|
2642 |
|
2643 // Create a new empty entries directory |
|
2644 rv = CheckAndCreateDir(mCacheDirectory, kEntriesDir, false); |
|
2645 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2646 return rv; |
|
2647 } |
|
2648 |
|
2649 CacheIndex::RemoveAll(); |
|
2650 |
|
2651 return NS_OK; |
|
2652 } |
|
2653 |
|
2654 // static |
|
2655 nsresult |
|
2656 CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo) |
|
2657 { |
|
2658 LOG(("CacheFileIOManager::EvictByContext() [loadContextInfo=%p]", |
|
2659 aLoadContextInfo)); |
|
2660 |
|
2661 nsresult rv; |
|
2662 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2663 |
|
2664 if (!ioMan) { |
|
2665 return NS_ERROR_NOT_INITIALIZED; |
|
2666 } |
|
2667 |
|
2668 nsCOMPtr<nsIRunnable> ev; |
|
2669 ev = NS_NewRunnableMethodWithArg<nsCOMPtr<nsILoadContextInfo> > |
|
2670 (ioMan, &CacheFileIOManager::EvictByContextInternal, aLoadContextInfo); |
|
2671 |
|
2672 rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); |
|
2673 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2674 return rv; |
|
2675 } |
|
2676 |
|
2677 return NS_OK; |
|
2678 } |
|
2679 |
|
2680 nsresult |
|
2681 CacheFileIOManager::EvictByContextInternal(nsILoadContextInfo *aLoadContextInfo) |
|
2682 { |
|
2683 LOG(("CacheFileIOManager::EvictByContextInternal() [loadContextInfo=%p, " |
|
2684 "anonymous=%u, inBrowser=%u, appId=%u]", aLoadContextInfo, |
|
2685 aLoadContextInfo->IsAnonymous(), aLoadContextInfo->IsInBrowserElement(), |
|
2686 aLoadContextInfo->AppId())); |
|
2687 |
|
2688 nsresult rv; |
|
2689 |
|
2690 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2691 |
|
2692 MOZ_ASSERT(!aLoadContextInfo->IsPrivate()); |
|
2693 if (aLoadContextInfo->IsPrivate()) { |
|
2694 return NS_ERROR_INVALID_ARG; |
|
2695 } |
|
2696 |
|
2697 if (!mCacheDirectory) { |
|
2698 return NS_ERROR_FILE_INVALID_PATH; |
|
2699 } |
|
2700 |
|
2701 if (mShuttingDown) { |
|
2702 return NS_ERROR_NOT_INITIALIZED; |
|
2703 } |
|
2704 |
|
2705 if (!mTreeCreated) { |
|
2706 rv = CreateCacheTree(); |
|
2707 if (NS_FAILED(rv)) { |
|
2708 return rv; |
|
2709 } |
|
2710 } |
|
2711 |
|
2712 // Doom all active handles that matches the load context |
|
2713 nsTArray<nsRefPtr<CacheFileHandle> > handles; |
|
2714 mHandles.GetActiveHandles(&handles); |
|
2715 |
|
2716 for (uint32_t i = 0; i < handles.Length(); ++i) { |
|
2717 bool equals; |
|
2718 rv = CacheFileUtils::KeyMatchesLoadContextInfo(handles[i]->Key(), |
|
2719 aLoadContextInfo, |
|
2720 &equals); |
|
2721 if (NS_FAILED(rv)) { |
|
2722 LOG(("CacheFileIOManager::EvictByContextInternal() - Cannot parse key in " |
|
2723 "handle! [handle=%p, key=%s]", handles[i].get(), |
|
2724 handles[i]->Key().get())); |
|
2725 MOZ_CRASH("Unexpected error!"); |
|
2726 } |
|
2727 |
|
2728 if (equals) { |
|
2729 rv = DoomFileInternal(handles[i]); |
|
2730 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2731 LOG(("CacheFileIOManager::EvictByContextInternal() - Cannot doom handle" |
|
2732 " [handle=%p]", handles[i].get())); |
|
2733 } |
|
2734 } |
|
2735 } |
|
2736 |
|
2737 if (!mContextEvictor) { |
|
2738 mContextEvictor = new CacheFileContextEvictor(); |
|
2739 mContextEvictor->Init(mCacheDirectory); |
|
2740 } |
|
2741 |
|
2742 mContextEvictor->AddContext(aLoadContextInfo); |
|
2743 |
|
2744 return NS_OK; |
|
2745 } |
|
2746 |
|
2747 // static |
|
2748 nsresult |
|
2749 CacheFileIOManager::CacheIndexStateChanged() |
|
2750 { |
|
2751 LOG(("CacheFileIOManager::CacheIndexStateChanged()")); |
|
2752 |
|
2753 nsresult rv; |
|
2754 |
|
2755 // CacheFileIOManager lives longer than CacheIndex so gInstance must be |
|
2756 // non-null here. |
|
2757 MOZ_ASSERT(gInstance); |
|
2758 |
|
2759 // We have to re-distatch even if we are on IO thread to prevent reentering |
|
2760 // the lock in CacheIndex |
|
2761 nsCOMPtr<nsIRunnable> ev; |
|
2762 ev = NS_NewRunnableMethod( |
|
2763 gInstance, &CacheFileIOManager::CacheIndexStateChangedInternal); |
|
2764 |
|
2765 nsCOMPtr<nsIEventTarget> ioTarget = IOTarget(); |
|
2766 MOZ_ASSERT(ioTarget); |
|
2767 |
|
2768 rv = ioTarget->Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL); |
|
2769 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
2770 return rv; |
|
2771 } |
|
2772 |
|
2773 return NS_OK; |
|
2774 } |
|
2775 |
|
2776 nsresult |
|
2777 CacheFileIOManager::CacheIndexStateChangedInternal() |
|
2778 { |
|
2779 if (mShuttingDown) { |
|
2780 // ignore notification during shutdown |
|
2781 return NS_OK; |
|
2782 } |
|
2783 |
|
2784 if (!mContextEvictor) { |
|
2785 return NS_OK; |
|
2786 } |
|
2787 |
|
2788 mContextEvictor->CacheIndexStateChanged(); |
|
2789 return NS_OK; |
|
2790 } |
|
2791 |
|
2792 nsresult |
|
2793 CacheFileIOManager::TrashDirectory(nsIFile *aFile) |
|
2794 { |
|
2795 #ifdef PR_LOGGING |
|
2796 nsAutoCString path; |
|
2797 aFile->GetNativePath(path); |
|
2798 #endif |
|
2799 LOG(("CacheFileIOManager::TrashDirectory() [file=%s]", path.get())); |
|
2800 |
|
2801 nsresult rv; |
|
2802 |
|
2803 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2804 MOZ_ASSERT(mCacheDirectory); |
|
2805 |
|
2806 // When the directory is empty, it is cheaper to remove it directly instead of |
|
2807 // using the trash mechanism. |
|
2808 bool isEmpty; |
|
2809 rv = IsEmptyDirectory(aFile, &isEmpty); |
|
2810 NS_ENSURE_SUCCESS(rv, rv); |
|
2811 |
|
2812 if (isEmpty) { |
|
2813 rv = aFile->Remove(false); |
|
2814 LOG(("CacheFileIOManager::TrashDirectory() - Directory removed [rv=0x%08x]", |
|
2815 rv)); |
|
2816 return rv; |
|
2817 } |
|
2818 |
|
2819 #ifdef DEBUG |
|
2820 nsCOMPtr<nsIFile> dirCheck; |
|
2821 rv = aFile->GetParent(getter_AddRefs(dirCheck)); |
|
2822 NS_ENSURE_SUCCESS(rv, rv); |
|
2823 |
|
2824 bool equals = false; |
|
2825 rv = dirCheck->Equals(mCacheDirectory, &equals); |
|
2826 NS_ENSURE_SUCCESS(rv, rv); |
|
2827 |
|
2828 MOZ_ASSERT(equals); |
|
2829 #endif |
|
2830 |
|
2831 nsCOMPtr<nsIFile> dir, trash; |
|
2832 nsAutoCString leaf; |
|
2833 |
|
2834 rv = aFile->Clone(getter_AddRefs(dir)); |
|
2835 NS_ENSURE_SUCCESS(rv, rv); |
|
2836 |
|
2837 rv = aFile->Clone(getter_AddRefs(trash)); |
|
2838 NS_ENSURE_SUCCESS(rv, rv); |
|
2839 |
|
2840 srand(static_cast<unsigned>(PR_Now())); |
|
2841 while (true) { |
|
2842 leaf = kTrashDir; |
|
2843 leaf.AppendInt(rand()); |
|
2844 rv = trash->SetNativeLeafName(leaf); |
|
2845 NS_ENSURE_SUCCESS(rv, rv); |
|
2846 |
|
2847 bool exists; |
|
2848 if (NS_SUCCEEDED(trash->Exists(&exists)) && !exists) { |
|
2849 break; |
|
2850 } |
|
2851 } |
|
2852 |
|
2853 LOG(("CacheFileIOManager::TrashDirectory() - Renaming directory [leaf=%s]", |
|
2854 leaf.get())); |
|
2855 |
|
2856 rv = dir->MoveToNative(nullptr, leaf); |
|
2857 NS_ENSURE_SUCCESS(rv, rv); |
|
2858 |
|
2859 StartRemovingTrash(); |
|
2860 return NS_OK; |
|
2861 } |
|
2862 |
|
2863 // static |
|
2864 void |
|
2865 CacheFileIOManager::OnTrashTimer(nsITimer *aTimer, void *aClosure) |
|
2866 { |
|
2867 LOG(("CacheFileIOManager::OnTrashTimer() [timer=%p, closure=%p]", aTimer, |
|
2868 aClosure)); |
|
2869 |
|
2870 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
2871 |
|
2872 if (!ioMan) { |
|
2873 return; |
|
2874 } |
|
2875 |
|
2876 ioMan->mTrashTimer = nullptr; |
|
2877 ioMan->StartRemovingTrash(); |
|
2878 } |
|
2879 |
|
2880 nsresult |
|
2881 CacheFileIOManager::StartRemovingTrash() |
|
2882 { |
|
2883 LOG(("CacheFileIOManager::StartRemovingTrash()")); |
|
2884 |
|
2885 nsresult rv; |
|
2886 |
|
2887 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2888 |
|
2889 if (mShuttingDown) { |
|
2890 return NS_ERROR_NOT_INITIALIZED; |
|
2891 } |
|
2892 |
|
2893 if (!mCacheDirectory) { |
|
2894 return NS_ERROR_FILE_INVALID_PATH; |
|
2895 } |
|
2896 |
|
2897 if (mTrashTimer) { |
|
2898 LOG(("CacheFileIOManager::StartRemovingTrash() - Trash timer exists.")); |
|
2899 return NS_OK; |
|
2900 } |
|
2901 |
|
2902 if (mRemovingTrashDirs) { |
|
2903 LOG(("CacheFileIOManager::StartRemovingTrash() - Trash removing in " |
|
2904 "progress.")); |
|
2905 return NS_OK; |
|
2906 } |
|
2907 |
|
2908 uint32_t elapsed = (TimeStamp::NowLoRes() - mStartTime).ToMilliseconds(); |
|
2909 if (elapsed < kRemoveTrashStartDelay) { |
|
2910 nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv); |
|
2911 NS_ENSURE_SUCCESS(rv, rv); |
|
2912 |
|
2913 nsCOMPtr<nsIEventTarget> ioTarget = IOTarget(); |
|
2914 MOZ_ASSERT(ioTarget); |
|
2915 |
|
2916 rv = timer->SetTarget(ioTarget); |
|
2917 NS_ENSURE_SUCCESS(rv, rv); |
|
2918 |
|
2919 rv = timer->InitWithFuncCallback(CacheFileIOManager::OnTrashTimer, nullptr, |
|
2920 kRemoveTrashStartDelay - elapsed, |
|
2921 nsITimer::TYPE_ONE_SHOT); |
|
2922 NS_ENSURE_SUCCESS(rv, rv); |
|
2923 |
|
2924 mTrashTimer.swap(timer); |
|
2925 return NS_OK; |
|
2926 } |
|
2927 |
|
2928 nsCOMPtr<nsIRunnable> ev; |
|
2929 ev = NS_NewRunnableMethod(this, |
|
2930 &CacheFileIOManager::RemoveTrashInternal); |
|
2931 |
|
2932 rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); |
|
2933 NS_ENSURE_SUCCESS(rv, rv); |
|
2934 |
|
2935 mRemovingTrashDirs = true; |
|
2936 return NS_OK; |
|
2937 } |
|
2938 |
|
2939 nsresult |
|
2940 CacheFileIOManager::RemoveTrashInternal() |
|
2941 { |
|
2942 LOG(("CacheFileIOManager::RemoveTrashInternal()")); |
|
2943 |
|
2944 nsresult rv; |
|
2945 |
|
2946 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
2947 |
|
2948 if (mShuttingDown) { |
|
2949 return NS_ERROR_NOT_INITIALIZED; |
|
2950 } |
|
2951 |
|
2952 MOZ_ASSERT(!mTrashTimer); |
|
2953 MOZ_ASSERT(mRemovingTrashDirs); |
|
2954 |
|
2955 if (!mTreeCreated) { |
|
2956 rv = CreateCacheTree(); |
|
2957 if (NS_FAILED(rv)) { |
|
2958 return rv; |
|
2959 } |
|
2960 } |
|
2961 |
|
2962 // mRemovingTrashDirs is accessed only on IO thread, so we can drop the flag |
|
2963 // here and set it again once we dispatch a continuation event. By doing so, |
|
2964 // we don't have to drop the flag on any possible early return. |
|
2965 mRemovingTrashDirs = false; |
|
2966 |
|
2967 while (true) { |
|
2968 if (CacheIOThread::YieldAndRerun()) { |
|
2969 LOG(("CacheFileIOManager::RemoveTrashInternal() - Breaking loop for " |
|
2970 "higher level events.")); |
|
2971 mRemovingTrashDirs = true; |
|
2972 return NS_OK; |
|
2973 } |
|
2974 |
|
2975 // Find some trash directory |
|
2976 if (!mTrashDir) { |
|
2977 MOZ_ASSERT(!mTrashDirEnumerator); |
|
2978 |
|
2979 rv = FindTrashDirToRemove(); |
|
2980 if (rv == NS_ERROR_NOT_AVAILABLE) { |
|
2981 LOG(("CacheFileIOManager::RemoveTrashInternal() - No trash directory " |
|
2982 "found.")); |
|
2983 return NS_OK; |
|
2984 } |
|
2985 NS_ENSURE_SUCCESS(rv, rv); |
|
2986 |
|
2987 nsCOMPtr<nsISimpleEnumerator> enumerator; |
|
2988 rv = mTrashDir->GetDirectoryEntries(getter_AddRefs(enumerator)); |
|
2989 if (NS_SUCCEEDED(rv)) { |
|
2990 mTrashDirEnumerator = do_QueryInterface(enumerator, &rv); |
|
2991 NS_ENSURE_SUCCESS(rv, rv); |
|
2992 } |
|
2993 |
|
2994 continue; // check elapsed time |
|
2995 } |
|
2996 |
|
2997 // We null out mTrashDirEnumerator once we remove all files in the |
|
2998 // directory, so remove the trash directory if we don't have enumerator. |
|
2999 if (!mTrashDirEnumerator) { |
|
3000 rv = mTrashDir->Remove(false); |
|
3001 if (NS_FAILED(rv)) { |
|
3002 // There is no reason why removing an empty directory should fail, but |
|
3003 // if it does, we should continue and try to remove all other trash |
|
3004 // directories. |
|
3005 nsAutoCString leafName; |
|
3006 mTrashDir->GetNativeLeafName(leafName); |
|
3007 mFailedTrashDirs.AppendElement(leafName); |
|
3008 LOG(("CacheFileIOManager::RemoveTrashInternal() - Cannot remove " |
|
3009 "trashdir. [name=%s]", leafName.get())); |
|
3010 } |
|
3011 |
|
3012 mTrashDir = nullptr; |
|
3013 continue; // check elapsed time |
|
3014 } |
|
3015 |
|
3016 nsCOMPtr<nsIFile> file; |
|
3017 rv = mTrashDirEnumerator->GetNextFile(getter_AddRefs(file)); |
|
3018 if (!file) { |
|
3019 mTrashDirEnumerator->Close(); |
|
3020 mTrashDirEnumerator = nullptr; |
|
3021 continue; // check elapsed time |
|
3022 } else { |
|
3023 bool isDir = false; |
|
3024 file->IsDirectory(&isDir); |
|
3025 if (isDir) { |
|
3026 NS_WARNING("Found a directory in a trash directory! It will be removed " |
|
3027 "recursively, but this can block IO thread for a while!"); |
|
3028 #ifdef PR_LOGGING |
|
3029 nsAutoCString path; |
|
3030 file->GetNativePath(path); |
|
3031 #endif |
|
3032 LOG(("CacheFileIOManager::RemoveTrashInternal() - Found a directory in a trash " |
|
3033 "directory! It will be removed recursively, but this can block IO " |
|
3034 "thread for a while! [file=%s]", path.get())); |
|
3035 } |
|
3036 file->Remove(isDir); |
|
3037 } |
|
3038 } |
|
3039 |
|
3040 NS_NOTREACHED("We should never get here"); |
|
3041 return NS_OK; |
|
3042 } |
|
3043 |
|
3044 nsresult |
|
3045 CacheFileIOManager::FindTrashDirToRemove() |
|
3046 { |
|
3047 LOG(("CacheFileIOManager::FindTrashDirToRemove()")); |
|
3048 |
|
3049 nsresult rv; |
|
3050 |
|
3051 // We call this method on the main thread during shutdown when user wants to |
|
3052 // remove all cache files. |
|
3053 MOZ_ASSERT(mIOThread->IsCurrentThread() || mShuttingDown); |
|
3054 |
|
3055 nsCOMPtr<nsISimpleEnumerator> iter; |
|
3056 rv = mCacheDirectory->GetDirectoryEntries(getter_AddRefs(iter)); |
|
3057 NS_ENSURE_SUCCESS(rv, rv); |
|
3058 |
|
3059 bool more; |
|
3060 nsCOMPtr<nsISupports> elem; |
|
3061 |
|
3062 while (NS_SUCCEEDED(iter->HasMoreElements(&more)) && more) { |
|
3063 rv = iter->GetNext(getter_AddRefs(elem)); |
|
3064 if (NS_FAILED(rv)) { |
|
3065 continue; |
|
3066 } |
|
3067 |
|
3068 nsCOMPtr<nsIFile> file = do_QueryInterface(elem); |
|
3069 if (!file) { |
|
3070 continue; |
|
3071 } |
|
3072 |
|
3073 bool isDir = false; |
|
3074 file->IsDirectory(&isDir); |
|
3075 if (!isDir) { |
|
3076 continue; |
|
3077 } |
|
3078 |
|
3079 nsAutoCString leafName; |
|
3080 rv = file->GetNativeLeafName(leafName); |
|
3081 if (NS_FAILED(rv)) { |
|
3082 continue; |
|
3083 } |
|
3084 |
|
3085 if (leafName.Length() < strlen(kTrashDir)) { |
|
3086 continue; |
|
3087 } |
|
3088 |
|
3089 if (!StringBeginsWith(leafName, NS_LITERAL_CSTRING(kTrashDir))) { |
|
3090 continue; |
|
3091 } |
|
3092 |
|
3093 if (mFailedTrashDirs.Contains(leafName)) { |
|
3094 continue; |
|
3095 } |
|
3096 |
|
3097 LOG(("CacheFileIOManager::FindTrashDirToRemove() - Returning directory %s", |
|
3098 leafName.get())); |
|
3099 |
|
3100 mTrashDir = file; |
|
3101 return NS_OK; |
|
3102 } |
|
3103 |
|
3104 // When we're here we've tried to delete all trash directories. Clear |
|
3105 // mFailedTrashDirs so we will try to delete them again when we start removing |
|
3106 // trash directories next time. |
|
3107 mFailedTrashDirs.Clear(); |
|
3108 return NS_ERROR_NOT_AVAILABLE; |
|
3109 } |
|
3110 |
|
3111 // static |
|
3112 nsresult |
|
3113 CacheFileIOManager::InitIndexEntry(CacheFileHandle *aHandle, |
|
3114 uint32_t aAppId, |
|
3115 bool aAnonymous, |
|
3116 bool aInBrowser) |
|
3117 { |
|
3118 LOG(("CacheFileIOManager::InitIndexEntry() [handle=%p, appId=%u, anonymous=%d" |
|
3119 ", inBrowser=%d]", aHandle, aAppId, aAnonymous, aInBrowser)); |
|
3120 |
|
3121 nsresult rv; |
|
3122 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
3123 |
|
3124 if (aHandle->IsClosed() || !ioMan) { |
|
3125 return NS_ERROR_NOT_INITIALIZED; |
|
3126 } |
|
3127 |
|
3128 if (aHandle->IsSpecialFile()) { |
|
3129 return NS_ERROR_UNEXPECTED; |
|
3130 } |
|
3131 |
|
3132 nsRefPtr<InitIndexEntryEvent> ev = |
|
3133 new InitIndexEntryEvent(aHandle, aAppId, aAnonymous, aInBrowser); |
|
3134 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); |
|
3135 NS_ENSURE_SUCCESS(rv, rv); |
|
3136 |
|
3137 return NS_OK; |
|
3138 } |
|
3139 |
|
3140 // static |
|
3141 nsresult |
|
3142 CacheFileIOManager::UpdateIndexEntry(CacheFileHandle *aHandle, |
|
3143 const uint32_t *aFrecency, |
|
3144 const uint32_t *aExpirationTime) |
|
3145 { |
|
3146 LOG(("CacheFileIOManager::UpdateIndexEntry() [handle=%p, frecency=%s, " |
|
3147 "expirationTime=%s]", aHandle, |
|
3148 aFrecency ? nsPrintfCString("%u", *aFrecency).get() : "", |
|
3149 aExpirationTime ? nsPrintfCString("%u", *aExpirationTime).get() : "")); |
|
3150 |
|
3151 nsresult rv; |
|
3152 nsRefPtr<CacheFileIOManager> ioMan = gInstance; |
|
3153 |
|
3154 if (aHandle->IsClosed() || !ioMan) { |
|
3155 return NS_ERROR_NOT_INITIALIZED; |
|
3156 } |
|
3157 |
|
3158 if (aHandle->IsSpecialFile()) { |
|
3159 return NS_ERROR_UNEXPECTED; |
|
3160 } |
|
3161 |
|
3162 nsRefPtr<UpdateIndexEntryEvent> ev = |
|
3163 new UpdateIndexEntryEvent(aHandle, aFrecency, aExpirationTime); |
|
3164 rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::WRITE); |
|
3165 NS_ENSURE_SUCCESS(rv, rv); |
|
3166 |
|
3167 return NS_OK; |
|
3168 } |
|
3169 |
|
3170 nsresult |
|
3171 CacheFileIOManager::CreateFile(CacheFileHandle *aHandle) |
|
3172 { |
|
3173 MOZ_ASSERT(!aHandle->mFD); |
|
3174 MOZ_ASSERT(aHandle->mFile); |
|
3175 |
|
3176 nsresult rv; |
|
3177 |
|
3178 if (aHandle->IsDoomed()) { |
|
3179 nsCOMPtr<nsIFile> file; |
|
3180 |
|
3181 rv = GetDoomedFile(getter_AddRefs(file)); |
|
3182 NS_ENSURE_SUCCESS(rv, rv); |
|
3183 |
|
3184 aHandle->mFile.swap(file); |
|
3185 } else { |
|
3186 bool exists; |
|
3187 if (NS_SUCCEEDED(aHandle->mFile->Exists(&exists)) && exists) { |
|
3188 NS_WARNING("Found a file that should not exist!"); |
|
3189 } |
|
3190 } |
|
3191 |
|
3192 rv = OpenNSPRHandle(aHandle, true); |
|
3193 NS_ENSURE_SUCCESS(rv, rv); |
|
3194 |
|
3195 aHandle->mFileSize = 0; |
|
3196 return NS_OK; |
|
3197 } |
|
3198 |
|
3199 // static |
|
3200 void |
|
3201 CacheFileIOManager::HashToStr(const SHA1Sum::Hash *aHash, nsACString &_retval) |
|
3202 { |
|
3203 _retval.Assign(""); |
|
3204 const char hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', |
|
3205 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
|
3206 for (uint32_t i=0 ; i<sizeof(SHA1Sum::Hash) ; i++) { |
|
3207 _retval.Append(hexChars[(*aHash)[i] >> 4]); |
|
3208 _retval.Append(hexChars[(*aHash)[i] & 0xF]); |
|
3209 } |
|
3210 } |
|
3211 |
|
3212 // static |
|
3213 nsresult |
|
3214 CacheFileIOManager::StrToHash(const nsACString &aHash, SHA1Sum::Hash *_retval) |
|
3215 { |
|
3216 if (aHash.Length() != 2*sizeof(SHA1Sum::Hash)) { |
|
3217 return NS_ERROR_INVALID_ARG; |
|
3218 } |
|
3219 |
|
3220 for (uint32_t i=0 ; i<aHash.Length() ; i++) { |
|
3221 uint8_t value; |
|
3222 |
|
3223 if (aHash[i] >= '0' && aHash[i] <= '9') { |
|
3224 value = aHash[i] - '0'; |
|
3225 } else if (aHash[i] >= 'A' && aHash[i] <= 'F') { |
|
3226 value = aHash[i] - 'A' + 10; |
|
3227 } else if (aHash[i] >= 'a' && aHash[i] <= 'f') { |
|
3228 value = aHash[i] - 'a' + 10; |
|
3229 } else { |
|
3230 return NS_ERROR_INVALID_ARG; |
|
3231 } |
|
3232 |
|
3233 if (i%2 == 0) { |
|
3234 (reinterpret_cast<uint8_t *>(_retval))[i/2] = value << 4; |
|
3235 } else { |
|
3236 (reinterpret_cast<uint8_t *>(_retval))[i/2] += value; |
|
3237 } |
|
3238 } |
|
3239 |
|
3240 return NS_OK; |
|
3241 } |
|
3242 |
|
3243 nsresult |
|
3244 CacheFileIOManager::GetFile(const SHA1Sum::Hash *aHash, nsIFile **_retval) |
|
3245 { |
|
3246 nsresult rv; |
|
3247 nsCOMPtr<nsIFile> file; |
|
3248 rv = mCacheDirectory->Clone(getter_AddRefs(file)); |
|
3249 NS_ENSURE_SUCCESS(rv, rv); |
|
3250 |
|
3251 rv = file->AppendNative(NS_LITERAL_CSTRING(kEntriesDir)); |
|
3252 NS_ENSURE_SUCCESS(rv, rv); |
|
3253 |
|
3254 nsAutoCString leafName; |
|
3255 HashToStr(aHash, leafName); |
|
3256 |
|
3257 rv = file->AppendNative(leafName); |
|
3258 NS_ENSURE_SUCCESS(rv, rv); |
|
3259 |
|
3260 file.swap(*_retval); |
|
3261 return NS_OK; |
|
3262 } |
|
3263 |
|
3264 nsresult |
|
3265 CacheFileIOManager::GetSpecialFile(const nsACString &aKey, nsIFile **_retval) |
|
3266 { |
|
3267 nsresult rv; |
|
3268 nsCOMPtr<nsIFile> file; |
|
3269 rv = mCacheDirectory->Clone(getter_AddRefs(file)); |
|
3270 NS_ENSURE_SUCCESS(rv, rv); |
|
3271 |
|
3272 rv = file->AppendNative(aKey); |
|
3273 NS_ENSURE_SUCCESS(rv, rv); |
|
3274 |
|
3275 file.swap(*_retval); |
|
3276 return NS_OK; |
|
3277 } |
|
3278 |
|
3279 nsresult |
|
3280 CacheFileIOManager::GetDoomedFile(nsIFile **_retval) |
|
3281 { |
|
3282 nsresult rv; |
|
3283 nsCOMPtr<nsIFile> file; |
|
3284 rv = mCacheDirectory->Clone(getter_AddRefs(file)); |
|
3285 NS_ENSURE_SUCCESS(rv, rv); |
|
3286 |
|
3287 rv = file->AppendNative(NS_LITERAL_CSTRING(kDoomedDir)); |
|
3288 NS_ENSURE_SUCCESS(rv, rv); |
|
3289 |
|
3290 rv = file->AppendNative(NS_LITERAL_CSTRING("dummyleaf")); |
|
3291 NS_ENSURE_SUCCESS(rv, rv); |
|
3292 |
|
3293 srand(static_cast<unsigned>(PR_Now())); |
|
3294 nsAutoCString leafName; |
|
3295 uint32_t iter=0; |
|
3296 while (true) { |
|
3297 iter++; |
|
3298 leafName.AppendInt(rand()); |
|
3299 rv = file->SetNativeLeafName(leafName); |
|
3300 NS_ENSURE_SUCCESS(rv, rv); |
|
3301 |
|
3302 bool exists; |
|
3303 if (NS_SUCCEEDED(file->Exists(&exists)) && !exists) { |
|
3304 break; |
|
3305 } |
|
3306 |
|
3307 leafName.Truncate(); |
|
3308 } |
|
3309 |
|
3310 // Telemetry::Accumulate(Telemetry::DISK_CACHE_GETDOOMEDFILE_ITERATIONS, iter); |
|
3311 |
|
3312 file.swap(*_retval); |
|
3313 return NS_OK; |
|
3314 } |
|
3315 |
|
3316 nsresult |
|
3317 CacheFileIOManager::IsEmptyDirectory(nsIFile *aFile, bool *_retval) |
|
3318 { |
|
3319 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
3320 |
|
3321 nsresult rv; |
|
3322 |
|
3323 nsCOMPtr<nsISimpleEnumerator> enumerator; |
|
3324 rv = aFile->GetDirectoryEntries(getter_AddRefs(enumerator)); |
|
3325 NS_ENSURE_SUCCESS(rv, rv); |
|
3326 |
|
3327 bool hasMoreElements = false; |
|
3328 rv = enumerator->HasMoreElements(&hasMoreElements); |
|
3329 NS_ENSURE_SUCCESS(rv, rv); |
|
3330 |
|
3331 *_retval = !hasMoreElements; |
|
3332 return NS_OK; |
|
3333 } |
|
3334 |
|
3335 nsresult |
|
3336 CacheFileIOManager::CheckAndCreateDir(nsIFile *aFile, const char *aDir, |
|
3337 bool aEnsureEmptyDir) |
|
3338 { |
|
3339 nsresult rv; |
|
3340 |
|
3341 nsCOMPtr<nsIFile> file; |
|
3342 if (!aDir) { |
|
3343 file = aFile; |
|
3344 } else { |
|
3345 nsAutoCString dir(aDir); |
|
3346 rv = aFile->Clone(getter_AddRefs(file)); |
|
3347 NS_ENSURE_SUCCESS(rv, rv); |
|
3348 rv = file->AppendNative(dir); |
|
3349 NS_ENSURE_SUCCESS(rv, rv); |
|
3350 } |
|
3351 |
|
3352 bool exists = false; |
|
3353 rv = file->Exists(&exists); |
|
3354 if (NS_SUCCEEDED(rv) && exists) { |
|
3355 bool isDirectory = false; |
|
3356 rv = file->IsDirectory(&isDirectory); |
|
3357 if (NS_FAILED(rv) || !isDirectory) { |
|
3358 // Try to remove the file |
|
3359 rv = file->Remove(false); |
|
3360 if (NS_SUCCEEDED(rv)) { |
|
3361 exists = false; |
|
3362 } |
|
3363 } |
|
3364 NS_ENSURE_SUCCESS(rv, rv); |
|
3365 } |
|
3366 |
|
3367 if (aEnsureEmptyDir && NS_SUCCEEDED(rv) && exists) { |
|
3368 bool isEmpty; |
|
3369 rv = IsEmptyDirectory(file, &isEmpty); |
|
3370 NS_ENSURE_SUCCESS(rv, rv); |
|
3371 |
|
3372 if (!isEmpty) { |
|
3373 rv = TrashDirectory(file); |
|
3374 NS_ENSURE_SUCCESS(rv, rv); |
|
3375 |
|
3376 exists = false; |
|
3377 } |
|
3378 } |
|
3379 |
|
3380 if (NS_SUCCEEDED(rv) && !exists) { |
|
3381 rv = file->Create(nsIFile::DIRECTORY_TYPE, 0700); |
|
3382 } |
|
3383 if (NS_FAILED(rv)) { |
|
3384 NS_WARNING("Cannot create directory"); |
|
3385 return NS_ERROR_FAILURE; |
|
3386 } |
|
3387 |
|
3388 return NS_OK; |
|
3389 } |
|
3390 |
|
3391 nsresult |
|
3392 CacheFileIOManager::CreateCacheTree() |
|
3393 { |
|
3394 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
3395 MOZ_ASSERT(!mTreeCreated); |
|
3396 |
|
3397 if (!mCacheDirectory) { |
|
3398 return NS_ERROR_FILE_INVALID_PATH; |
|
3399 } |
|
3400 |
|
3401 nsresult rv; |
|
3402 |
|
3403 // ensure parent directory exists |
|
3404 nsCOMPtr<nsIFile> parentDir; |
|
3405 rv = mCacheDirectory->GetParent(getter_AddRefs(parentDir)); |
|
3406 NS_ENSURE_SUCCESS(rv, rv); |
|
3407 rv = CheckAndCreateDir(parentDir, nullptr, false); |
|
3408 NS_ENSURE_SUCCESS(rv, rv); |
|
3409 |
|
3410 // ensure cache directory exists |
|
3411 rv = CheckAndCreateDir(mCacheDirectory, nullptr, false); |
|
3412 NS_ENSURE_SUCCESS(rv, rv); |
|
3413 |
|
3414 // ensure entries directory exists |
|
3415 rv = CheckAndCreateDir(mCacheDirectory, kEntriesDir, false); |
|
3416 NS_ENSURE_SUCCESS(rv, rv); |
|
3417 |
|
3418 // ensure doomed directory exists |
|
3419 rv = CheckAndCreateDir(mCacheDirectory, kDoomedDir, true); |
|
3420 NS_ENSURE_SUCCESS(rv, rv); |
|
3421 |
|
3422 mTreeCreated = true; |
|
3423 |
|
3424 if (!mContextEvictor) { |
|
3425 nsRefPtr<CacheFileContextEvictor> contextEvictor; |
|
3426 contextEvictor = new CacheFileContextEvictor(); |
|
3427 |
|
3428 // Init() method will try to load unfinished contexts from the disk. Store |
|
3429 // the evictor as a member only when there is some unfinished job. |
|
3430 contextEvictor->Init(mCacheDirectory); |
|
3431 if (contextEvictor->ContextsCount()) { |
|
3432 contextEvictor.swap(mContextEvictor); |
|
3433 } |
|
3434 } |
|
3435 |
|
3436 StartRemovingTrash(); |
|
3437 |
|
3438 return NS_OK; |
|
3439 } |
|
3440 |
|
3441 nsresult |
|
3442 CacheFileIOManager::OpenNSPRHandle(CacheFileHandle *aHandle, bool aCreate) |
|
3443 { |
|
3444 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
3445 MOZ_ASSERT(!aHandle->mFD); |
|
3446 MOZ_ASSERT(mHandlesByLastUsed.IndexOf(aHandle) == mHandlesByLastUsed.NoIndex); |
|
3447 MOZ_ASSERT(mHandlesByLastUsed.Length() <= kOpenHandlesLimit); |
|
3448 MOZ_ASSERT((aCreate && !aHandle->mFileExists) || |
|
3449 (!aCreate && aHandle->mFileExists)); |
|
3450 |
|
3451 nsresult rv; |
|
3452 |
|
3453 if (mHandlesByLastUsed.Length() == kOpenHandlesLimit) { |
|
3454 // close handle that hasn't been used for the longest time |
|
3455 rv = ReleaseNSPRHandleInternal(mHandlesByLastUsed[0]); |
|
3456 NS_ENSURE_SUCCESS(rv, rv); |
|
3457 } |
|
3458 |
|
3459 if (aCreate) { |
|
3460 rv = aHandle->mFile->OpenNSPRFileDesc( |
|
3461 PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0600, &aHandle->mFD); |
|
3462 NS_ENSURE_SUCCESS(rv, rv); |
|
3463 |
|
3464 aHandle->mFileExists = true; |
|
3465 } else { |
|
3466 rv = aHandle->mFile->OpenNSPRFileDesc(PR_RDWR, 0600, &aHandle->mFD); |
|
3467 if (NS_ERROR_FILE_NOT_FOUND == rv) { |
|
3468 LOG((" file doesn't exists")); |
|
3469 aHandle->mFileExists = false; |
|
3470 return DoomFileInternal(aHandle); |
|
3471 } |
|
3472 NS_ENSURE_SUCCESS(rv, rv); |
|
3473 } |
|
3474 |
|
3475 mHandlesByLastUsed.AppendElement(aHandle); |
|
3476 return NS_OK; |
|
3477 } |
|
3478 |
|
3479 void |
|
3480 CacheFileIOManager::NSPRHandleUsed(CacheFileHandle *aHandle) |
|
3481 { |
|
3482 MOZ_ASSERT(CacheFileIOManager::IsOnIOThreadOrCeased()); |
|
3483 MOZ_ASSERT(aHandle->mFD); |
|
3484 |
|
3485 DebugOnly<bool> found; |
|
3486 found = mHandlesByLastUsed.RemoveElement(aHandle); |
|
3487 MOZ_ASSERT(found); |
|
3488 |
|
3489 mHandlesByLastUsed.AppendElement(aHandle); |
|
3490 } |
|
3491 |
|
3492 nsresult |
|
3493 CacheFileIOManager::SyncRemoveDir(nsIFile *aFile, const char *aDir) |
|
3494 { |
|
3495 nsresult rv; |
|
3496 nsCOMPtr<nsIFile> file; |
|
3497 |
|
3498 if (!aDir) { |
|
3499 file = aFile; |
|
3500 } else { |
|
3501 rv = aFile->Clone(getter_AddRefs(file)); |
|
3502 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3503 return rv; |
|
3504 } |
|
3505 |
|
3506 rv = file->AppendNative(nsDependentCString(aDir)); |
|
3507 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3508 return rv; |
|
3509 } |
|
3510 } |
|
3511 |
|
3512 #ifdef PR_LOGGING |
|
3513 nsAutoCString path; |
|
3514 file->GetNativePath(path); |
|
3515 #endif |
|
3516 |
|
3517 LOG(("CacheFileIOManager::SyncRemoveDir() - Removing directory %s", |
|
3518 path.get())); |
|
3519 |
|
3520 rv = file->Remove(true); |
|
3521 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3522 LOG(("CacheFileIOManager::SyncRemoveDir() - Removing failed! [rv=0x%08x]", |
|
3523 rv)); |
|
3524 } |
|
3525 |
|
3526 return rv; |
|
3527 } |
|
3528 |
|
3529 void |
|
3530 CacheFileIOManager::SyncRemoveAllCacheFiles() |
|
3531 { |
|
3532 LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles()")); |
|
3533 |
|
3534 nsresult rv; |
|
3535 |
|
3536 SyncRemoveDir(mCacheDirectory, kEntriesDir); |
|
3537 SyncRemoveDir(mCacheDirectory, kDoomedDir); |
|
3538 |
|
3539 // Clear any intermediate state of trash dir enumeration. |
|
3540 mFailedTrashDirs.Clear(); |
|
3541 mTrashDir = nullptr; |
|
3542 |
|
3543 while (true) { |
|
3544 // FindTrashDirToRemove() fills mTrashDir if there is any trash directory. |
|
3545 rv = FindTrashDirToRemove(); |
|
3546 if (rv == NS_ERROR_NOT_AVAILABLE) { |
|
3547 LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles() - No trash directory " |
|
3548 "found.")); |
|
3549 break; |
|
3550 } |
|
3551 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3552 LOG(("CacheFileIOManager::SyncRemoveAllCacheFiles() - " |
|
3553 "FindTrashDirToRemove() returned an unexpected error. [rv=0x%08x]", |
|
3554 rv)); |
|
3555 break; |
|
3556 } |
|
3557 |
|
3558 rv = SyncRemoveDir(mTrashDir, nullptr); |
|
3559 if (NS_FAILED(rv)) { |
|
3560 nsAutoCString leafName; |
|
3561 mTrashDir->GetNativeLeafName(leafName); |
|
3562 mFailedTrashDirs.AppendElement(leafName); |
|
3563 } |
|
3564 } |
|
3565 } |
|
3566 |
|
3567 // Returns default ("smart") size (in KB) of cache, given available disk space |
|
3568 // (also in KB) |
|
3569 static uint32_t |
|
3570 SmartCacheSize(const uint32_t availKB) |
|
3571 { |
|
3572 uint32_t maxSize = kMaxCacheSizeKB; |
|
3573 |
|
3574 if (availKB > 100 * 1024 * 1024) { |
|
3575 return maxSize; // skip computing if we're over 100 GB |
|
3576 } |
|
3577 |
|
3578 // Grow/shrink in 10 MB units, deliberately, so that in the common case we |
|
3579 // don't shrink cache and evict items every time we startup (it's important |
|
3580 // that we don't slow down startup benchmarks). |
|
3581 uint32_t sz10MBs = 0; |
|
3582 uint32_t avail10MBs = availKB / (1024*10); |
|
3583 |
|
3584 // .5% of space above 25 GB |
|
3585 if (avail10MBs > 2500) { |
|
3586 sz10MBs += static_cast<uint32_t>((avail10MBs - 2500)*.005); |
|
3587 avail10MBs = 2500; |
|
3588 } |
|
3589 // 1% of space between 7GB -> 25 GB |
|
3590 if (avail10MBs > 700) { |
|
3591 sz10MBs += static_cast<uint32_t>((avail10MBs - 700)*.01); |
|
3592 avail10MBs = 700; |
|
3593 } |
|
3594 // 5% of space between 500 MB -> 7 GB |
|
3595 if (avail10MBs > 50) { |
|
3596 sz10MBs += static_cast<uint32_t>((avail10MBs - 50)*.05); |
|
3597 avail10MBs = 50; |
|
3598 } |
|
3599 |
|
3600 #ifdef ANDROID |
|
3601 // On Android, smaller/older devices may have very little storage and |
|
3602 // device owners may be sensitive to storage footprint: Use a smaller |
|
3603 // percentage of available space and a smaller minimum. |
|
3604 |
|
3605 // 20% of space up to 500 MB (10 MB min) |
|
3606 sz10MBs += std::max<uint32_t>(1, static_cast<uint32_t>(avail10MBs * .2)); |
|
3607 #else |
|
3608 // 40% of space up to 500 MB (50 MB min) |
|
3609 sz10MBs += std::max<uint32_t>(5, static_cast<uint32_t>(avail10MBs * .4)); |
|
3610 #endif |
|
3611 |
|
3612 return std::min<uint32_t>(maxSize, sz10MBs * 10 * 1024); |
|
3613 } |
|
3614 |
|
3615 nsresult |
|
3616 CacheFileIOManager::UpdateSmartCacheSize() |
|
3617 { |
|
3618 MOZ_ASSERT(mIOThread->IsCurrentThread()); |
|
3619 |
|
3620 nsresult rv; |
|
3621 |
|
3622 if (!CacheObserver::UseNewCache()) { |
|
3623 return NS_ERROR_NOT_AVAILABLE; |
|
3624 } |
|
3625 |
|
3626 if (!CacheObserver::SmartCacheSizeEnabled()) { |
|
3627 return NS_ERROR_NOT_AVAILABLE; |
|
3628 } |
|
3629 |
|
3630 // Wait at least kSmartSizeUpdateInterval before recomputing smart size. |
|
3631 static const TimeDuration kUpdateLimit = |
|
3632 TimeDuration::FromMilliseconds(kSmartSizeUpdateInterval); |
|
3633 if (!mLastSmartSizeTime.IsNull() && |
|
3634 (TimeStamp::NowLoRes() - mLastSmartSizeTime) < kUpdateLimit) { |
|
3635 return NS_OK; |
|
3636 } |
|
3637 |
|
3638 // Do not compute smart size when cache size is not reliable. |
|
3639 bool isUpToDate = false; |
|
3640 CacheIndex::IsUpToDate(&isUpToDate); |
|
3641 if (!isUpToDate) { |
|
3642 return NS_ERROR_NOT_AVAILABLE; |
|
3643 } |
|
3644 |
|
3645 uint32_t cacheUsage; |
|
3646 rv = CacheIndex::GetCacheSize(&cacheUsage); |
|
3647 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3648 LOG(("CacheFileIOManager::UpdateSmartCacheSize() - Cannot get cacheUsage! " |
|
3649 "[rv=0x%08x]", rv)); |
|
3650 return rv; |
|
3651 } |
|
3652 |
|
3653 int64_t avail; |
|
3654 rv = mCacheDirectory->GetDiskSpaceAvailable(&avail); |
|
3655 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
3656 // Do not change smart size. |
|
3657 LOG(("CacheFileIOManager::UpdateSmartCacheSize() - GetDiskSpaceAvailable() " |
|
3658 "failed! [rv=0x%08x]", rv)); |
|
3659 return rv; |
|
3660 } |
|
3661 |
|
3662 mLastSmartSizeTime = TimeStamp::NowLoRes(); |
|
3663 |
|
3664 uint32_t smartSize = SmartCacheSize(static_cast<uint32_t>(avail / 1024) + |
|
3665 cacheUsage); |
|
3666 |
|
3667 if (smartSize == (CacheObserver::DiskCacheCapacity() >> 10)) { |
|
3668 // Smart size has not changed. |
|
3669 return NS_OK; |
|
3670 } |
|
3671 |
|
3672 CacheObserver::SetDiskCacheCapacity(smartSize << 10); |
|
3673 |
|
3674 return NS_OK; |
|
3675 } |
|
3676 |
|
3677 // Memory reporting |
|
3678 |
|
3679 namespace { // anon |
|
3680 |
|
3681 // A helper class that dispatches and waits for an event that gets result of |
|
3682 // CacheFileIOManager->mHandles.SizeOfExcludingThis() on the I/O thread |
|
3683 // to safely get handles memory report. |
|
3684 // We must do this, since the handle list is only accessed and managed w/o |
|
3685 // locking on the I/O thread. That is by design. |
|
3686 class SizeOfHandlesRunnable : public nsRunnable |
|
3687 { |
|
3688 public: |
|
3689 SizeOfHandlesRunnable(mozilla::MallocSizeOf mallocSizeOf, |
|
3690 CacheFileHandles const &handles, |
|
3691 nsTArray<CacheFileHandle *> const &specialHandles) |
|
3692 : mMonitor("SizeOfHandlesRunnable.mMonitor") |
|
3693 , mMallocSizeOf(mallocSizeOf) |
|
3694 , mHandles(handles) |
|
3695 , mSpecialHandles(specialHandles) |
|
3696 { |
|
3697 } |
|
3698 |
|
3699 size_t Get(CacheIOThread* thread) |
|
3700 { |
|
3701 nsCOMPtr<nsIEventTarget> target = thread->Target(); |
|
3702 if (!target) { |
|
3703 NS_ERROR("If we have the I/O thread we also must have the I/O target"); |
|
3704 return 0; |
|
3705 } |
|
3706 |
|
3707 mozilla::MonitorAutoLock mon(mMonitor); |
|
3708 nsresult rv = target->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL); |
|
3709 if (NS_FAILED(rv)) { |
|
3710 NS_ERROR("Dispatch failed, cannot do memory report of CacheFileHandles"); |
|
3711 return 0; |
|
3712 } |
|
3713 |
|
3714 mon.Wait(); |
|
3715 return mSize; |
|
3716 } |
|
3717 |
|
3718 NS_IMETHOD Run() |
|
3719 { |
|
3720 mozilla::MonitorAutoLock mon(mMonitor); |
|
3721 // Excluding this since the object itself is a member of CacheFileIOManager |
|
3722 // reported in CacheFileIOManager::SizeOfIncludingThis as part of |this|. |
|
3723 mSize = mHandles.SizeOfExcludingThis(mMallocSizeOf); |
|
3724 for (uint32_t i = 0; i < mSpecialHandles.Length(); ++i) { |
|
3725 mSize += mSpecialHandles[i]->SizeOfIncludingThis(mMallocSizeOf); |
|
3726 } |
|
3727 |
|
3728 mon.Notify(); |
|
3729 return NS_OK; |
|
3730 } |
|
3731 |
|
3732 private: |
|
3733 mozilla::Monitor mMonitor; |
|
3734 mozilla::MallocSizeOf mMallocSizeOf; |
|
3735 CacheFileHandles const &mHandles; |
|
3736 nsTArray<CacheFileHandle *> const &mSpecialHandles; |
|
3737 size_t mSize; |
|
3738 }; |
|
3739 |
|
3740 } // anon |
|
3741 |
|
3742 size_t |
|
3743 CacheFileIOManager::SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const |
|
3744 { |
|
3745 size_t n = 0; |
|
3746 nsCOMPtr<nsISizeOf> sizeOf; |
|
3747 |
|
3748 if (mIOThread) { |
|
3749 n += mIOThread->SizeOfIncludingThis(mallocSizeOf); |
|
3750 |
|
3751 // mHandles and mSpecialHandles must be accessed only on the I/O thread, |
|
3752 // must sync dispatch. |
|
3753 nsRefPtr<SizeOfHandlesRunnable> sizeOfHandlesRunnable = |
|
3754 new SizeOfHandlesRunnable(mallocSizeOf, mHandles, mSpecialHandles); |
|
3755 n += sizeOfHandlesRunnable->Get(mIOThread); |
|
3756 } |
|
3757 |
|
3758 // mHandlesByLastUsed just refers handles reported by mHandles. |
|
3759 |
|
3760 sizeOf = do_QueryInterface(mCacheDirectory); |
|
3761 if (sizeOf) |
|
3762 n += sizeOf->SizeOfIncludingThis(mallocSizeOf); |
|
3763 |
|
3764 sizeOf = do_QueryInterface(mMetadataWritesTimer); |
|
3765 if (sizeOf) |
|
3766 n += sizeOf->SizeOfIncludingThis(mallocSizeOf); |
|
3767 |
|
3768 sizeOf = do_QueryInterface(mTrashTimer); |
|
3769 if (sizeOf) |
|
3770 n += sizeOf->SizeOfIncludingThis(mallocSizeOf); |
|
3771 |
|
3772 sizeOf = do_QueryInterface(mTrashDir); |
|
3773 if (sizeOf) |
|
3774 n += sizeOf->SizeOfIncludingThis(mallocSizeOf); |
|
3775 |
|
3776 for (uint32_t i = 0; i < mFailedTrashDirs.Length(); ++i) { |
|
3777 n += mFailedTrashDirs[i].SizeOfExcludingThisIfUnshared(mallocSizeOf); |
|
3778 } |
|
3779 |
|
3780 return n; |
|
3781 } |
|
3782 |
|
3783 // static |
|
3784 size_t |
|
3785 CacheFileIOManager::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) |
|
3786 { |
|
3787 if (!gInstance) |
|
3788 return 0; |
|
3789 |
|
3790 return gInstance->SizeOfExcludingThisInternal(mallocSizeOf); |
|
3791 } |
|
3792 |
|
3793 // static |
|
3794 size_t |
|
3795 CacheFileIOManager::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) |
|
3796 { |
|
3797 return mallocSizeOf(gInstance) + SizeOfExcludingThis(mallocSizeOf); |
|
3798 } |
|
3799 |
|
3800 } // net |
|
3801 } // mozilla |