LCOV - code coverage report
Current view: top level - netwerk/cache2 - CacheFileContextEvictor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 42 319 13.2 %
Date: 2017-07-14 16:53:18 Functions: 6 17 35.3 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13