LCOV - code coverage report
Current view: directory - netwerk/cache - nsMemoryCacheDevice.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 263 181 68.8 %
Date: 2012-06-02 Functions: 34 26 76.5 %

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

Generated by: LCOV version 1.7