LCOV - code coverage report
Current view: top level - netwerk/cache - nsDiskCacheDevice.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 468 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 57 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include <limits.h>
       8             : 
       9             : #include "mozilla/DebugOnly.h"
      10             : 
      11             : #include "nsCache.h"
      12             : #include "nsIMemoryReporter.h"
      13             : 
      14             : // include files for ftruncate (or equivalent)
      15             : #if defined(XP_UNIX)
      16             : #include <unistd.h>
      17             : #elif defined(XP_WIN)
      18             : #include <windows.h>
      19             : #else
      20             : // XXX add necessary include file for ftruncate (or equivalent)
      21             : #endif
      22             : 
      23             : #include "prthread.h"
      24             : 
      25             : #include "private/pprio.h"
      26             : 
      27             : #include "nsDiskCacheDevice.h"
      28             : #include "nsDiskCacheEntry.h"
      29             : #include "nsDiskCacheMap.h"
      30             : #include "nsDiskCacheStreams.h"
      31             : 
      32             : #include "nsDiskCache.h"
      33             : 
      34             : #include "nsCacheService.h"
      35             : 
      36             : #include "nsDeleteDir.h"
      37             : 
      38             : #include "nsICacheVisitor.h"
      39             : #include "nsReadableUtils.h"
      40             : #include "nsIInputStream.h"
      41             : #include "nsIOutputStream.h"
      42             : #include "nsCRT.h"
      43             : #include "nsCOMArray.h"
      44             : #include "nsISimpleEnumerator.h"
      45             : 
      46             : #include "nsThreadUtils.h"
      47             : #include "mozilla/MemoryReporting.h"
      48             : #include "mozilla/Telemetry.h"
      49             : 
      50             : static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
      51             : using namespace mozilla;
      52             : 
      53           0 : class nsDiskCacheDeviceDeactivateEntryEvent : public Runnable {
      54             : public:
      55           0 :   nsDiskCacheDeviceDeactivateEntryEvent(nsDiskCacheDevice* device,
      56             :                                         nsCacheEntry* entry,
      57             :                                         nsDiskCacheBinding* binding)
      58           0 :     : mozilla::Runnable("nsDiskCacheDeviceDeactivateEntryEvent")
      59             :     , mCanceled(false)
      60             :     , mEntry(entry)
      61             :     , mDevice(device)
      62           0 :     , mBinding(binding)
      63             :   {
      64           0 :     }
      65             : 
      66           0 :     NS_IMETHOD Run() override
      67             :     {
      68           0 :         nsCacheServiceAutoLock lock;
      69           0 :         CACHE_LOG_DEBUG(("nsDiskCacheDeviceDeactivateEntryEvent[%p]\n", this));
      70           0 :         if (!mCanceled) {
      71           0 :             (void) mDevice->DeactivateEntry_Private(mEntry, mBinding);
      72             :         }
      73           0 :         return NS_OK;
      74             :     }
      75             : 
      76           0 :     void CancelEvent() { mCanceled = true; }
      77             : private:
      78             :     bool mCanceled;
      79             :     nsCacheEntry *mEntry;
      80             :     nsDiskCacheDevice *mDevice;
      81             :     nsDiskCacheBinding *mBinding;
      82             : };
      83             : 
      84           0 : class nsEvictDiskCacheEntriesEvent : public Runnable {
      85             : public:
      86           0 :   explicit nsEvictDiskCacheEntriesEvent(nsDiskCacheDevice* device)
      87           0 :     : mozilla::Runnable("nsEvictDiskCacheEntriesEvent")
      88           0 :     , mDevice(device)
      89             :   {
      90           0 :   }
      91             : 
      92           0 :   NS_IMETHOD Run() override
      93             :   {
      94           0 :     nsCacheServiceAutoLock lock;
      95           0 :     mDevice->EvictDiskCacheEntries(mDevice->mCacheCapacity);
      96           0 :     return NS_OK;
      97             :     }
      98             : 
      99             : private:
     100             :     nsDiskCacheDevice *mDevice;
     101             : };
     102             : 
     103             : /******************************************************************************
     104             :  *  nsDiskCacheEvictor
     105             :  *
     106             :  *  Helper class for nsDiskCacheDevice.
     107             :  *
     108             :  *****************************************************************************/
     109             : 
     110             : class nsDiskCacheEvictor : public nsDiskCacheRecordVisitor
     111             : {
     112             : public:
     113           0 :     nsDiskCacheEvictor( nsDiskCacheMap *      cacheMap,
     114             :                         nsDiskCacheBindery *  cacheBindery,
     115             :                         uint32_t              targetSize,
     116             :                         const char *          clientID)
     117           0 :         : mCacheMap(cacheMap)
     118             :         , mBindery(cacheBindery)
     119             :         , mTargetSize(targetSize)
     120           0 :         , mClientID(clientID)
     121             :     {
     122           0 :         mClientIDSize = clientID ? strlen(clientID) : 0;
     123           0 :     }
     124             : 
     125             :     virtual int32_t  VisitRecord(nsDiskCacheRecord *  mapRecord);
     126             : 
     127             : private:
     128             :         nsDiskCacheMap *     mCacheMap;
     129             :         nsDiskCacheBindery * mBindery;
     130             :         uint32_t             mTargetSize;
     131             :         const char *         mClientID;
     132             :         uint32_t             mClientIDSize;
     133             : };
     134             : 
     135             : 
     136             : int32_t
     137           0 : nsDiskCacheEvictor::VisitRecord(nsDiskCacheRecord *  mapRecord)
     138             : {
     139           0 :     if (mCacheMap->TotalSize() < mTargetSize)
     140           0 :         return kStopVisitingRecords;
     141             : 
     142           0 :     if (mClientID) {
     143             :         // we're just evicting records for a specific client
     144           0 :         nsDiskCacheEntry * diskEntry = mCacheMap->ReadDiskCacheEntry(mapRecord);
     145           0 :         if (!diskEntry)
     146           0 :             return kVisitNextRecord;  // XXX or delete record?
     147             : 
     148             :         // Compare clientID's without malloc
     149           0 :         if ((diskEntry->mKeySize <= mClientIDSize) ||
     150           0 :             (diskEntry->Key()[mClientIDSize] != ':') ||
     151           0 :             (memcmp(diskEntry->Key(), mClientID, mClientIDSize) != 0)) {
     152           0 :             return kVisitNextRecord;  // clientID doesn't match, skip it
     153             :         }
     154             :     }
     155             : 
     156           0 :     nsDiskCacheBinding * binding = mBindery->FindActiveBinding(mapRecord->HashNumber());
     157           0 :     if (binding) {
     158             :         // If the entry is pending deactivation, cancel deactivation and doom
     159             :         // the entry
     160           0 :         if (binding->mDeactivateEvent) {
     161           0 :             binding->mDeactivateEvent->CancelEvent();
     162           0 :             binding->mDeactivateEvent = nullptr;
     163             :         }
     164             :         // We are currently using this entry, so all we can do is doom it.
     165             :         // Since we're enumerating the records, we don't want to call
     166             :         // DeleteRecord when nsCacheService::DoomEntry() calls us back.
     167           0 :         binding->mDoomed = true;         // mark binding record as 'deleted'
     168           0 :         nsCacheService::DoomEntry(binding->mCacheEntry);
     169             :     } else {
     170             :         // entry not in use, just delete storage because we're enumerating the records
     171           0 :         (void) mCacheMap->DeleteStorage(mapRecord);
     172             :     }
     173             : 
     174           0 :     return kDeleteRecordAndContinue;  // this will REALLY delete the record
     175             : }
     176             : 
     177             : 
     178             : /******************************************************************************
     179             :  *  nsDiskCacheDeviceInfo
     180             :  *****************************************************************************/
     181             : 
     182             : class nsDiskCacheDeviceInfo : public nsICacheDeviceInfo {
     183             : public:
     184             :     NS_DECL_ISUPPORTS
     185             :     NS_DECL_NSICACHEDEVICEINFO
     186             : 
     187           0 :     explicit nsDiskCacheDeviceInfo(nsDiskCacheDevice* device)
     188           0 :         :   mDevice(device)
     189             :     {
     190           0 :     }
     191             : 
     192             : private:
     193           0 :     virtual ~nsDiskCacheDeviceInfo() {}
     194             : 
     195             :     nsDiskCacheDevice* mDevice;
     196             : };
     197             : 
     198           0 : NS_IMPL_ISUPPORTS(nsDiskCacheDeviceInfo, nsICacheDeviceInfo)
     199             : 
     200           0 : NS_IMETHODIMP nsDiskCacheDeviceInfo::GetDescription(char ** aDescription)
     201             : {
     202           0 :     NS_ENSURE_ARG_POINTER(aDescription);
     203           0 :     *aDescription = NS_strdup("Disk cache device");
     204           0 :     return *aDescription ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     205             : }
     206             : 
     207           0 : NS_IMETHODIMP nsDiskCacheDeviceInfo::GetUsageReport(char ** usageReport)
     208             : {
     209           0 :     NS_ENSURE_ARG_POINTER(usageReport);
     210           0 :     nsCString buffer;
     211             : 
     212             :     buffer.AssignLiteral("  <tr>\n"
     213             :                          "    <th>Cache Directory:</th>\n"
     214           0 :                          "    <td>");
     215           0 :     nsCOMPtr<nsIFile> cacheDir;
     216           0 :     nsAutoString path;
     217           0 :     mDevice->getCacheDirectory(getter_AddRefs(cacheDir));
     218           0 :     nsresult rv = cacheDir->GetPath(path);
     219           0 :     if (NS_SUCCEEDED(rv)) {
     220           0 :         AppendUTF16toUTF8(path, buffer);
     221             :     } else {
     222           0 :         buffer.AppendLiteral("directory unavailable");
     223             :     }
     224             :     buffer.AppendLiteral("</td>\n"
     225           0 :                          "  </tr>\n");
     226             : 
     227           0 :     *usageReport = ToNewCString(buffer);
     228           0 :     if (!*usageReport) return NS_ERROR_OUT_OF_MEMORY;
     229             : 
     230           0 :     return NS_OK;
     231             : }
     232             : 
     233           0 : NS_IMETHODIMP nsDiskCacheDeviceInfo::GetEntryCount(uint32_t *aEntryCount)
     234             : {
     235           0 :     NS_ENSURE_ARG_POINTER(aEntryCount);
     236           0 :     *aEntryCount = mDevice->getEntryCount();
     237           0 :     return NS_OK;
     238             : }
     239             : 
     240           0 : NS_IMETHODIMP nsDiskCacheDeviceInfo::GetTotalSize(uint32_t *aTotalSize)
     241             : {
     242           0 :     NS_ENSURE_ARG_POINTER(aTotalSize);
     243             :     // Returned unit's are in bytes
     244           0 :     *aTotalSize = mDevice->getCacheSize() * 1024;
     245           0 :     return NS_OK;
     246             : }
     247             : 
     248           0 : NS_IMETHODIMP nsDiskCacheDeviceInfo::GetMaximumSize(uint32_t *aMaximumSize)
     249             : {
     250           0 :     NS_ENSURE_ARG_POINTER(aMaximumSize);
     251             :     // Returned unit's are in bytes
     252           0 :     *aMaximumSize = mDevice->getCacheCapacity() * 1024;
     253           0 :     return NS_OK;
     254             : }
     255             : 
     256             : 
     257             : /******************************************************************************
     258             :  *  nsDiskCache
     259             :  *****************************************************************************/
     260             : 
     261             : /**
     262             :  *  nsDiskCache::Hash(const char * key, PLDHashNumber initval)
     263             :  *
     264             :  *  See http://burtleburtle.net/bob/hash/evahash.html for more information
     265             :  *  about this hash function.
     266             :  *
     267             :  *  This algorithm of this method implies nsDiskCacheRecords will be stored
     268             :  *  in a certain order on disk.  If the algorithm changes, existing cache
     269             :  *  map files may become invalid, and therefore the kCurrentVersion needs
     270             :  *  to be revised.
     271             :  */
     272             : 
     273           0 : static inline void hashmix(uint32_t& a, uint32_t& b, uint32_t& c)
     274             : {
     275           0 :   a -= b; a -= c; a ^= (c>>13);
     276           0 :   b -= c; b -= a; b ^= (a<<8);
     277           0 :   c -= a; c -= b; c ^= (b>>13);
     278           0 :   a -= b; a -= c; a ^= (c>>12);
     279           0 :   b -= c; b -= a; b ^= (a<<16);
     280           0 :   c -= a; c -= b; c ^= (b>>5);
     281           0 :   a -= b; a -= c; a ^= (c>>3);
     282           0 :   b -= c; b -= a; b ^= (a<<10);
     283           0 :   c -= a; c -= b; c ^= (b>>15);
     284           0 : }
     285             : 
     286             : PLDHashNumber
     287           0 : nsDiskCache::Hash(const char * key, PLDHashNumber initval)
     288             : {
     289           0 :   const uint8_t *k = reinterpret_cast<const uint8_t*>(key);
     290             :   uint32_t a, b, c, len, length;
     291             : 
     292           0 :   length = strlen(key);
     293             :   /* Set up the internal state */
     294           0 :   len = length;
     295           0 :   a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
     296           0 :   c = initval;         /* variable initialization of internal state */
     297             : 
     298             :   /*---------------------------------------- handle most of the key */
     299           0 :   while (len >= 12)
     300             :   {
     301           0 :     a += k[0] + (uint32_t(k[1])<<8) + (uint32_t(k[2])<<16) + (uint32_t(k[3])<<24);
     302           0 :     b += k[4] + (uint32_t(k[5])<<8) + (uint32_t(k[6])<<16) + (uint32_t(k[7])<<24);
     303           0 :     c += k[8] + (uint32_t(k[9])<<8) + (uint32_t(k[10])<<16) + (uint32_t(k[11])<<24);
     304           0 :     hashmix(a, b, c);
     305           0 :     k += 12; len -= 12;
     306             :   }
     307             : 
     308             :   /*------------------------------------- handle the last 11 bytes */
     309           0 :   c += length;
     310           0 :   switch(len) {              /* all the case statements fall through */
     311           0 :     case 11: c += (uint32_t(k[10])<<24);  MOZ_FALLTHROUGH;
     312           0 :     case 10: c += (uint32_t(k[9])<<16);   MOZ_FALLTHROUGH;
     313           0 :     case 9 : c += (uint32_t(k[8])<<8);    MOZ_FALLTHROUGH;
     314             :     /* the low-order byte of c is reserved for the length */
     315           0 :     case 8 : b += (uint32_t(k[7])<<24);   MOZ_FALLTHROUGH;
     316           0 :     case 7 : b += (uint32_t(k[6])<<16);   MOZ_FALLTHROUGH;
     317           0 :     case 6 : b += (uint32_t(k[5])<<8);    MOZ_FALLTHROUGH;
     318           0 :     case 5 : b += k[4];                   MOZ_FALLTHROUGH;
     319           0 :     case 4 : a += (uint32_t(k[3])<<24);   MOZ_FALLTHROUGH;
     320           0 :     case 3 : a += (uint32_t(k[2])<<16);   MOZ_FALLTHROUGH;
     321           0 :     case 2 : a += (uint32_t(k[1])<<8);    MOZ_FALLTHROUGH;
     322           0 :     case 1 : a += k[0];
     323             :     /* case 0: nothing left to add */
     324             :   }
     325           0 :   hashmix(a, b, c);
     326             : 
     327           0 :   return c;
     328             : }
     329             : 
     330             : nsresult
     331           0 : nsDiskCache::Truncate(PRFileDesc *  fd, uint32_t  newEOF)
     332             : {
     333             :     // use modified SetEOF from nsFileStreams::SetEOF()
     334             : 
     335             : #if defined(XP_UNIX)
     336           0 :     if (ftruncate(PR_FileDesc2NativeHandle(fd), newEOF) != 0) {
     337           0 :         NS_ERROR("ftruncate failed");
     338           0 :         return NS_ERROR_FAILURE;
     339             :     }
     340             : 
     341             : #elif defined(XP_WIN)
     342             :     int32_t cnt = PR_Seek(fd, newEOF, PR_SEEK_SET);
     343             :     if (cnt == -1)  return NS_ERROR_FAILURE;
     344             :     if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(fd))) {
     345             :         NS_ERROR("SetEndOfFile failed");
     346             :         return NS_ERROR_FAILURE;
     347             :     }
     348             : 
     349             : #else
     350             :     // add implementations for other platforms here
     351             : #endif
     352           0 :     return NS_OK;
     353             : }
     354             : 
     355             : 
     356             : /******************************************************************************
     357             :  *  nsDiskCacheDevice
     358             :  *****************************************************************************/
     359             : 
     360           0 : nsDiskCacheDevice::nsDiskCacheDevice()
     361             :     : mCacheCapacity(0)
     362             :     , mMaxEntrySize(-1) // -1 means "no limit"
     363             :     , mInitialized(false)
     364           0 :     , mClearingDiskCache(false)
     365             : {
     366           0 : }
     367             : 
     368           0 : nsDiskCacheDevice::~nsDiskCacheDevice()
     369             : {
     370           0 :     Shutdown();
     371           0 : }
     372             : 
     373             : 
     374             : /**
     375             :  *  methods of nsCacheDevice
     376             :  */
     377             : nsresult
     378           0 : nsDiskCacheDevice::Init()
     379             : {
     380             :     nsresult rv;
     381             : 
     382           0 :     if (Initialized()) {
     383           0 :         NS_ERROR("Disk cache already initialized!");
     384           0 :         return NS_ERROR_UNEXPECTED;
     385             :     }
     386             : 
     387           0 :     if (!mCacheDirectory)
     388           0 :         return NS_ERROR_FAILURE;
     389             : 
     390           0 :     mBindery.Init();
     391             : 
     392             :     // Open Disk Cache
     393           0 :     rv = OpenDiskCache();
     394           0 :     if (NS_FAILED(rv)) {
     395           0 :         (void) mCacheMap.Close(false);
     396           0 :         return rv;
     397             :     }
     398             : 
     399           0 :     mInitialized = true;
     400           0 :     return NS_OK;
     401             : }
     402             : 
     403             : 
     404             : /**
     405             :  *  NOTE: called while holding the cache service lock
     406             :  */
     407             : nsresult
     408           0 : nsDiskCacheDevice::Shutdown()
     409             : {
     410           0 :     nsCacheService::AssertOwnsLock();
     411             : 
     412           0 :     nsresult rv = Shutdown_Private(true);
     413           0 :     if (NS_FAILED(rv))
     414           0 :         return rv;
     415             : 
     416           0 :     return NS_OK;
     417             : }
     418             : 
     419             : 
     420             : nsresult
     421           0 : nsDiskCacheDevice::Shutdown_Private(bool    flush)
     422             : {
     423           0 :     CACHE_LOG_DEBUG(("CACHE: disk Shutdown_Private [%u]\n", flush));
     424             : 
     425           0 :     if (Initialized()) {
     426             :         // check cache limits in case we need to evict.
     427           0 :         EvictDiskCacheEntries(mCacheCapacity);
     428             : 
     429             :         // At this point there may be a number of pending cache-requests on the
     430             :         // cache-io thread. Wait for all these to run before we wipe out our
     431             :         // datastructures (see bug #620660)
     432           0 :         (void) nsCacheService::SyncWithCacheIOThread();
     433             : 
     434             :         // write out persistent information about the cache.
     435           0 :         (void) mCacheMap.Close(flush);
     436             : 
     437           0 :         mBindery.Reset();
     438             : 
     439           0 :         mInitialized = false;
     440             :     }
     441             : 
     442           0 :     return NS_OK;
     443             : }
     444             : 
     445             : 
     446             : const char *
     447           0 : nsDiskCacheDevice::GetDeviceID()
     448             : {
     449           0 :     return DISK_CACHE_DEVICE_ID;
     450             : }
     451             : 
     452             : /**
     453             :  *  FindEntry -
     454             :  *
     455             :  *      cases:  key not in disk cache, hash number free
     456             :  *              key not in disk cache, hash number used
     457             :  *              key in disk cache
     458             :  *
     459             :  *  NOTE: called while holding the cache service lock
     460             :  */
     461             : nsCacheEntry *
     462           0 : nsDiskCacheDevice::FindEntry(nsCString * key, bool *collision)
     463             : {
     464           0 :     Telemetry::AutoTimer<Telemetry::CACHE_DISK_SEARCH_2> timer;
     465           0 :     if (!Initialized())  return nullptr;  // NS_ERROR_NOT_INITIALIZED
     466           0 :     if (mClearingDiskCache)  return nullptr;
     467           0 :     nsDiskCacheRecord       record;
     468           0 :     nsDiskCacheBinding *    binding = nullptr;
     469           0 :     PLDHashNumber           hashNumber = nsDiskCache::Hash(key->get());
     470             : 
     471           0 :     *collision = false;
     472             : 
     473           0 :     binding = mBindery.FindActiveBinding(hashNumber);
     474           0 :     if (binding && !binding->mCacheEntry->Key()->Equals(*key)) {
     475           0 :         *collision = true;
     476           0 :         return nullptr;
     477           0 :     } else if (binding && binding->mDeactivateEvent) {
     478           0 :         binding->mDeactivateEvent->CancelEvent();
     479           0 :         binding->mDeactivateEvent = nullptr;
     480           0 :         CACHE_LOG_DEBUG(("CACHE: reusing deactivated entry %p " \
     481             :                          "req-key=%s  entry-key=%s\n",
     482             :                          binding->mCacheEntry, key->get(),
     483             :                          binding->mCacheEntry->Key()->get()));
     484             : 
     485           0 :         return binding->mCacheEntry; // just return this one, observing that
     486             :                                      // FindActiveBinding() does not return
     487             :                                      // bindings to doomed entries
     488             :     }
     489           0 :     binding = nullptr;
     490             : 
     491             :     // lookup hash number in cache map
     492           0 :     nsresult rv = mCacheMap.FindRecord(hashNumber, &record);
     493           0 :     if (NS_FAILED(rv))  return nullptr;  // XXX log error?
     494             : 
     495           0 :     nsDiskCacheEntry * diskEntry = mCacheMap.ReadDiskCacheEntry(&record);
     496           0 :     if (!diskEntry) return nullptr;
     497             : 
     498             :     // compare key to be sure
     499           0 :     if (!key->Equals(diskEntry->Key())) {
     500           0 :         *collision = true;
     501           0 :         return nullptr;
     502             :     }
     503             : 
     504           0 :     nsCacheEntry * entry = diskEntry->CreateCacheEntry(this);
     505           0 :     if (entry) {
     506           0 :         binding = mBindery.CreateBinding(entry, &record);
     507           0 :         if (!binding) {
     508           0 :             delete entry;
     509           0 :             entry = nullptr;
     510             :         }
     511             :     }
     512             : 
     513           0 :     if (!entry) {
     514           0 :       (void) mCacheMap.DeleteStorage(&record);
     515           0 :       (void) mCacheMap.DeleteRecord(&record);
     516             :     }
     517             : 
     518           0 :     return entry;
     519             : }
     520             : 
     521             : 
     522             : /**
     523             :  *  NOTE: called while holding the cache service lock
     524             :  */
     525             : nsresult
     526           0 : nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry)
     527             : {
     528           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     529           0 :     if (!IsValidBinding(binding))
     530           0 :         return NS_ERROR_UNEXPECTED;
     531             : 
     532           0 :     CACHE_LOG_DEBUG(("CACHE: disk DeactivateEntry [%p %x]\n",
     533             :         entry, binding->mRecord.HashNumber()));
     534             : 
     535             :     nsDiskCacheDeviceDeactivateEntryEvent *event =
     536           0 :         new nsDiskCacheDeviceDeactivateEntryEvent(this, entry, binding);
     537             : 
     538             :     // ensure we can cancel the event via the binding later if necessary
     539           0 :     binding->mDeactivateEvent = event;
     540             : 
     541           0 :     DebugOnly<nsresult> rv = nsCacheService::DispatchToCacheIOThread(event);
     542           0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "DeactivateEntry: Failed dispatching "
     543             :                                    "deactivation event");
     544           0 :     return NS_OK;
     545             : }
     546             : 
     547             : /**
     548             :  *  NOTE: called while holding the cache service lock
     549             :  */
     550             : nsresult
     551           0 : nsDiskCacheDevice::DeactivateEntry_Private(nsCacheEntry * entry,
     552             :                                            nsDiskCacheBinding * binding)
     553             : {
     554           0 :     nsresult rv = NS_OK;
     555           0 :     if (entry->IsDoomed()) {
     556             :         // delete data, entry, record from disk for entry
     557           0 :         rv = mCacheMap.DeleteStorage(&binding->mRecord);
     558             : 
     559             :     } else {
     560             :         // save stuff to disk for entry
     561           0 :         rv = mCacheMap.WriteDiskCacheEntry(binding);
     562           0 :         if (NS_FAILED(rv)) {
     563             :             // clean up as best we can
     564           0 :             (void) mCacheMap.DeleteStorage(&binding->mRecord);
     565           0 :             (void) mCacheMap.DeleteRecord(&binding->mRecord);
     566           0 :             binding->mDoomed = true; // record is no longer in cache map
     567             :         }
     568             :     }
     569             : 
     570           0 :     mBindery.RemoveBinding(binding); // extract binding from collision detection stuff
     571           0 :     delete entry;   // which will release binding
     572           0 :     return rv;
     573             : }
     574             : 
     575             : 
     576             : /**
     577             :  * BindEntry()
     578             :  *      no hash number collision -> no problem
     579             :  *      collision
     580             :  *          record not active -> evict, no problem
     581             :  *          record is active
     582             :  *              record is already doomed -> record shouldn't have been in map, no problem
     583             :  *              record is not doomed -> doom, and replace record in map
     584             :  *
     585             :  *              walk matching hashnumber list to find lowest generation number
     586             :  *              take generation number from other (data/meta) location,
     587             :  *                  or walk active list
     588             :  *
     589             :  *  NOTE: called while holding the cache service lock
     590             :  */
     591             : nsresult
     592           0 : nsDiskCacheDevice::BindEntry(nsCacheEntry * entry)
     593             : {
     594           0 :     if (!Initialized())  return  NS_ERROR_NOT_INITIALIZED;
     595           0 :     if (mClearingDiskCache)  return NS_ERROR_NOT_AVAILABLE;
     596           0 :     nsresult rv = NS_OK;
     597           0 :     nsDiskCacheRecord record, oldRecord;
     598             :     nsDiskCacheBinding *binding;
     599           0 :     PLDHashNumber hashNumber = nsDiskCache::Hash(entry->Key()->get());
     600             : 
     601             :     // Find out if there is already an active binding for this hash. If yes it
     602             :     // should have another key since BindEntry() shouldn't be called twice for
     603             :     // the same entry. Doom the old entry, the new one will get another
     604             :     // generation number so files won't collide.
     605           0 :     binding = mBindery.FindActiveBinding(hashNumber);
     606           0 :     if (binding) {
     607           0 :         NS_ASSERTION(!binding->mCacheEntry->Key()->Equals(*entry->Key()),
     608             :                      "BindEntry called for already bound entry!");
     609             :         // If the entry is pending deactivation, cancel deactivation
     610           0 :         if (binding->mDeactivateEvent) {
     611           0 :             binding->mDeactivateEvent->CancelEvent();
     612           0 :             binding->mDeactivateEvent = nullptr;
     613             :         }
     614           0 :         nsCacheService::DoomEntry(binding->mCacheEntry);
     615           0 :         binding = nullptr;
     616             :     }
     617             : 
     618             :     // Lookup hash number in cache map. There can be a colliding inactive entry.
     619             :     // See bug #321361 comment 21 for the scenario. If there is such entry,
     620             :     // delete it.
     621           0 :     rv = mCacheMap.FindRecord(hashNumber, &record);
     622           0 :     if (NS_SUCCEEDED(rv)) {
     623           0 :         nsDiskCacheEntry * diskEntry = mCacheMap.ReadDiskCacheEntry(&record);
     624           0 :         if (diskEntry) {
     625             :             // compare key to be sure
     626           0 :             if (!entry->Key()->Equals(diskEntry->Key())) {
     627           0 :                 mCacheMap.DeleteStorage(&record);
     628           0 :                 rv = mCacheMap.DeleteRecord(&record);
     629           0 :                 if (NS_FAILED(rv))  return rv;
     630             :             }
     631             :         }
     632           0 :         record = nsDiskCacheRecord();
     633             :     }
     634             : 
     635             :     // create a new record for this entry
     636           0 :     record.SetHashNumber(nsDiskCache::Hash(entry->Key()->get()));
     637           0 :     record.SetEvictionRank(ULONG_MAX - SecondsFromPRTime(PR_Now()));
     638             : 
     639           0 :     CACHE_LOG_DEBUG(("CACHE: disk BindEntry [%p %x]\n",
     640             :         entry, record.HashNumber()));
     641             : 
     642           0 :     if (!entry->IsDoomed()) {
     643             :         // if entry isn't doomed, add it to the cache map
     644           0 :         rv = mCacheMap.AddRecord(&record, &oldRecord); // deletes old record, if any
     645           0 :         if (NS_FAILED(rv))  return rv;
     646             : 
     647           0 :         uint32_t    oldHashNumber = oldRecord.HashNumber();
     648           0 :         if (oldHashNumber) {
     649             :             // gotta evict this one first
     650           0 :             nsDiskCacheBinding * oldBinding = mBindery.FindActiveBinding(oldHashNumber);
     651           0 :             if (oldBinding) {
     652             :                 // XXX if debug : compare keys for hashNumber collision
     653             : 
     654           0 :                 if (!oldBinding->mCacheEntry->IsDoomed()) {
     655             :                     // If the old entry is pending deactivation, cancel deactivation
     656           0 :                     if (oldBinding->mDeactivateEvent) {
     657           0 :                         oldBinding->mDeactivateEvent->CancelEvent();
     658           0 :                         oldBinding->mDeactivateEvent = nullptr;
     659             :                     }
     660             :                 // we've got a live one!
     661           0 :                     nsCacheService::DoomEntry(oldBinding->mCacheEntry);
     662             :                     // storage will be delete when oldBinding->mCacheEntry is Deactivated
     663             :                 }
     664             :             } else {
     665             :                 // delete storage
     666             :                 // XXX if debug : compare keys for hashNumber collision
     667           0 :                 rv = mCacheMap.DeleteStorage(&oldRecord);
     668           0 :                 if (NS_FAILED(rv))  return rv;  // XXX delete record we just added?
     669             :             }
     670             :         }
     671             :     }
     672             : 
     673             :     // Make sure this entry has its associated nsDiskCacheBinding attached.
     674           0 :     binding = mBindery.CreateBinding(entry, &record);
     675           0 :     NS_ASSERTION(binding, "nsDiskCacheDevice::BindEntry");
     676           0 :     if (!binding) return NS_ERROR_OUT_OF_MEMORY;
     677           0 :     NS_ASSERTION(binding->mRecord.ValidRecord(), "bad cache map record");
     678             : 
     679           0 :     return NS_OK;
     680             : }
     681             : 
     682             : 
     683             : /**
     684             :  *  NOTE: called while holding the cache service lock
     685             :  */
     686             : void
     687           0 : nsDiskCacheDevice::DoomEntry(nsCacheEntry * entry)
     688             : {
     689           0 :     CACHE_LOG_DEBUG(("CACHE: disk DoomEntry [%p]\n", entry));
     690             : 
     691           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     692           0 :     NS_ASSERTION(binding, "DoomEntry: binding == nullptr");
     693           0 :     if (!binding)
     694           0 :         return;
     695             : 
     696           0 :     if (!binding->mDoomed) {
     697             :         // so it can't be seen by FindEntry() ever again.
     698             : #ifdef DEBUG
     699             :         nsresult rv =
     700             : #endif
     701           0 :             mCacheMap.DeleteRecord(&binding->mRecord);
     702           0 :         NS_ASSERTION(NS_SUCCEEDED(rv),"DeleteRecord failed.");
     703           0 :         binding->mDoomed = true; // record in no longer in cache map
     704             :     }
     705             : }
     706             : 
     707             : 
     708             : /**
     709             :  *  NOTE: called while holding the cache service lock
     710             :  */
     711             : nsresult
     712           0 : nsDiskCacheDevice::OpenInputStreamForEntry(nsCacheEntry *      entry,
     713             :                                            nsCacheAccessMode   mode,
     714             :                                            uint32_t            offset,
     715             :                                            nsIInputStream **   result)
     716             : {
     717           0 :     CACHE_LOG_DEBUG(("CACHE: disk OpenInputStreamForEntry [%p %x %u]\n",
     718             :         entry, mode, offset));
     719             : 
     720           0 :     NS_ENSURE_ARG_POINTER(entry);
     721           0 :     NS_ENSURE_ARG_POINTER(result);
     722             : 
     723             :     nsresult             rv;
     724           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     725           0 :     if (!IsValidBinding(binding))
     726           0 :         return NS_ERROR_UNEXPECTED;
     727             : 
     728           0 :     NS_ASSERTION(binding->mCacheEntry == entry, "binding & entry don't point to each other");
     729             : 
     730           0 :     rv = binding->EnsureStreamIO();
     731           0 :     if (NS_FAILED(rv)) return rv;
     732             : 
     733           0 :     return binding->mStreamIO->GetInputStream(offset, result);
     734             : }
     735             : 
     736             : 
     737             : /**
     738             :  *  NOTE: called while holding the cache service lock
     739             :  */
     740             : nsresult
     741           0 : nsDiskCacheDevice::OpenOutputStreamForEntry(nsCacheEntry *      entry,
     742             :                                             nsCacheAccessMode   mode,
     743             :                                             uint32_t            offset,
     744             :                                             nsIOutputStream **  result)
     745             : {
     746           0 :     CACHE_LOG_DEBUG(("CACHE: disk OpenOutputStreamForEntry [%p %x %u]\n",
     747             :         entry, mode, offset));
     748             : 
     749           0 :     NS_ENSURE_ARG_POINTER(entry);
     750           0 :     NS_ENSURE_ARG_POINTER(result);
     751             : 
     752             :     nsresult             rv;
     753           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     754           0 :     if (!IsValidBinding(binding))
     755           0 :         return NS_ERROR_UNEXPECTED;
     756             : 
     757           0 :     NS_ASSERTION(binding->mCacheEntry == entry, "binding & entry don't point to each other");
     758             : 
     759           0 :     rv = binding->EnsureStreamIO();
     760           0 :     if (NS_FAILED(rv)) return rv;
     761             : 
     762           0 :     return binding->mStreamIO->GetOutputStream(offset, result);
     763             : }
     764             : 
     765             : 
     766             : /**
     767             :  *  NOTE: called while holding the cache service lock
     768             :  */
     769             : nsresult
     770           0 : nsDiskCacheDevice::GetFileForEntry(nsCacheEntry *    entry,
     771             :                                    nsIFile **        result)
     772             : {
     773           0 :     NS_ENSURE_ARG_POINTER(result);
     774           0 :     *result = nullptr;
     775             : 
     776             :     nsresult             rv;
     777             : 
     778           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     779           0 :     if (!IsValidBinding(binding))
     780           0 :         return NS_ERROR_UNEXPECTED;
     781             : 
     782             :     // check/set binding->mRecord for separate file, sync w/mCacheMap
     783           0 :     if (binding->mRecord.DataLocationInitialized()) {
     784           0 :         if (binding->mRecord.DataFile() != 0)
     785           0 :             return NS_ERROR_NOT_AVAILABLE;  // data not stored as separate file
     786             : 
     787           0 :         NS_ASSERTION(binding->mRecord.DataFileGeneration() == binding->mGeneration, "error generations out of sync");
     788             :     } else {
     789           0 :         binding->mRecord.SetDataFileGeneration(binding->mGeneration);
     790           0 :         binding->mRecord.SetDataFileSize(0);    // 1k minimum
     791           0 :         if (!binding->mDoomed) {
     792             :             // record stored in cache map, so update it
     793           0 :             rv = mCacheMap.UpdateRecord(&binding->mRecord);
     794           0 :             if (NS_FAILED(rv))  return rv;
     795             :         }
     796             :     }
     797             : 
     798           0 :     nsCOMPtr<nsIFile>  file;
     799           0 :     rv = mCacheMap.GetFileForDiskCacheRecord(&binding->mRecord,
     800             :                                              nsDiskCache::kData,
     801             :                                              false,
     802           0 :                                              getter_AddRefs(file));
     803           0 :     if (NS_FAILED(rv))  return rv;
     804             : 
     805           0 :     NS_IF_ADDREF(*result = file);
     806           0 :     return NS_OK;
     807             : }
     808             : 
     809             : 
     810             : /**
     811             :  *  This routine will get called every time an open descriptor is written to.
     812             :  *
     813             :  *  NOTE: called while holding the cache service lock
     814             :  */
     815             : nsresult
     816           0 : nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, int32_t deltaSize)
     817             : {
     818           0 :     CACHE_LOG_DEBUG(("CACHE: disk OnDataSizeChange [%p %d]\n",
     819             :         entry, deltaSize));
     820             : 
     821             :     // If passed a negative value, then there's nothing to do.
     822           0 :     if (deltaSize < 0)
     823           0 :         return NS_OK;
     824             : 
     825           0 :     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     826           0 :     if (!IsValidBinding(binding))
     827           0 :         return NS_ERROR_UNEXPECTED;
     828             : 
     829           0 :     NS_ASSERTION(binding->mRecord.ValidRecord(), "bad record");
     830             : 
     831           0 :     uint32_t  newSize = entry->DataSize() + deltaSize;
     832           0 :     uint32_t  newSizeK =  ((newSize + 0x3FF) >> 10);
     833             : 
     834             :     // If the new size is larger than max. file size or larger than
     835             :     // 1/8 the cache capacity (which is in KiB's), doom the entry and abort.
     836           0 :     if (EntryIsTooBig(newSize)) {
     837             : #ifdef DEBUG
     838             :         nsresult rv =
     839             : #endif
     840           0 :             nsCacheService::DoomEntry(entry);
     841           0 :         NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed.");
     842           0 :         return NS_ERROR_ABORT;
     843             :     }
     844             : 
     845           0 :     uint32_t  sizeK = ((entry->DataSize() + 0x03FF) >> 10); // round up to next 1k
     846             : 
     847             :     // In total count we ignore anything over kMaxDataSizeK (bug #651100), so
     848             :     // the target capacity should be calculated the same way.
     849           0 :     if (sizeK > kMaxDataSizeK) sizeK = kMaxDataSizeK;
     850           0 :     if (newSizeK > kMaxDataSizeK) newSizeK = kMaxDataSizeK;
     851             : 
     852             :     // pre-evict entries to make space for new data
     853           0 :     uint32_t  targetCapacity = mCacheCapacity > (newSizeK - sizeK)
     854           0 :                              ? mCacheCapacity - (newSizeK - sizeK)
     855           0 :                              : 0;
     856           0 :     EvictDiskCacheEntries(targetCapacity);
     857             : 
     858           0 :     return NS_OK;
     859             : }
     860             : 
     861             : 
     862             : /******************************************************************************
     863             :  *  EntryInfoVisitor
     864             :  *****************************************************************************/
     865             : class EntryInfoVisitor : public nsDiskCacheRecordVisitor
     866             : {
     867             : public:
     868           0 :     EntryInfoVisitor(nsDiskCacheMap *    cacheMap,
     869             :                      nsICacheVisitor *   visitor)
     870           0 :         : mCacheMap(cacheMap)
     871           0 :         , mVisitor(visitor)
     872           0 :     {}
     873             : 
     874           0 :     virtual int32_t  VisitRecord(nsDiskCacheRecord *  mapRecord)
     875             :     {
     876             :         // XXX optimization: do we have this record in memory?
     877             : 
     878             :         // read in the entry (metadata)
     879           0 :         nsDiskCacheEntry * diskEntry = mCacheMap->ReadDiskCacheEntry(mapRecord);
     880           0 :         if (!diskEntry) {
     881           0 :             return kVisitNextRecord;
     882             :         }
     883             : 
     884             :         // create nsICacheEntryInfo
     885           0 :         nsDiskCacheEntryInfo * entryInfo = new nsDiskCacheEntryInfo(DISK_CACHE_DEVICE_ID, diskEntry);
     886           0 :         if (!entryInfo) {
     887           0 :             return kStopVisitingRecords;
     888             :         }
     889           0 :         nsCOMPtr<nsICacheEntryInfo> ref(entryInfo);
     890             : 
     891             :         bool    keepGoing;
     892           0 :         (void)mVisitor->VisitEntry(DISK_CACHE_DEVICE_ID, entryInfo, &keepGoing);
     893           0 :         return keepGoing ? kVisitNextRecord : kStopVisitingRecords;
     894             :     }
     895             : 
     896             : private:
     897             :         nsDiskCacheMap *    mCacheMap;
     898             :         nsICacheVisitor *   mVisitor;
     899             : };
     900             : 
     901             : 
     902             : nsresult
     903           0 : nsDiskCacheDevice::Visit(nsICacheVisitor * visitor)
     904             : {
     905           0 :     if (!Initialized())  return NS_ERROR_NOT_INITIALIZED;
     906           0 :     nsDiskCacheDeviceInfo* deviceInfo = new nsDiskCacheDeviceInfo(this);
     907           0 :     nsCOMPtr<nsICacheDeviceInfo> ref(deviceInfo);
     908             : 
     909             :     bool keepGoing;
     910           0 :     nsresult rv = visitor->VisitDevice(DISK_CACHE_DEVICE_ID, deviceInfo, &keepGoing);
     911           0 :     if (NS_FAILED(rv)) return rv;
     912             : 
     913           0 :     if (keepGoing) {
     914           0 :         EntryInfoVisitor  infoVisitor(&mCacheMap, visitor);
     915           0 :         return mCacheMap.VisitRecords(&infoVisitor);
     916             :     }
     917             : 
     918           0 :     return NS_OK;
     919             : }
     920             : 
     921             : // Max allowed size for an entry is currently MIN(mMaxEntrySize, 1/8 CacheCapacity)
     922             : bool
     923           0 : nsDiskCacheDevice::EntryIsTooBig(int64_t entrySize)
     924             : {
     925           0 :     if (mMaxEntrySize == -1) // no limit
     926           0 :         return entrySize > (static_cast<int64_t>(mCacheCapacity) * 1024 / 8);
     927             :     else
     928           0 :         return entrySize > mMaxEntrySize ||
     929           0 :                entrySize > (static_cast<int64_t>(mCacheCapacity) * 1024 / 8);
     930             : }
     931             : 
     932             : nsresult
     933           0 : nsDiskCacheDevice::EvictEntries(const char * clientID)
     934             : {
     935           0 :     CACHE_LOG_DEBUG(("CACHE: disk EvictEntries [%s]\n", clientID));
     936             : 
     937           0 :     if (!Initialized())  return NS_ERROR_NOT_INITIALIZED;
     938             :     nsresult  rv;
     939             : 
     940           0 :     if (clientID == nullptr) {
     941             :         // we're clearing the entire disk cache
     942           0 :         rv = ClearDiskCache();
     943           0 :         if (rv != NS_ERROR_CACHE_IN_USE)
     944           0 :             return rv;
     945             :     }
     946             : 
     947           0 :     nsDiskCacheEvictor  evictor(&mCacheMap, &mBindery, 0, clientID);
     948           0 :     rv = mCacheMap.VisitRecords(&evictor);
     949             : 
     950           0 :     if (clientID == nullptr)     // we tried to clear the entire cache
     951           0 :         rv = mCacheMap.Trim(); // so trim cache block files (if possible)
     952           0 :     return rv;
     953             : }
     954             : 
     955             : 
     956             : /**
     957             :  *  private methods
     958             :  */
     959             : 
     960             : nsresult
     961           0 : nsDiskCacheDevice::OpenDiskCache()
     962             : {
     963           0 :     Telemetry::AutoTimer<Telemetry::NETWORK_DISK_CACHE_OPEN> timer;
     964             :     // if we don't have a cache directory, create one and open it
     965             :     bool exists;
     966           0 :     nsresult rv = mCacheDirectory->Exists(&exists);
     967           0 :     if (NS_FAILED(rv))
     968           0 :         return rv;
     969             : 
     970           0 :     if (exists) {
     971             :         // Try opening cache map file.
     972             :         nsDiskCache::CorruptCacheInfo corruptInfo;
     973           0 :         rv = mCacheMap.Open(mCacheDirectory, &corruptInfo);
     974             : 
     975           0 :         if (rv == NS_ERROR_ALREADY_INITIALIZED) {
     976           0 :           NS_WARNING("nsDiskCacheDevice::OpenDiskCache: already open!");
     977           0 :         } else if (NS_FAILED(rv)) {
     978             :             // Consider cache corrupt: delete it
     979             :             // delay delete by 1 minute to avoid IO thrash at startup
     980           0 :             rv = nsDeleteDir::DeleteDir(mCacheDirectory, true, 60000);
     981           0 :             if (NS_FAILED(rv))
     982           0 :                 return rv;
     983           0 :             exists = false;
     984             :         }
     985             :     }
     986             : 
     987             :     // if we don't have a cache directory, create one and open it
     988           0 :     if (!exists) {
     989           0 :         nsCacheService::MarkStartingFresh();
     990           0 :         rv = mCacheDirectory->Create(nsIFile::DIRECTORY_TYPE, 0777);
     991           0 :         CACHE_LOG_PATH(LogLevel::Info, "\ncreate cache directory: %s\n", mCacheDirectory);
     992           0 :         CACHE_LOG_INFO(("mCacheDirectory->Create() = %" PRIx32 "\n",
     993             :                         static_cast<uint32_t>(rv)));
     994           0 :         if (NS_FAILED(rv))
     995           0 :             return rv;
     996             : 
     997             :         // reopen the cache map
     998             :         nsDiskCache::CorruptCacheInfo corruptInfo;
     999           0 :         rv = mCacheMap.Open(mCacheDirectory, &corruptInfo);
    1000           0 :         if (NS_FAILED(rv))
    1001           0 :             return rv;
    1002             :     }
    1003             : 
    1004           0 :     return NS_OK;
    1005             : }
    1006             : 
    1007             : 
    1008             : nsresult
    1009           0 : nsDiskCacheDevice::ClearDiskCache()
    1010             : {
    1011           0 :     if (mBindery.ActiveBindings())
    1012           0 :         return NS_ERROR_CACHE_IN_USE;
    1013             : 
    1014           0 :     mClearingDiskCache = true;
    1015             : 
    1016           0 :     nsresult rv = Shutdown_Private(false);  // false: don't bother flushing
    1017           0 :     if (NS_FAILED(rv))
    1018           0 :         return rv;
    1019             : 
    1020           0 :     mClearingDiskCache = false;
    1021             : 
    1022             :     // If the disk cache directory is already gone, then it's not an error if
    1023             :     // we fail to delete it ;-)
    1024           0 :     rv = nsDeleteDir::DeleteDir(mCacheDirectory, true);
    1025           0 :     if (NS_FAILED(rv) && rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
    1026           0 :         return rv;
    1027             : 
    1028           0 :     return Init();
    1029             : }
    1030             : 
    1031             : 
    1032             : nsresult
    1033           0 : nsDiskCacheDevice::EvictDiskCacheEntries(uint32_t  targetCapacity)
    1034             : {
    1035           0 :     CACHE_LOG_DEBUG(("CACHE: disk EvictDiskCacheEntries [%u]\n",
    1036             :         targetCapacity));
    1037             : 
    1038           0 :     NS_ASSERTION(targetCapacity > 0, "oops");
    1039             : 
    1040           0 :     if (mCacheMap.TotalSize() < targetCapacity)
    1041           0 :         return NS_OK;
    1042             : 
    1043             :     // targetCapacity is in KiB's
    1044           0 :     nsDiskCacheEvictor  evictor(&mCacheMap, &mBindery, targetCapacity, nullptr);
    1045           0 :     return mCacheMap.EvictRecords(&evictor);
    1046             : }
    1047             : 
    1048             : 
    1049             : /**
    1050             :  *  methods for prefs
    1051             :  */
    1052             : 
    1053             : void
    1054           0 : nsDiskCacheDevice::SetCacheParentDirectory(nsIFile * parentDir)
    1055             : {
    1056             :     nsresult rv;
    1057             :     bool    exists;
    1058             : 
    1059           0 :     if (Initialized()) {
    1060           0 :         NS_ASSERTION(false, "Cannot switch cache directory when initialized");
    1061           0 :         return;
    1062             :     }
    1063             : 
    1064           0 :     if (!parentDir) {
    1065           0 :         mCacheDirectory = nullptr;
    1066           0 :         return;
    1067             :     }
    1068             : 
    1069             :     // ensure parent directory exists
    1070           0 :     rv = parentDir->Exists(&exists);
    1071           0 :     if (NS_SUCCEEDED(rv) && !exists)
    1072           0 :         rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
    1073           0 :     if (NS_FAILED(rv))  return;
    1074             : 
    1075             :     // ensure cache directory exists
    1076           0 :     nsCOMPtr<nsIFile> directory;
    1077             : 
    1078           0 :     rv = parentDir->Clone(getter_AddRefs(directory));
    1079           0 :     if (NS_FAILED(rv))  return;
    1080           0 :     rv = directory->AppendNative(NS_LITERAL_CSTRING("Cache"));
    1081           0 :     if (NS_FAILED(rv))  return;
    1082             : 
    1083           0 :     mCacheDirectory = do_QueryInterface(directory);
    1084             : }
    1085             : 
    1086             : 
    1087             : void
    1088           0 : nsDiskCacheDevice::getCacheDirectory(nsIFile ** result)
    1089             : {
    1090           0 :     *result = mCacheDirectory;
    1091           0 :     NS_IF_ADDREF(*result);
    1092           0 : }
    1093             : 
    1094             : 
    1095             : /**
    1096             :  *  NOTE: called while holding the cache service lock
    1097             :  */
    1098             : void
    1099           0 : nsDiskCacheDevice::SetCapacity(uint32_t  capacity)
    1100             : {
    1101             :     // Units are KiB's
    1102           0 :     mCacheCapacity = capacity;
    1103           0 :     if (Initialized()) {
    1104           0 :         if (NS_IsMainThread()) {
    1105             :             // Do not evict entries on the main thread
    1106             :             nsCacheService::DispatchToCacheIOThread(
    1107           0 :                 new nsEvictDiskCacheEntriesEvent(this));
    1108             :         } else {
    1109             :             // start evicting entries if the new size is smaller!
    1110           0 :             EvictDiskCacheEntries(mCacheCapacity);
    1111             :         }
    1112             :     }
    1113             :     // Let cache map know of the new capacity
    1114           0 :     mCacheMap.NotifyCapacityChange(capacity);
    1115           0 : }
    1116             : 
    1117             : 
    1118           0 : uint32_t nsDiskCacheDevice::getCacheCapacity()
    1119             : {
    1120           0 :     return mCacheCapacity;
    1121             : }
    1122             : 
    1123             : 
    1124           0 : uint32_t nsDiskCacheDevice::getCacheSize()
    1125             : {
    1126           0 :     return mCacheMap.TotalSize();
    1127             : }
    1128             : 
    1129             : 
    1130           0 : uint32_t nsDiskCacheDevice::getEntryCount()
    1131             : {
    1132           0 :     return mCacheMap.EntryCount();
    1133             : }
    1134             : 
    1135             : void
    1136           0 : nsDiskCacheDevice::SetMaxEntrySize(int32_t maxSizeInKilobytes)
    1137             : {
    1138             :     // Internal units are bytes. Changing this only takes effect *after* the
    1139             :     // change and has no consequences for existing cache-entries
    1140           0 :     if (maxSizeInKilobytes >= 0)
    1141           0 :         mMaxEntrySize = maxSizeInKilobytes * 1024;
    1142             :     else
    1143           0 :         mMaxEntrySize = -1;
    1144           0 : }
    1145             : 
    1146             : size_t
    1147           0 : nsDiskCacheDevice::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
    1148             : {
    1149           0 :     size_t usage = aMallocSizeOf(this);
    1150             : 
    1151           0 :     usage += mCacheMap.SizeOfExcludingThis(aMallocSizeOf);
    1152           0 :     usage += mBindery.SizeOfExcludingThis(aMallocSizeOf);
    1153             : 
    1154           0 :     return usage;
    1155             : }

Generated by: LCOV version 1.13