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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=80: */
       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 "nsCache.h"
       8             : #include "nsMemoryCacheDevice.h"
       9             : #include "nsCacheService.h"
      10             : #include "nsICacheService.h"
      11             : #include "nsICacheVisitor.h"
      12             : #include "nsIStorageStream.h"
      13             : #include "nsCRT.h"
      14             : #include "nsReadableUtils.h"
      15             : #include "mozilla/IntegerPrintfMacros.h"
      16             : #include "mozilla/MathAlgorithms.h"
      17             : #include "mozilla/Telemetry.h"
      18             : #include <algorithm>
      19             : 
      20             : // The memory cache implements the "LRU-SP" caching algorithm
      21             : // described in "LRU-SP: A Size-Adjusted and Popularity-Aware LRU Replacement
      22             : // Algorithm for Web Caching" by Kai Cheng and Yahiko Kambayashi.
      23             : 
      24             : // We keep kQueueCount LRU queues, which should be about ceil(log2(mHardLimit))
      25             : // The queues hold exponentially increasing ranges of floor(log2((size/nref)))
      26             : // values for entries.
      27             : // Entries larger than 2^(kQueueCount-1) go in the last queue.
      28             : // Entries with no expiration go in the first queue.
      29             : 
      30             : const char *gMemoryDeviceID      = "memory";
      31             : using namespace mozilla;
      32             : 
      33           0 : nsMemoryCacheDevice::nsMemoryCacheDevice()
      34             :     : mInitialized(false),
      35             :       mHardLimit(4 * 1024 * 1024),       // default, if no pref
      36           0 :       mSoftLimit((mHardLimit * 9) / 10), // default, if no pref
      37             :       mTotalSize(0),
      38             :       mInactiveSize(0),
      39             :       mEntryCount(0),
      40             :       mMaxEntryCount(0),
      41           0 :       mMaxEntrySize(-1)  // -1 means "no limit"
      42             : {
      43           0 :     for (int i=0; i<kQueueCount; ++i)
      44           0 :         PR_INIT_CLIST(&mEvictionList[i]);
      45           0 : }
      46             : 
      47             : 
      48           0 : nsMemoryCacheDevice::~nsMemoryCacheDevice()
      49             : {
      50           0 :     Shutdown();
      51           0 : }
      52             : 
      53             : 
      54             : nsresult
      55           0 : nsMemoryCacheDevice::Init()
      56             : {
      57           0 :     if (mInitialized)  return NS_ERROR_ALREADY_INITIALIZED;
      58             : 
      59           0 :     mMemCacheEntries.Init();
      60           0 :     mInitialized = true;
      61           0 :     return NS_OK;
      62             : }
      63             : 
      64             : 
      65             : nsresult
      66           0 : nsMemoryCacheDevice::Shutdown()
      67             : {
      68           0 :     NS_ASSERTION(mInitialized, "### attempting shutdown while not initialized");
      69           0 :     NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
      70             : 
      71           0 :     mMemCacheEntries.Shutdown();
      72             : 
      73             :     // evict all entries
      74             :     nsCacheEntry * entry, * next;
      75             : 
      76           0 :     for (int i = kQueueCount - 1; i >= 0; --i) {
      77           0 :         entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
      78           0 :         while (entry != &mEvictionList[i]) {
      79           0 :             NS_ASSERTION(!entry->IsInUse(), "### shutting down with active entries");
      80           0 :             next = (nsCacheEntry *)PR_NEXT_LINK(entry);
      81           0 :             PR_REMOVE_AND_INIT_LINK(entry);
      82             : 
      83             :             // update statistics
      84           0 :             int32_t memoryRecovered = (int32_t)entry->DataSize();
      85           0 :             mTotalSize    -= memoryRecovered;
      86           0 :             mInactiveSize -= memoryRecovered;
      87           0 :             --mEntryCount;
      88             : 
      89           0 :             delete entry;
      90           0 :             entry = next;
      91             :         }
      92             :     }
      93             : 
      94             : /*
      95             :  * we're not factoring in changes to meta data yet...
      96             :  *  NS_ASSERTION(mTotalSize == 0, "### mem cache leaking entries?");
      97             :  */
      98           0 :     NS_ASSERTION(mInactiveSize == 0, "### mem cache leaking entries?");
      99           0 :     NS_ASSERTION(mEntryCount == 0, "### mem cache leaking entries?");
     100             : 
     101           0 :     mInitialized = false;
     102             : 
     103           0 :     return NS_OK;
     104             : }
     105             : 
     106             : 
     107             : const char *
     108           0 : nsMemoryCacheDevice::GetDeviceID()
     109             : {
     110           0 :     return gMemoryDeviceID;
     111             : }
     112             : 
     113             : 
     114             : nsCacheEntry *
     115           0 : nsMemoryCacheDevice::FindEntry(nsCString * key, bool *collision)
     116             : {
     117           0 :     mozilla::Telemetry::AutoTimer<mozilla::Telemetry::CACHE_MEMORY_SEARCH_2> timer;
     118           0 :     nsCacheEntry * entry = mMemCacheEntries.GetEntry(key);
     119           0 :     if (!entry)  return nullptr;
     120             : 
     121             :     // move entry to the tail of an eviction list
     122           0 :     PR_REMOVE_AND_INIT_LINK(entry);
     123           0 :     PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);
     124             : 
     125           0 :     mInactiveSize -= entry->DataSize();
     126             : 
     127           0 :     return entry;
     128             : }
     129             : 
     130             : 
     131             : nsresult
     132           0 : nsMemoryCacheDevice::DeactivateEntry(nsCacheEntry * entry)
     133             : {
     134           0 :     CACHE_LOG_DEBUG(("nsMemoryCacheDevice::DeactivateEntry for entry 0x%p\n",
     135             :                      entry));
     136           0 :     if (entry->IsDoomed()) {
     137             : #ifdef DEBUG
     138             :         // XXX verify we've removed it from mMemCacheEntries & eviction list
     139             : #endif
     140           0 :         delete entry;
     141           0 :         CACHE_LOG_DEBUG(("deleted doomed entry 0x%p\n", entry));
     142           0 :         return NS_OK;
     143             :     }
     144             : 
     145             : #ifdef DEBUG
     146           0 :     nsCacheEntry * ourEntry = mMemCacheEntries.GetEntry(entry->Key());
     147           0 :     NS_ASSERTION(ourEntry, "DeactivateEntry called for an entry we don't have!");
     148           0 :     NS_ASSERTION(entry == ourEntry, "entry doesn't match ourEntry");
     149           0 :     if (ourEntry != entry)
     150           0 :         return NS_ERROR_INVALID_POINTER;
     151             : #endif
     152             : 
     153           0 :     mInactiveSize += entry->DataSize();
     154           0 :     EvictEntriesIfNecessary();
     155             : 
     156           0 :     return NS_OK;
     157             : }
     158             : 
     159             : 
     160             : nsresult
     161           0 : nsMemoryCacheDevice::BindEntry(nsCacheEntry * entry)
     162             : {
     163           0 :     if (!entry->IsDoomed()) {
     164           0 :         NS_ASSERTION(PR_CLIST_IS_EMPTY(entry),"entry is already on a list!");
     165             : 
     166             :         // append entry to the eviction list
     167           0 :         PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);
     168             : 
     169             :         // add entry to hashtable of mem cache entries
     170           0 :         nsresult  rv = mMemCacheEntries.AddEntry(entry);
     171           0 :         if (NS_FAILED(rv)) {
     172           0 :             PR_REMOVE_AND_INIT_LINK(entry);
     173           0 :             return rv;
     174             :         }
     175             : 
     176             :         // add size of entry to memory totals
     177           0 :         ++mEntryCount;
     178           0 :         if (mMaxEntryCount < mEntryCount) mMaxEntryCount = mEntryCount;
     179             : 
     180           0 :         mTotalSize += entry->DataSize();
     181           0 :         EvictEntriesIfNecessary();
     182             :     }
     183             : 
     184           0 :     return NS_OK;
     185             : }
     186             : 
     187             : 
     188             : void
     189           0 : nsMemoryCacheDevice::DoomEntry(nsCacheEntry * entry)
     190             : {
     191             : #ifdef DEBUG
     192             :     // debug code to verify we have entry
     193           0 :     nsCacheEntry * hashEntry = mMemCacheEntries.GetEntry(entry->Key());
     194           0 :     if (!hashEntry)               NS_WARNING("no entry for key");
     195           0 :     else if (entry != hashEntry)  NS_WARNING("entry != hashEntry");
     196             : #endif
     197           0 :     CACHE_LOG_DEBUG(("Dooming entry 0x%p in memory cache\n", entry));
     198           0 :     EvictEntry(entry, DO_NOT_DELETE_ENTRY);
     199           0 : }
     200             : 
     201             : 
     202             : nsresult
     203           0 : nsMemoryCacheDevice::OpenInputStreamForEntry( nsCacheEntry *    entry,
     204             :                                               nsCacheAccessMode mode,
     205             :                                               uint32_t          offset,
     206             :                                               nsIInputStream ** result)
     207             : {
     208           0 :     NS_ENSURE_ARG_POINTER(entry);
     209           0 :     NS_ENSURE_ARG_POINTER(result);
     210             : 
     211           0 :     nsCOMPtr<nsIStorageStream> storage;
     212             :     nsresult rv;
     213             : 
     214           0 :     nsISupports *data = entry->Data();
     215           0 :     if (data) {
     216           0 :         storage = do_QueryInterface(data, &rv);
     217           0 :         if (NS_FAILED(rv))
     218           0 :             return rv;
     219             :     }
     220             :     else {
     221           0 :         rv = NS_NewStorageStream(4096, uint32_t(-1), getter_AddRefs(storage));
     222           0 :         if (NS_FAILED(rv))
     223           0 :             return rv;
     224           0 :         entry->SetData(storage);
     225             :     }
     226             : 
     227           0 :     return storage->NewInputStream(offset, result);
     228             : }
     229             : 
     230             : 
     231             : nsresult
     232           0 : nsMemoryCacheDevice::OpenOutputStreamForEntry( nsCacheEntry *     entry,
     233             :                                                nsCacheAccessMode  mode,
     234             :                                                uint32_t           offset,
     235             :                                                nsIOutputStream ** result)
     236             : {
     237           0 :     NS_ENSURE_ARG_POINTER(entry);
     238           0 :     NS_ENSURE_ARG_POINTER(result);
     239             : 
     240           0 :     nsCOMPtr<nsIStorageStream> storage;
     241             :     nsresult rv;
     242             : 
     243           0 :     nsISupports *data = entry->Data();
     244           0 :     if (data) {
     245           0 :         storage = do_QueryInterface(data, &rv);
     246           0 :         if (NS_FAILED(rv))
     247           0 :             return rv;
     248             :     }
     249             :     else {
     250           0 :         rv = NS_NewStorageStream(4096, uint32_t(-1), getter_AddRefs(storage));
     251           0 :         if (NS_FAILED(rv))
     252           0 :             return rv;
     253           0 :         entry->SetData(storage);
     254             :     }
     255             : 
     256           0 :     return storage->GetOutputStream(offset, result);
     257             : }
     258             : 
     259             : 
     260             : nsresult
     261           0 : nsMemoryCacheDevice::GetFileForEntry( nsCacheEntry *    entry,
     262             :                                       nsIFile **        result )
     263             : {
     264           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     265             : }
     266             : 
     267             : bool
     268           0 : nsMemoryCacheDevice::EntryIsTooBig(int64_t entrySize)
     269             : {
     270           0 :     CACHE_LOG_DEBUG(("nsMemoryCacheDevice::EntryIsTooBig "
     271             :                      "[size=%" PRId64 " max=%d soft=%d]\n",
     272             :                      entrySize, mMaxEntrySize, mSoftLimit));
     273           0 :     if (mMaxEntrySize == -1)
     274           0 :         return entrySize > mSoftLimit;
     275             :     else
     276           0 :         return (entrySize > mSoftLimit || entrySize > mMaxEntrySize);
     277             : }
     278             : 
     279             : size_t
     280           0 : nsMemoryCacheDevice::TotalSize()
     281             : {
     282           0 :     return mTotalSize;
     283             : }
     284             : 
     285             : nsresult
     286           0 : nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, int32_t deltaSize)
     287             : {
     288           0 :     if (entry->IsStreamData()) {
     289             :         // we have the right to refuse or pre-evict
     290           0 :         uint32_t  newSize = entry->DataSize() + deltaSize;
     291           0 :         if (EntryIsTooBig(newSize)) {
     292             : #ifdef DEBUG
     293             :             nsresult rv =
     294             : #endif
     295           0 :                 nsCacheService::DoomEntry(entry);
     296           0 :             NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed.");
     297           0 :             return NS_ERROR_ABORT;
     298             :         }
     299             :     }
     300             : 
     301             :     // adjust our totals
     302           0 :     mTotalSize    += deltaSize;
     303             : 
     304           0 :     if (!entry->IsDoomed()) {
     305             :         // move entry to the tail of the appropriate eviction list
     306           0 :         PR_REMOVE_AND_INIT_LINK(entry);
     307           0 :         PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, deltaSize)]);
     308             :     }
     309             : 
     310           0 :     EvictEntriesIfNecessary();
     311           0 :     return NS_OK;
     312             : }
     313             : 
     314             : 
     315             : void
     316           0 : nsMemoryCacheDevice::AdjustMemoryLimits(int32_t  softLimit, int32_t  hardLimit)
     317             : {
     318           0 :     mSoftLimit = softLimit;
     319           0 :     mHardLimit = hardLimit;
     320             : 
     321             :     // First, evict entries that won't fit into the new cache size.
     322           0 :     EvictEntriesIfNecessary();
     323           0 : }
     324             : 
     325             : 
     326             : void
     327           0 : nsMemoryCacheDevice::EvictEntry(nsCacheEntry * entry, bool deleteEntry)
     328             : {
     329           0 :     CACHE_LOG_DEBUG(("Evicting entry 0x%p from memory cache, deleting: %d\n",
     330             :                      entry, deleteEntry));
     331             :     // remove entry from our hashtable
     332           0 :     mMemCacheEntries.RemoveEntry(entry);
     333             : 
     334             :     // remove entry from the eviction list
     335           0 :     PR_REMOVE_AND_INIT_LINK(entry);
     336             : 
     337             :     // update statistics
     338           0 :     int32_t memoryRecovered = (int32_t)entry->DataSize();
     339           0 :     mTotalSize    -= memoryRecovered;
     340           0 :     if (!entry->IsDoomed())
     341           0 :         mInactiveSize -= memoryRecovered;
     342           0 :     --mEntryCount;
     343             : 
     344           0 :     if (deleteEntry)  delete entry;
     345           0 : }
     346             : 
     347             : 
     348             : void
     349           0 : nsMemoryCacheDevice::EvictEntriesIfNecessary(void)
     350             : {
     351             :     nsCacheEntry * entry;
     352             :     nsCacheEntry * maxEntry;
     353           0 :     CACHE_LOG_DEBUG(("EvictEntriesIfNecessary.  mTotalSize: %d, mHardLimit: %d,"
     354             :                      "mInactiveSize: %d, mSoftLimit: %d\n",
     355             :                      mTotalSize, mHardLimit, mInactiveSize, mSoftLimit));
     356             : 
     357           0 :     if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit))
     358           0 :         return;
     359             : 
     360           0 :     uint32_t now = SecondsFromPRTime(PR_Now());
     361           0 :     uint64_t entryCost = 0;
     362           0 :     uint64_t maxCost = 0;
     363           0 :     do {
     364             :         // LRU-SP eviction selection: Check the head of each segment (each
     365             :         // eviction list, kept in LRU order) and select the maximal-cost
     366             :         // entry for eviction. Cost is time-since-accessed * size / nref.
     367           0 :         maxEntry = 0;
     368           0 :         for (int i = kQueueCount - 1; i >= 0; --i) {
     369           0 :             entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
     370             : 
     371             :             // If the head of a list is in use, check the next available entry
     372           0 :             while ((entry != &mEvictionList[i]) &&
     373           0 :                    (entry->IsInUse())) {
     374           0 :                 entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
     375             :             }
     376             : 
     377           0 :             if (entry != &mEvictionList[i]) {
     378           0 :                 entryCost = (uint64_t)
     379           0 :                     (now - entry->LastFetched()) * entry->DataSize() /
     380           0 :                     std::max(1, entry->FetchCount());
     381           0 :                 if (!maxEntry || (entryCost > maxCost)) {
     382           0 :                     maxEntry = entry;
     383           0 :                     maxCost = entryCost;
     384             :                 }
     385             :             }
     386             :         }
     387           0 :         if (maxEntry) {
     388           0 :             EvictEntry(maxEntry, DELETE_ENTRY);
     389             :         } else {
     390           0 :             break;
     391             :         }
     392             :     }
     393           0 :     while ((mTotalSize >= mHardLimit) || (mInactiveSize >= mSoftLimit));
     394             : }
     395             : 
     396             : 
     397             : int
     398           0 : nsMemoryCacheDevice::EvictionList(nsCacheEntry * entry, int32_t  deltaSize)
     399             : {
     400             :     // favor items which never expire by putting them in the lowest-index queue
     401           0 :     if (entry->ExpirationTime() == nsICache::NO_EXPIRATION_TIME)
     402           0 :         return 0;
     403             : 
     404             :     // compute which eviction queue this entry should go into,
     405             :     // based on floor(log2(size/nref))
     406           0 :     int32_t  size       = deltaSize + (int32_t)entry->DataSize();
     407           0 :     int32_t  fetchCount = std::max(1, entry->FetchCount());
     408             : 
     409           0 :     return std::min((int)mozilla::FloorLog2(size / fetchCount), kQueueCount - 1);
     410             : }
     411             : 
     412             : 
     413             : nsresult
     414           0 : nsMemoryCacheDevice::Visit(nsICacheVisitor * visitor)
     415             : {
     416           0 :     nsMemoryCacheDeviceInfo * deviceInfo = new nsMemoryCacheDeviceInfo(this);
     417           0 :     nsCOMPtr<nsICacheDeviceInfo> deviceRef(deviceInfo);
     418           0 :     if (!deviceInfo) return NS_ERROR_OUT_OF_MEMORY;
     419             : 
     420             :     bool keepGoing;
     421           0 :     nsresult rv = visitor->VisitDevice(gMemoryDeviceID, deviceInfo, &keepGoing);
     422           0 :     if (NS_FAILED(rv)) return rv;
     423             : 
     424           0 :     if (!keepGoing)
     425           0 :         return NS_OK;
     426             : 
     427             :     nsCacheEntry *              entry;
     428           0 :     nsCOMPtr<nsICacheEntryInfo> entryRef;
     429             : 
     430           0 :     for (int i = kQueueCount - 1; i >= 0; --i) {
     431           0 :         entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
     432           0 :         while (entry != &mEvictionList[i]) {
     433           0 :             nsCacheEntryInfo * entryInfo = new nsCacheEntryInfo(entry);
     434           0 :             if (!entryInfo) return NS_ERROR_OUT_OF_MEMORY;
     435           0 :             entryRef = entryInfo;
     436             : 
     437           0 :             rv = visitor->VisitEntry(gMemoryDeviceID, entryInfo, &keepGoing);
     438           0 :             entryInfo->DetachEntry();
     439           0 :             if (NS_FAILED(rv)) return rv;
     440           0 :             if (!keepGoing) break;
     441             : 
     442           0 :             entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
     443             :         }
     444             :     }
     445           0 :     return NS_OK;
     446             : }
     447             : 
     448             : 
     449             : static bool
     450           0 : IsEntryPrivate(nsCacheEntry* entry, void* args)
     451             : {
     452           0 :     return entry->IsPrivate();
     453             : }
     454             : 
     455             : struct ClientIDArgs {
     456             :     const char* clientID;
     457             :     uint32_t prefixLength;
     458             : };
     459             : 
     460             : static bool
     461           0 : EntryMatchesClientID(nsCacheEntry* entry, void* args)
     462             : {
     463           0 :     const char * clientID = static_cast<ClientIDArgs*>(args)->clientID;
     464           0 :     uint32_t prefixLength = static_cast<ClientIDArgs*>(args)->prefixLength;
     465           0 :     const char * key = entry->Key()->get();
     466           0 :     return !clientID || nsCRT::strncmp(clientID, key, prefixLength) == 0;
     467             : }
     468             : 
     469             : nsresult
     470           0 : nsMemoryCacheDevice::DoEvictEntries(bool (*matchFn)(nsCacheEntry* entry, void* args), void* args)
     471             : {
     472             :     nsCacheEntry * entry;
     473             : 
     474           0 :     for (int i = kQueueCount - 1; i >= 0; --i) {
     475           0 :         PRCList * elem = PR_LIST_HEAD(&mEvictionList[i]);
     476           0 :         while (elem != &mEvictionList[i]) {
     477           0 :             entry = (nsCacheEntry *)elem;
     478           0 :             elem = PR_NEXT_LINK(elem);
     479             : 
     480           0 :             if (!matchFn(entry, args))
     481           0 :                 continue;
     482             : 
     483           0 :             if (entry->IsInUse()) {
     484           0 :                 nsresult rv = nsCacheService::DoomEntry(entry);
     485           0 :                 if (NS_FAILED(rv)) {
     486           0 :                     CACHE_LOG_WARNING(("memCache->DoEvictEntries() aborted: rv =%" PRIx32,
     487             :                                        static_cast<uint32_t>(rv)));
     488           0 :                     return rv;
     489             :                 }
     490             :             } else {
     491           0 :                 EvictEntry(entry, DELETE_ENTRY);
     492             :             }
     493             :         }
     494             :     }
     495             : 
     496           0 :     return NS_OK;
     497             : }
     498             : 
     499             : nsresult
     500           0 : nsMemoryCacheDevice::EvictEntries(const char * clientID)
     501             : {
     502           0 :     ClientIDArgs args = {clientID, clientID ? uint32_t(strlen(clientID)) : 0};
     503           0 :     return DoEvictEntries(&EntryMatchesClientID, &args);
     504             : }
     505             : 
     506             : nsresult
     507           0 : nsMemoryCacheDevice::EvictPrivateEntries()
     508             : {
     509           0 :     return DoEvictEntries(&IsEntryPrivate, nullptr);
     510             : }
     511             : 
     512             : 
     513             : // WARNING: SetCapacity can get called before Init()
     514             : void
     515           0 : nsMemoryCacheDevice::SetCapacity(int32_t  capacity)
     516             : {
     517           0 :     int32_t hardLimit = capacity * 1024;  // convert k into bytes
     518           0 :     int32_t softLimit = (hardLimit * 9) / 10;
     519           0 :     AdjustMemoryLimits(softLimit, hardLimit);
     520           0 : }
     521             : 
     522             : void
     523           0 : nsMemoryCacheDevice::SetMaxEntrySize(int32_t maxSizeInKilobytes)
     524             : {
     525             :     // Internal unit is bytes. Changing this only takes effect *after* the
     526             :     // change and has no consequences for existing cache-entries
     527           0 :     if (maxSizeInKilobytes >= 0)
     528           0 :         mMaxEntrySize = maxSizeInKilobytes * 1024;
     529             :     else
     530           0 :         mMaxEntrySize = -1;
     531           0 : }
     532             : 
     533             : #ifdef DEBUG
     534             : void
     535           0 : nsMemoryCacheDevice::CheckEntryCount()
     536             : {
     537           0 :     if (!mInitialized)  return;
     538             : 
     539           0 :     int32_t evictionListCount = 0;
     540           0 :     for (int i=0; i<kQueueCount; ++i) {
     541           0 :         PRCList * elem = PR_LIST_HEAD(&mEvictionList[i]);
     542           0 :         while (elem != &mEvictionList[i]) {
     543           0 :             elem = PR_NEXT_LINK(elem);
     544           0 :             ++evictionListCount;
     545             :         }
     546             :     }
     547           0 :     NS_ASSERTION(mEntryCount == evictionListCount, "### mem cache badness");
     548             : 
     549           0 :     int32_t entryCount = 0;
     550           0 :     for (auto iter = mMemCacheEntries.Iter(); !iter.Done(); iter.Next()) {
     551           0 :         ++entryCount;
     552             :     }
     553           0 :     NS_ASSERTION(mEntryCount == entryCount, "### mem cache badness");
     554             : }
     555             : #endif
     556             : 
     557             : /******************************************************************************
     558             :  * nsMemoryCacheDeviceInfo - for implementing about:cache
     559             :  *****************************************************************************/
     560             : 
     561             : 
     562           0 : NS_IMPL_ISUPPORTS(nsMemoryCacheDeviceInfo, nsICacheDeviceInfo)
     563             : 
     564             : 
     565             : NS_IMETHODIMP
     566           0 : nsMemoryCacheDeviceInfo::GetDescription(char ** result)
     567             : {
     568           0 :     NS_ENSURE_ARG_POINTER(result);
     569           0 :     *result = NS_strdup("Memory cache device");
     570           0 :     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
     571           0 :     return NS_OK;
     572             : }
     573             : 
     574             : 
     575             : NS_IMETHODIMP
     576           0 : nsMemoryCacheDeviceInfo::GetUsageReport(char ** result)
     577             : {
     578           0 :     NS_ENSURE_ARG_POINTER(result);
     579           0 :     nsCString  buffer;
     580             : 
     581             :     buffer.AssignLiteral("  <tr>\n"
     582             :                          "    <th>Inactive storage:</th>\n"
     583           0 :                          "    <td>");
     584           0 :     buffer.AppendInt(mDevice->mInactiveSize / 1024);
     585             :     buffer.AppendLiteral(" KiB</td>\n"
     586           0 :                          "  </tr>\n");
     587             : 
     588           0 :     *result = ToNewCString(buffer);
     589           0 :     if (!*result) return NS_ERROR_OUT_OF_MEMORY;
     590           0 :     return NS_OK;
     591             : }
     592             : 
     593             : 
     594             : NS_IMETHODIMP
     595           0 : nsMemoryCacheDeviceInfo::GetEntryCount(uint32_t * result)
     596             : {
     597           0 :     NS_ENSURE_ARG_POINTER(result);
     598             :     // XXX compare calculated count vs. mEntryCount
     599           0 :     *result = (uint32_t)mDevice->mEntryCount;
     600           0 :     return NS_OK;
     601             : }
     602             : 
     603             : 
     604             : NS_IMETHODIMP
     605           0 : nsMemoryCacheDeviceInfo::GetTotalSize(uint32_t * result)
     606             : {
     607           0 :     NS_ENSURE_ARG_POINTER(result);
     608           0 :     *result = (uint32_t)mDevice->mTotalSize;
     609           0 :     return NS_OK;
     610             : }
     611             : 
     612             : 
     613             : NS_IMETHODIMP
     614           0 : nsMemoryCacheDeviceInfo::GetMaximumSize(uint32_t * result)
     615             : {
     616           0 :     NS_ENSURE_ARG_POINTER(result);
     617           0 :     *result = (uint32_t)mDevice->mHardLimit;
     618           0 :     return NS_OK;
     619             : }

Generated by: LCOV version 1.13