|
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 "CacheFileContextEvictor.h" |
|
7 #include "CacheFileIOManager.h" |
|
8 #include "CacheIndex.h" |
|
9 #include "CacheIndexIterator.h" |
|
10 #include "CacheFileUtils.h" |
|
11 #include "nsIFile.h" |
|
12 #include "LoadContextInfo.h" |
|
13 #include "nsThreadUtils.h" |
|
14 #include "nsString.h" |
|
15 #include "nsISimpleEnumerator.h" |
|
16 #include "nsIDirectoryEnumerator.h" |
|
17 #include "mozilla/Base64.h" |
|
18 |
|
19 |
|
20 namespace mozilla { |
|
21 namespace net { |
|
22 |
|
23 const char kContextEvictionPrefix[] = "ce_"; |
|
24 const uint32_t kContextEvictionPrefixLength = |
|
25 sizeof(kContextEvictionPrefix) - 1; |
|
26 |
|
27 bool CacheFileContextEvictor::sDiskAlreadySearched = false; |
|
28 |
|
29 CacheFileContextEvictor::CacheFileContextEvictor() |
|
30 : mEvicting(false) |
|
31 , mIndexIsUpToDate(false) |
|
32 { |
|
33 LOG(("CacheFileContextEvictor::CacheFileContextEvictor() [this=%p]", this)); |
|
34 } |
|
35 |
|
36 CacheFileContextEvictor::~CacheFileContextEvictor() |
|
37 { |
|
38 LOG(("CacheFileContextEvictor::~CacheFileContextEvictor() [this=%p]", this)); |
|
39 } |
|
40 |
|
41 nsresult |
|
42 CacheFileContextEvictor::Init(nsIFile *aCacheDirectory) |
|
43 { |
|
44 LOG(("CacheFileContextEvictor::Init()")); |
|
45 |
|
46 nsresult rv; |
|
47 |
|
48 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
49 |
|
50 CacheIndex::IsUpToDate(&mIndexIsUpToDate); |
|
51 |
|
52 mCacheDirectory = aCacheDirectory; |
|
53 |
|
54 rv = aCacheDirectory->Clone(getter_AddRefs(mEntriesDir)); |
|
55 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
56 return rv; |
|
57 } |
|
58 |
|
59 rv = mEntriesDir->AppendNative(NS_LITERAL_CSTRING(kEntriesDir)); |
|
60 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
61 return rv; |
|
62 } |
|
63 |
|
64 if (!sDiskAlreadySearched) { |
|
65 LoadEvictInfoFromDisk(); |
|
66 if ((mEntries.Length() != 0) && mIndexIsUpToDate) { |
|
67 CreateIterators(); |
|
68 StartEvicting(); |
|
69 } |
|
70 } |
|
71 |
|
72 return NS_OK; |
|
73 } |
|
74 |
|
75 uint32_t |
|
76 CacheFileContextEvictor::ContextsCount() |
|
77 { |
|
78 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
79 |
|
80 return mEntries.Length(); |
|
81 } |
|
82 |
|
83 nsresult |
|
84 CacheFileContextEvictor::AddContext(nsILoadContextInfo *aLoadContextInfo) |
|
85 { |
|
86 LOG(("CacheFileContextEvictor::AddContext() [this=%p, loadContextInfo=%p]", |
|
87 this, aLoadContextInfo)); |
|
88 |
|
89 nsresult rv; |
|
90 |
|
91 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
92 |
|
93 CacheFileContextEvictorEntry *entry = nullptr; |
|
94 for (uint32_t i = 0; i < mEntries.Length(); ++i) { |
|
95 if (mEntries[i]->mInfo->Equals(aLoadContextInfo)) { |
|
96 entry = mEntries[i]; |
|
97 break; |
|
98 } |
|
99 } |
|
100 |
|
101 if (!entry) { |
|
102 entry = new CacheFileContextEvictorEntry(); |
|
103 entry->mInfo = aLoadContextInfo; |
|
104 mEntries.AppendElement(entry); |
|
105 } |
|
106 |
|
107 entry->mTimeStamp = PR_Now() / PR_USEC_PER_MSEC; |
|
108 |
|
109 PersistEvictionInfoToDisk(aLoadContextInfo); |
|
110 |
|
111 if (mIndexIsUpToDate) { |
|
112 // Already existing context could be added again, in this case the iterator |
|
113 // would be recreated. Close the old iterator explicitely. |
|
114 if (entry->mIterator) { |
|
115 entry->mIterator->Close(); |
|
116 entry->mIterator = nullptr; |
|
117 } |
|
118 |
|
119 rv = CacheIndex::GetIterator(aLoadContextInfo, false, |
|
120 getter_AddRefs(entry->mIterator)); |
|
121 if (NS_FAILED(rv)) { |
|
122 // This could probably happen during shutdown. Remove the entry from |
|
123 // the array, but leave the info on the disk. No entry can be opened |
|
124 // during shutdown and we'll load the eviction info on next start. |
|
125 LOG(("CacheFileContextEvictor::AddContext() - Cannot get an iterator. " |
|
126 "[rv=0x%08x]", rv)); |
|
127 mEntries.RemoveElement(entry); |
|
128 return rv; |
|
129 } |
|
130 |
|
131 StartEvicting(); |
|
132 } |
|
133 |
|
134 return NS_OK; |
|
135 } |
|
136 |
|
137 nsresult |
|
138 CacheFileContextEvictor::CacheIndexStateChanged() |
|
139 { |
|
140 LOG(("CacheFileContextEvictor::CacheIndexStateChanged() [this=%p]", this)); |
|
141 |
|
142 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
143 |
|
144 bool isUpToDate = false; |
|
145 CacheIndex::IsUpToDate(&isUpToDate); |
|
146 if (mEntries.Length() == 0) { |
|
147 // Just save the state and exit, since there is nothing to do |
|
148 mIndexIsUpToDate = isUpToDate; |
|
149 return NS_OK; |
|
150 } |
|
151 |
|
152 if (!isUpToDate && !mIndexIsUpToDate) { |
|
153 // Index is outdated and status has not changed, nothing to do. |
|
154 return NS_OK; |
|
155 } |
|
156 |
|
157 if (isUpToDate && mIndexIsUpToDate) { |
|
158 // Status has not changed, but make sure the eviction is running. |
|
159 if (mEvicting) { |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
163 // We're not evicting, but we should be evicting?! |
|
164 LOG(("CacheFileContextEvictor::CacheIndexStateChanged() - Index is up to " |
|
165 "date, we have some context to evict but eviction is not running! " |
|
166 "Starting now.")); |
|
167 } |
|
168 |
|
169 mIndexIsUpToDate = isUpToDate; |
|
170 |
|
171 if (mIndexIsUpToDate) { |
|
172 CreateIterators(); |
|
173 StartEvicting(); |
|
174 } else { |
|
175 CloseIterators(); |
|
176 } |
|
177 |
|
178 return NS_OK; |
|
179 } |
|
180 |
|
181 nsresult |
|
182 CacheFileContextEvictor::WasEvicted(const nsACString &aKey, nsIFile *aFile, |
|
183 bool *_retval) |
|
184 { |
|
185 LOG(("CacheFileContextEvictor::WasEvicted() [key=%s]", |
|
186 PromiseFlatCString(aKey).get())); |
|
187 |
|
188 nsresult rv; |
|
189 |
|
190 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
191 |
|
192 nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey); |
|
193 MOZ_ASSERT(info); |
|
194 if (!info) { |
|
195 LOG(("CacheFileContextEvictor::WasEvicted() - Cannot parse key!")); |
|
196 *_retval = false; |
|
197 return NS_OK; |
|
198 } |
|
199 |
|
200 CacheFileContextEvictorEntry *entry = nullptr; |
|
201 for (uint32_t i = 0; i < mEntries.Length(); ++i) { |
|
202 if (info->Equals(mEntries[i]->mInfo)) { |
|
203 entry = mEntries[i]; |
|
204 break; |
|
205 } |
|
206 } |
|
207 |
|
208 if (!entry) { |
|
209 LOG(("CacheFileContextEvictor::WasEvicted() - Didn't find equal context, " |
|
210 "returning false.")); |
|
211 *_retval = false; |
|
212 return NS_OK; |
|
213 } |
|
214 |
|
215 PRTime lastModifiedTime; |
|
216 rv = aFile->GetLastModifiedTime(&lastModifiedTime); |
|
217 if (NS_FAILED(rv)) { |
|
218 LOG(("CacheFileContextEvictor::WasEvicted() - Cannot get last modified time" |
|
219 ", returning false.")); |
|
220 *_retval = false; |
|
221 return NS_OK; |
|
222 } |
|
223 |
|
224 *_retval = !(lastModifiedTime > entry->mTimeStamp); |
|
225 LOG(("CacheFileContextEvictor::WasEvicted() - returning %s. [mTimeStamp=%lld," |
|
226 " lastModifiedTime=%lld]", *_retval ? "true" : "false", |
|
227 mEntries[0]->mTimeStamp, lastModifiedTime)); |
|
228 |
|
229 return NS_OK; |
|
230 } |
|
231 |
|
232 nsresult |
|
233 CacheFileContextEvictor::PersistEvictionInfoToDisk( |
|
234 nsILoadContextInfo *aLoadContextInfo) |
|
235 { |
|
236 LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() [this=%p, " |
|
237 "loadContextInfo=%p]", this, aLoadContextInfo)); |
|
238 |
|
239 nsresult rv; |
|
240 |
|
241 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
242 |
|
243 nsCOMPtr<nsIFile> file; |
|
244 rv = GetContextFile(aLoadContextInfo, getter_AddRefs(file)); |
|
245 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
246 return rv; |
|
247 } |
|
248 |
|
249 #ifdef PR_LOGGING |
|
250 nsAutoCString path; |
|
251 file->GetNativePath(path); |
|
252 #endif |
|
253 |
|
254 PRFileDesc *fd; |
|
255 rv = file->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0600, |
|
256 &fd); |
|
257 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
258 LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() - Creating file " |
|
259 "failed! [path=%s, rv=0x%08x]", path.get(), rv)); |
|
260 return rv; |
|
261 } |
|
262 |
|
263 PR_Close(fd); |
|
264 |
|
265 LOG(("CacheFileContextEvictor::PersistEvictionInfoToDisk() - Successfully " |
|
266 "created file. [path=%s]", path.get())); |
|
267 |
|
268 return NS_OK; |
|
269 } |
|
270 |
|
271 nsresult |
|
272 CacheFileContextEvictor::RemoveEvictInfoFromDisk( |
|
273 nsILoadContextInfo *aLoadContextInfo) |
|
274 { |
|
275 LOG(("CacheFileContextEvictor::RemoveEvictInfoFromDisk() [this=%p, " |
|
276 "loadContextInfo=%p]", this, aLoadContextInfo)); |
|
277 |
|
278 nsresult rv; |
|
279 |
|
280 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
281 |
|
282 nsCOMPtr<nsIFile> file; |
|
283 rv = GetContextFile(aLoadContextInfo, getter_AddRefs(file)); |
|
284 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
285 return rv; |
|
286 } |
|
287 |
|
288 #ifdef PR_LOGGING |
|
289 nsAutoCString path; |
|
290 file->GetNativePath(path); |
|
291 #endif |
|
292 |
|
293 rv = file->Remove(false); |
|
294 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
295 LOG(("CacheFileContextEvictor::RemoveEvictionInfoFromDisk() - Removing file" |
|
296 " failed! [path=%s, rv=0x%08x]", path.get(), rv)); |
|
297 return rv; |
|
298 } |
|
299 |
|
300 LOG(("CacheFileContextEvictor::RemoveEvictionInfoFromDisk() - Successfully " |
|
301 "removed file. [path=%s]", path.get())); |
|
302 |
|
303 return NS_OK; |
|
304 } |
|
305 |
|
306 nsresult |
|
307 CacheFileContextEvictor::LoadEvictInfoFromDisk() |
|
308 { |
|
309 LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() [this=%p]", this)); |
|
310 |
|
311 nsresult rv; |
|
312 |
|
313 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
314 |
|
315 sDiskAlreadySearched = true; |
|
316 |
|
317 nsCOMPtr<nsISimpleEnumerator> enumerator; |
|
318 rv = mCacheDirectory->GetDirectoryEntries(getter_AddRefs(enumerator)); |
|
319 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
320 return rv; |
|
321 } |
|
322 |
|
323 nsCOMPtr<nsIDirectoryEnumerator> dirEnum = do_QueryInterface(enumerator, &rv); |
|
324 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
325 return rv; |
|
326 } |
|
327 |
|
328 while (true) { |
|
329 nsCOMPtr<nsIFile> file; |
|
330 rv = dirEnum->GetNextFile(getter_AddRefs(file)); |
|
331 if (!file) { |
|
332 break; |
|
333 } |
|
334 |
|
335 bool isDir = false; |
|
336 file->IsDirectory(&isDir); |
|
337 if (isDir) { |
|
338 continue; |
|
339 } |
|
340 |
|
341 nsAutoCString leaf; |
|
342 rv = file->GetNativeLeafName(leaf); |
|
343 if (NS_FAILED(rv)) { |
|
344 LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() - " |
|
345 "GetNativeLeafName() failed! Skipping file.")); |
|
346 continue; |
|
347 } |
|
348 |
|
349 if (leaf.Length() < kContextEvictionPrefixLength) { |
|
350 continue; |
|
351 } |
|
352 |
|
353 if (!StringBeginsWith(leaf, NS_LITERAL_CSTRING(kContextEvictionPrefix))) { |
|
354 continue; |
|
355 } |
|
356 |
|
357 nsAutoCString encoded; |
|
358 encoded = Substring(leaf, kContextEvictionPrefixLength); |
|
359 encoded.ReplaceChar('-', '/'); |
|
360 |
|
361 nsAutoCString decoded; |
|
362 rv = Base64Decode(encoded, decoded); |
|
363 if (NS_FAILED(rv)) { |
|
364 LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() - Base64 decoding " |
|
365 "failed. Removing the file. [file=%s]", leaf.get())); |
|
366 file->Remove(false); |
|
367 continue; |
|
368 } |
|
369 |
|
370 nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(decoded); |
|
371 |
|
372 if (!info) { |
|
373 LOG(("CacheFileContextEvictor::LoadEvictInfoFromDisk() - Cannot parse " |
|
374 "context key, removing file. [contextKey=%s, file=%s]", |
|
375 decoded.get(), leaf.get())); |
|
376 file->Remove(false); |
|
377 continue; |
|
378 } |
|
379 |
|
380 PRTime lastModifiedTime; |
|
381 rv = file->GetLastModifiedTime(&lastModifiedTime); |
|
382 if (NS_FAILED(rv)) { |
|
383 continue; |
|
384 } |
|
385 |
|
386 CacheFileContextEvictorEntry *entry = new CacheFileContextEvictorEntry(); |
|
387 entry->mInfo = info; |
|
388 entry->mTimeStamp = lastModifiedTime; |
|
389 mEntries.AppendElement(entry); |
|
390 } |
|
391 |
|
392 return NS_OK; |
|
393 } |
|
394 |
|
395 nsresult |
|
396 CacheFileContextEvictor::GetContextFile(nsILoadContextInfo *aLoadContextInfo, |
|
397 nsIFile **_retval) |
|
398 { |
|
399 nsresult rv; |
|
400 |
|
401 nsAutoCString leafName; |
|
402 leafName.Assign(NS_LITERAL_CSTRING(kContextEvictionPrefix)); |
|
403 |
|
404 nsAutoCString keyPrefix; |
|
405 CacheFileUtils::AppendKeyPrefix(aLoadContextInfo, keyPrefix); |
|
406 |
|
407 // TODO: This hack is needed because current CacheFileUtils::ParseKey() can |
|
408 // parse only the whole key and not just the key prefix generated by |
|
409 // CacheFileUtils::CreateKeyPrefix(). This should be removed once bug #968593 |
|
410 // is fixed. |
|
411 keyPrefix.Append(":foo"); |
|
412 |
|
413 nsAutoCString data64; |
|
414 rv = Base64Encode(keyPrefix, data64); |
|
415 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
416 return rv; |
|
417 } |
|
418 |
|
419 // Replace '/' with '-' since '/' cannot be part of the filename. |
|
420 data64.ReplaceChar('/', '-'); |
|
421 |
|
422 leafName.Append(data64); |
|
423 |
|
424 nsCOMPtr<nsIFile> file; |
|
425 rv = mCacheDirectory->Clone(getter_AddRefs(file)); |
|
426 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
427 return rv; |
|
428 } |
|
429 |
|
430 rv = file->AppendNative(leafName); |
|
431 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
432 return rv; |
|
433 } |
|
434 |
|
435 file.swap(*_retval); |
|
436 return NS_OK; |
|
437 } |
|
438 |
|
439 void |
|
440 CacheFileContextEvictor::CreateIterators() |
|
441 { |
|
442 LOG(("CacheFileContextEvictor::CreateIterators() [this=%p]", this)); |
|
443 |
|
444 CloseIterators(); |
|
445 |
|
446 nsresult rv; |
|
447 |
|
448 for (uint32_t i = 0; i < mEntries.Length(); ) { |
|
449 rv = CacheIndex::GetIterator(mEntries[i]->mInfo, false, |
|
450 getter_AddRefs(mEntries[i]->mIterator)); |
|
451 if (NS_FAILED(rv)) { |
|
452 LOG(("CacheFileContextEvictor::CreateIterators() - Cannot get an iterator" |
|
453 ". [rv=0x%08x]", rv)); |
|
454 mEntries.RemoveElementAt(i); |
|
455 continue; |
|
456 } |
|
457 |
|
458 ++i; |
|
459 } |
|
460 } |
|
461 |
|
462 void |
|
463 CacheFileContextEvictor::CloseIterators() |
|
464 { |
|
465 LOG(("CacheFileContextEvictor::CloseIterators() [this=%p]", this)); |
|
466 |
|
467 for (uint32_t i = 0; i < mEntries.Length(); ++i) { |
|
468 if (mEntries[i]->mIterator) { |
|
469 mEntries[i]->mIterator->Close(); |
|
470 mEntries[i]->mIterator = nullptr; |
|
471 } |
|
472 } |
|
473 } |
|
474 |
|
475 void |
|
476 CacheFileContextEvictor::StartEvicting() |
|
477 { |
|
478 LOG(("CacheFileContextEvictor::StartEvicting() [this=%p]", this)); |
|
479 |
|
480 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
481 |
|
482 if (mEvicting) { |
|
483 LOG(("CacheFileContextEvictor::StartEvicting() - already evicintg.")); |
|
484 return; |
|
485 } |
|
486 |
|
487 if (mEntries.Length() == 0) { |
|
488 LOG(("CacheFileContextEvictor::StartEvicting() - no context to evict.")); |
|
489 return; |
|
490 } |
|
491 |
|
492 nsCOMPtr<nsIRunnable> ev; |
|
493 ev = NS_NewRunnableMethod(this, &CacheFileContextEvictor::EvictEntries); |
|
494 |
|
495 nsRefPtr<CacheIOThread> ioThread = CacheFileIOManager::IOThread(); |
|
496 |
|
497 nsresult rv = ioThread->Dispatch(ev, CacheIOThread::EVICT); |
|
498 if (NS_FAILED(rv)) { |
|
499 LOG(("CacheFileContextEvictor::StartEvicting() - Cannot dispatch event to " |
|
500 "IO thread. [rv=0x%08x]", rv)); |
|
501 } |
|
502 |
|
503 mEvicting = true; |
|
504 } |
|
505 |
|
506 nsresult |
|
507 CacheFileContextEvictor::EvictEntries() |
|
508 { |
|
509 LOG(("CacheFileContextEvictor::EvictEntries()")); |
|
510 |
|
511 nsresult rv; |
|
512 |
|
513 MOZ_ASSERT(CacheFileIOManager::IsOnIOThread()); |
|
514 |
|
515 mEvicting = false; |
|
516 |
|
517 if (!mIndexIsUpToDate) { |
|
518 LOG(("CacheFileContextEvictor::EvictEntries() - Stopping evicting due to " |
|
519 "outdated index.")); |
|
520 return NS_OK; |
|
521 } |
|
522 |
|
523 while (true) { |
|
524 if (CacheIOThread::YieldAndRerun()) { |
|
525 LOG(("CacheFileContextEvictor::EvictEntries() - Breaking loop for higher " |
|
526 "level events.")); |
|
527 mEvicting = true; |
|
528 return NS_OK; |
|
529 } |
|
530 |
|
531 if (mEntries.Length() == 0) { |
|
532 LOG(("CacheFileContextEvictor::EvictEntries() - Stopping evicting, there " |
|
533 "is no context to evict.")); |
|
534 return NS_OK; |
|
535 } |
|
536 |
|
537 SHA1Sum::Hash hash; |
|
538 rv = mEntries[0]->mIterator->GetNextHash(&hash); |
|
539 if (rv == NS_ERROR_NOT_AVAILABLE) { |
|
540 LOG(("CacheFileContextEvictor::EvictEntries() - No more entries left in " |
|
541 "iterator. [iterator=%p, info=%p]", mEntries[0]->mIterator.get(), |
|
542 mEntries[0]->mInfo.get())); |
|
543 RemoveEvictInfoFromDisk(mEntries[0]->mInfo); |
|
544 mEntries.RemoveElementAt(0); |
|
545 continue; |
|
546 } else if (NS_FAILED(rv)) { |
|
547 LOG(("CacheFileContextEvictor::EvictEntries() - Iterator failed to " |
|
548 "provide next hash (shutdown?), keeping eviction info on disk." |
|
549 " [iterator=%p, info=%p]", mEntries[0]->mIterator.get(), |
|
550 mEntries[0]->mInfo.get())); |
|
551 mEntries.RemoveElementAt(0); |
|
552 continue; |
|
553 } |
|
554 |
|
555 LOG(("CacheFileContextEvictor::EvictEntries() - Processing hash. " |
|
556 "[hash=%08x%08x%08x%08x%08x, iterator=%p, info=%p]", LOGSHA1(&hash), |
|
557 mEntries[0]->mIterator.get(), mEntries[0]->mInfo.get())); |
|
558 |
|
559 nsRefPtr<CacheFileHandle> handle; |
|
560 CacheFileIOManager::gInstance->mHandles.GetHandle(&hash, false, |
|
561 getter_AddRefs(handle)); |
|
562 if (handle) { |
|
563 // We doom any active handle in CacheFileIOManager::EvictByContext(), so |
|
564 // this must be a new one. Skip it. |
|
565 LOG(("CacheFileContextEvictor::EvictEntries() - Skipping entry since we " |
|
566 "found an active handle. [handle=%p]", handle.get())); |
|
567 continue; |
|
568 } |
|
569 |
|
570 nsAutoCString leafName; |
|
571 CacheFileIOManager::HashToStr(&hash, leafName); |
|
572 |
|
573 PRTime lastModifiedTime; |
|
574 nsCOMPtr<nsIFile> file; |
|
575 rv = mEntriesDir->Clone(getter_AddRefs(file)); |
|
576 if (NS_SUCCEEDED(rv)) { |
|
577 rv = file->AppendNative(leafName); |
|
578 } |
|
579 if (NS_SUCCEEDED(rv)) { |
|
580 rv = file->GetLastModifiedTime(&lastModifiedTime); |
|
581 } |
|
582 if (NS_FAILED(rv)) { |
|
583 LOG(("CacheFileContextEvictor::EvictEntries() - Cannot get last modified " |
|
584 "time, skipping entry.")); |
|
585 continue; |
|
586 } |
|
587 |
|
588 if (lastModifiedTime > mEntries[0]->mTimeStamp) { |
|
589 LOG(("CacheFileContextEvictor::EvictEntries() - Skipping newer entry. " |
|
590 "[mTimeStamp=%lld, lastModifiedTime=%lld]", mEntries[0]->mTimeStamp, |
|
591 lastModifiedTime)); |
|
592 continue; |
|
593 } |
|
594 |
|
595 LOG(("CacheFileContextEvictor::EvictEntries - Removing entry.")); |
|
596 file->Remove(false); |
|
597 CacheIndex::RemoveEntry(&hash); |
|
598 } |
|
599 |
|
600 NS_NOTREACHED("We should never get here"); |
|
601 return NS_OK; |
|
602 } |
|
603 |
|
604 } // net |
|
605 } // mozilla |