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