LCOV - code coverage report
Current view: top level - intl/icu/source/common - unifiedcache.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 231 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : ******************************************************************************
       5             : * Copyright (C) 2015, International Business Machines Corporation and         
       6             : * others. All Rights Reserved.                                                
       7             : ******************************************************************************
       8             : *                                                                             
       9             : * File UNIFIEDCACHE.CPP 
      10             : ******************************************************************************
      11             : */
      12             : 
      13             : #include "uhash.h"
      14             : #include "unifiedcache.h"
      15             : #include "umutex.h"
      16             : #include "mutex.h"
      17             : #include "uassert.h"
      18             : #include "ucln_cmn.h"
      19             : 
      20             : static icu::UnifiedCache *gCache = NULL;
      21             : static icu::SharedObject *gNoValue = NULL;
      22             : static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
      23             : static UConditionVar gInProgressValueAddedCond = U_CONDITION_INITIALIZER;
      24             : static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
      25             : static const int32_t MAX_EVICT_ITERATIONS = 10;
      26             : 
      27             : static int32_t DEFAULT_MAX_UNUSED = 1000;
      28             : static int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
      29             : 
      30             : 
      31             : U_CDECL_BEGIN
      32           0 : static UBool U_CALLCONV unifiedcache_cleanup() {
      33           0 :     gCacheInitOnce.reset();
      34           0 :     if (gCache) {
      35           0 :         delete gCache;
      36           0 :         gCache = NULL;
      37             :     }
      38           0 :     if (gNoValue) {
      39           0 :         delete gNoValue;
      40           0 :         gNoValue = NULL;
      41             :     }
      42           0 :     return TRUE;
      43             : }
      44             : U_CDECL_END
      45             : 
      46             : 
      47             : U_NAMESPACE_BEGIN
      48             : 
      49             : U_CAPI int32_t U_EXPORT2
      50           0 : ucache_hashKeys(const UHashTok key) {
      51           0 :     const CacheKeyBase *ckey = (const CacheKeyBase *) key.pointer;
      52           0 :     return ckey->hashCode();
      53             : }
      54             : 
      55             : U_CAPI UBool U_EXPORT2
      56           0 : ucache_compareKeys(const UHashTok key1, const UHashTok key2) {
      57           0 :     const CacheKeyBase *p1 = (const CacheKeyBase *) key1.pointer;
      58           0 :     const CacheKeyBase *p2 = (const CacheKeyBase *) key2.pointer;
      59           0 :     return *p1 == *p2;
      60             : }
      61             : 
      62             : U_CAPI void U_EXPORT2
      63           0 : ucache_deleteKey(void *obj) {
      64           0 :     CacheKeyBase *p = (CacheKeyBase *) obj;
      65           0 :     delete p;
      66           0 : }
      67             : 
      68           0 : CacheKeyBase::~CacheKeyBase() {
      69           0 : }
      70             : 
      71           0 : static void U_CALLCONV cacheInit(UErrorCode &status) {
      72           0 :     U_ASSERT(gCache == NULL);
      73             :     ucln_common_registerCleanup(
      74           0 :             UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
      75             : 
      76             :     // gNoValue must be created first to avoid assertion error in
      77             :     // cache constructor.
      78           0 :     gNoValue = new SharedObject();
      79           0 :     gCache = new UnifiedCache(status);
      80           0 :     if (gCache == NULL) {
      81           0 :         status = U_MEMORY_ALLOCATION_ERROR;
      82             :     }
      83           0 :     if (U_FAILURE(status)) {
      84           0 :         delete gCache;
      85           0 :         delete gNoValue;
      86           0 :         gCache = NULL;
      87           0 :         gNoValue = NULL;
      88           0 :         return;
      89             :     }
      90             :     // We add a softref because we want hash elements with gNoValue to be
      91             :     // elligible for purging but we don't ever want gNoValue to be deleted.
      92           0 :     gNoValue->addSoftRef();
      93             : }
      94             : 
      95           0 : UnifiedCache *UnifiedCache::getInstance(UErrorCode &status) {
      96           0 :     umtx_initOnce(gCacheInitOnce, &cacheInit, status);
      97           0 :     if (U_FAILURE(status)) {
      98           0 :         return NULL;
      99             :     }
     100           0 :     U_ASSERT(gCache != NULL);
     101           0 :     return gCache;
     102             : }
     103             : 
     104           0 : UnifiedCache::UnifiedCache(UErrorCode &status) :
     105             :         fHashtable(NULL),
     106             :         fEvictPos(UHASH_FIRST),
     107             :         fItemsInUseCount(0),
     108             :         fMaxUnused(DEFAULT_MAX_UNUSED),
     109             :         fMaxPercentageOfInUse(DEFAULT_PERCENTAGE_OF_IN_USE),
     110           0 :         fAutoEvictedCount(0) {
     111           0 :     if (U_FAILURE(status)) {
     112           0 :         return;
     113             :     }
     114           0 :     U_ASSERT(gNoValue != NULL);
     115           0 :     fHashtable = uhash_open(
     116             :             &ucache_hashKeys,
     117             :             &ucache_compareKeys,
     118             :             NULL,
     119             :             &status);
     120           0 :     if (U_FAILURE(status)) {
     121           0 :         return;
     122             :     }
     123           0 :     uhash_setKeyDeleter(fHashtable, &ucache_deleteKey);
     124             : }
     125             : 
     126           0 : void UnifiedCache::setEvictionPolicy(
     127             :         int32_t count, int32_t percentageOfInUseItems, UErrorCode &status) {
     128           0 :     if (U_FAILURE(status)) {
     129           0 :         return;
     130             :     }
     131           0 :     if (count < 0 || percentageOfInUseItems < 0) {
     132           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     133           0 :         return;
     134             :     }
     135           0 :     Mutex lock(&gCacheMutex);
     136           0 :     fMaxUnused = count;
     137           0 :     fMaxPercentageOfInUse = percentageOfInUseItems;
     138             : }
     139             : 
     140           0 : int32_t UnifiedCache::unusedCount() const {
     141           0 :     Mutex lock(&gCacheMutex);
     142           0 :     return uhash_count(fHashtable) - fItemsInUseCount;
     143             : }
     144             : 
     145           0 : int64_t UnifiedCache::autoEvictedCount() const {
     146           0 :     Mutex lock(&gCacheMutex);
     147           0 :     return fAutoEvictedCount;
     148             : }
     149             : 
     150           0 : int32_t UnifiedCache::keyCount() const {
     151           0 :     Mutex lock(&gCacheMutex);
     152           0 :     return uhash_count(fHashtable);
     153             : }
     154             : 
     155           0 : void UnifiedCache::flush() const {
     156           0 :     Mutex lock(&gCacheMutex);
     157             : 
     158             :     // Use a loop in case cache items that are flushed held hard references to
     159             :     // other cache items making those additional cache items eligible for
     160             :     // flushing.
     161           0 :     while (_flush(FALSE));
     162           0 : }
     163             : 
     164             : #ifdef UNIFIED_CACHE_DEBUG
     165             : #include <stdio.h>
     166             : 
     167             : void UnifiedCache::dump() {
     168             :     UErrorCode status = U_ZERO_ERROR;
     169             :     const UnifiedCache *cache = getInstance(status);
     170             :     if (U_FAILURE(status)) {
     171             :         fprintf(stderr, "Unified Cache: Error fetching cache.\n");
     172             :         return;
     173             :     }
     174             :     cache->dumpContents();
     175             : }
     176             : 
     177             : void UnifiedCache::dumpContents() const {
     178             :     Mutex lock(&gCacheMutex);
     179             :     _dumpContents();
     180             : }
     181             : 
     182             : // Dumps content of cache.
     183             : // On entry, gCacheMutex must be held.
     184             : // On exit, cache contents dumped to stderr.
     185             : void UnifiedCache::_dumpContents() const {
     186             :     int32_t pos = UHASH_FIRST;
     187             :     const UHashElement *element = uhash_nextElement(fHashtable, &pos);
     188             :     char buffer[256];
     189             :     int32_t cnt = 0;
     190             :     for (; element != NULL; element = uhash_nextElement(fHashtable, &pos)) {
     191             :         const SharedObject *sharedObject =
     192             :                 (const SharedObject *) element->value.pointer;
     193             :         const CacheKeyBase *key =
     194             :                 (const CacheKeyBase *) element->key.pointer;
     195             :         if (sharedObject->hasHardReferences()) {
     196             :             ++cnt;
     197             :             fprintf(
     198             :                     stderr,
     199             :                     "Unified Cache: Key '%s', error %d, value %p, total refcount %d, soft refcount %d\n", 
     200             :                     key->writeDescription(buffer, 256),
     201             :                     key->creationStatus,
     202             :                     sharedObject == gNoValue ? NULL :sharedObject,
     203             :                     sharedObject->getRefCount(),
     204             :                     sharedObject->getSoftRefCount());
     205             :         }
     206             :     }
     207             :     fprintf(stderr, "Unified Cache: %d out of a total of %d still have hard references\n", cnt, uhash_count(fHashtable));
     208             : }
     209             : #endif
     210             : 
     211           0 : UnifiedCache::~UnifiedCache() {
     212             :     // Try our best to clean up first.
     213           0 :     flush();
     214             :     {
     215             :         // Now all that should be left in the cache are entries that refer to
     216             :         // each other and entries with hard references from outside the cache. 
     217             :         // Nothing we can do about these so proceed to wipe out the cache.
     218           0 :         Mutex lock(&gCacheMutex);
     219           0 :         _flush(TRUE);
     220             :     }
     221           0 :     uhash_close(fHashtable);
     222           0 : }
     223             : 
     224             : // Returns the next element in the cache round robin style.
     225             : // On entry, gCacheMutex must be held.
     226             : const UHashElement *
     227           0 : UnifiedCache::_nextElement() const {
     228           0 :     const UHashElement *element = uhash_nextElement(fHashtable, &fEvictPos);
     229           0 :     if (element == NULL) {
     230           0 :         fEvictPos = UHASH_FIRST;
     231           0 :         return uhash_nextElement(fHashtable, &fEvictPos);
     232             :     }
     233           0 :     return element;
     234             : }
     235             : 
     236             : // Flushes the contents of the cache. If cache values hold references to other
     237             : // cache values then _flush should be called in a loop until it returns FALSE.
     238             : // On entry, gCacheMutex must be held.
     239             : // On exit, those values with are evictable are flushed. If all is true
     240             : // then every value is flushed even if it is not evictable.
     241             : // Returns TRUE if any value in cache was flushed or FALSE otherwise.
     242           0 : UBool UnifiedCache::_flush(UBool all) const {
     243           0 :     UBool result = FALSE;
     244           0 :     int32_t origSize = uhash_count(fHashtable);
     245           0 :     for (int32_t i = 0; i < origSize; ++i) {
     246           0 :         const UHashElement *element = _nextElement();
     247           0 :         if (all || _isEvictable(element)) {
     248             :             const SharedObject *sharedObject =
     249           0 :                     (const SharedObject *) element->value.pointer;
     250           0 :             uhash_removeElement(fHashtable, element);
     251           0 :             sharedObject->removeSoftRef();
     252           0 :             result = TRUE;
     253             :         }
     254             :     }
     255           0 :     return result;
     256             : }
     257             : 
     258             : // Computes how many items should be evicted.
     259             : // On entry, gCacheMutex must be held.
     260             : // Returns number of items that should be evicted or a value <= 0 if no
     261             : // items need to be evicted.
     262           0 : int32_t UnifiedCache::_computeCountOfItemsToEvict() const {
     263             :     int32_t maxPercentageOfInUseCount =
     264           0 :             fItemsInUseCount * fMaxPercentageOfInUse / 100;
     265           0 :     int32_t maxUnusedCount = fMaxUnused;
     266           0 :     if (maxUnusedCount < maxPercentageOfInUseCount) {
     267           0 :         maxUnusedCount = maxPercentageOfInUseCount;
     268             :     }
     269           0 :     return uhash_count(fHashtable) - fItemsInUseCount - maxUnusedCount;
     270             : }
     271             : 
     272             : // Run an eviction slice.
     273             : // On entry, gCacheMutex must be held.
     274             : // _runEvictionSlice runs a slice of the evict pipeline by examining the next
     275             : // 10 entries in the cache round robin style evicting them if they are eligible.
     276           0 : void UnifiedCache::_runEvictionSlice() const {
     277           0 :     int32_t maxItemsToEvict = _computeCountOfItemsToEvict();
     278           0 :     if (maxItemsToEvict <= 0) {
     279           0 :         return;
     280             :     }
     281           0 :     for (int32_t i = 0; i < MAX_EVICT_ITERATIONS; ++i) {
     282           0 :         const UHashElement *element = _nextElement();
     283           0 :         if (_isEvictable(element)) {
     284             :             const SharedObject *sharedObject =
     285           0 :                     (const SharedObject *) element->value.pointer;
     286           0 :             uhash_removeElement(fHashtable, element);
     287           0 :             sharedObject->removeSoftRef();
     288           0 :             ++fAutoEvictedCount;
     289           0 :             if (--maxItemsToEvict == 0) {
     290           0 :                 break;
     291             :             }
     292             :         }
     293             :     }
     294             : }
     295             : 
     296             : 
     297             : // Places a new value and creationStatus in the cache for the given key.
     298             : // On entry, gCacheMutex must be held. key must not exist in the cache. 
     299             : // On exit, value and creation status placed under key. Soft reference added
     300             : // to value on successful add. On error sets status.
     301           0 : void UnifiedCache::_putNew(
     302             :         const CacheKeyBase &key, 
     303             :         const SharedObject *value,
     304             :         const UErrorCode creationStatus,
     305             :         UErrorCode &status) const {
     306           0 :     if (U_FAILURE(status)) {
     307           0 :         return;
     308             :     }
     309           0 :     CacheKeyBase *keyToAdopt = key.clone();
     310           0 :     if (keyToAdopt == NULL) {
     311           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     312           0 :         return;
     313             :     }
     314           0 :     keyToAdopt->fCreationStatus = creationStatus;
     315           0 :     if (value->noSoftReferences()) {
     316           0 :         _registerMaster(keyToAdopt, value);
     317             :     }
     318           0 :     uhash_put(fHashtable, keyToAdopt, (void *) value, &status);
     319           0 :     if (U_SUCCESS(status)) {
     320           0 :         value->addSoftRef();
     321             :     }
     322             : }
     323             : 
     324             : // Places value and status at key if there is no value at key or if cache
     325             : // entry for key is in progress. Otherwise, it leaves the current value and
     326             : // status there.
     327             : // On entry. gCacheMutex must not be held. value must be
     328             : // included in the reference count of the object to which it points.
     329             : // On exit, value and status are changed to what was already in the cache if
     330             : // something was there and not in progress. Otherwise, value and status are left
     331             : // unchanged in which case they are placed in the cache on a best-effort basis.
     332             : // Caller must call removeRef() on value.
     333           0 : void UnifiedCache::_putIfAbsentAndGet(
     334             :         const CacheKeyBase &key,
     335             :         const SharedObject *&value,
     336             :         UErrorCode &status) const {
     337           0 :     Mutex lock(&gCacheMutex);
     338           0 :     const UHashElement *element = uhash_find(fHashtable, &key);
     339           0 :     if (element != NULL && !_inProgress(element)) {
     340           0 :         _fetch(element, value, status);
     341           0 :         return;
     342             :     }
     343           0 :     if (element == NULL) {
     344           0 :         UErrorCode putError = U_ZERO_ERROR;
     345             :         // best-effort basis only.
     346           0 :         _putNew(key, value, status, putError);
     347             :     } else {
     348           0 :         _put(element, value, status);
     349             :     }
     350             :     // Run an eviction slice. This will run even if we added a master entry
     351             :     // which doesn't increase the unused count, but that is still o.k
     352           0 :     _runEvictionSlice();
     353             : }
     354             : 
     355             : // Attempts to fetch value and status for key from cache.
     356             : // On entry, gCacheMutex must not be held value must be NULL and status must
     357             : // be U_ZERO_ERROR.
     358             : // On exit, either returns FALSE (In this
     359             : // case caller should try to create the object) or returns TRUE with value
     360             : // pointing to the fetched value and status set to fetched status. When
     361             : // FALSE is returned status may be set to failure if an in progress hash
     362             : // entry could not be made but value will remain unchanged. When TRUE is
     363             : // returned, caler must call removeRef() on value.
     364           0 : UBool UnifiedCache::_poll(
     365             :         const CacheKeyBase &key,
     366             :         const SharedObject *&value,
     367             :         UErrorCode &status) const {
     368           0 :     U_ASSERT(value == NULL);
     369           0 :     U_ASSERT(status == U_ZERO_ERROR);
     370           0 :     Mutex lock(&gCacheMutex);
     371           0 :     const UHashElement *element = uhash_find(fHashtable, &key);
     372           0 :     while (element != NULL && _inProgress(element)) {
     373           0 :         umtx_condWait(&gInProgressValueAddedCond, &gCacheMutex);
     374           0 :         element = uhash_find(fHashtable, &key);
     375             :     }
     376           0 :     if (element != NULL) {
     377           0 :         _fetch(element, value, status);
     378           0 :         return TRUE;
     379             :     }
     380           0 :     _putNew(key, gNoValue, U_ZERO_ERROR, status);
     381           0 :     return FALSE;
     382             : }
     383             : 
     384             : // Gets value out of cache.
     385             : // On entry. gCacheMutex must not be held. value must be NULL. status
     386             : // must be U_ZERO_ERROR.
     387             : // On exit. value and status set to what is in cache at key or on cache
     388             : // miss the key's createObject() is called and value and status are set to
     389             : // the result of that. In this latter case, best effort is made to add the
     390             : // value and status to the cache. If createObject() fails to create a value,
     391             : // gNoValue is stored in cache, and value is set to NULL. Caller must call
     392             : // removeRef on value if non NULL.
     393           0 : void UnifiedCache::_get(
     394             :         const CacheKeyBase &key,
     395             :         const SharedObject *&value,
     396             :         const void *creationContext,
     397             :         UErrorCode &status) const {
     398           0 :     U_ASSERT(value == NULL);
     399           0 :     U_ASSERT(status == U_ZERO_ERROR);
     400           0 :     if (_poll(key, value, status)) {
     401           0 :         if (value == gNoValue) {
     402           0 :             SharedObject::clearPtr(value);
     403             :         }
     404           0 :         return;
     405             :     }
     406           0 :     if (U_FAILURE(status)) {
     407           0 :         return;
     408             :     }
     409           0 :     value = key.createObject(creationContext, status);
     410           0 :     U_ASSERT(value == NULL || value->hasHardReferences());
     411           0 :     U_ASSERT(value != NULL || status != U_ZERO_ERROR);
     412           0 :     if (value == NULL) {
     413           0 :         SharedObject::copyPtr(gNoValue, value);
     414             :     }
     415           0 :     _putIfAbsentAndGet(key, value, status);
     416           0 :     if (value == gNoValue) {
     417           0 :         SharedObject::clearPtr(value);
     418             :     }
     419             : }
     420             : 
     421           0 : void UnifiedCache::decrementItemsInUseWithLockingAndEviction() const {
     422           0 :     Mutex mutex(&gCacheMutex);
     423           0 :     decrementItemsInUse();
     424           0 :     _runEvictionSlice();
     425           0 : }
     426             : 
     427           0 : void UnifiedCache::incrementItemsInUse() const {
     428           0 :     ++fItemsInUseCount;
     429           0 : }
     430             : 
     431           0 : void UnifiedCache::decrementItemsInUse() const {
     432           0 :     --fItemsInUseCount;
     433           0 : }
     434             : 
     435             : // Register a master cache entry.
     436             : // On entry, gCacheMutex must be held.
     437             : // On exit, items in use count incremented, entry is marked as a master
     438             : // entry, and value registered with cache so that subsequent calls to
     439             : // addRef() and removeRef() on it correctly updates items in use count
     440           0 : void UnifiedCache::_registerMaster(
     441             :         const CacheKeyBase *theKey, const SharedObject *value) const {
     442           0 :     theKey->fIsMaster = TRUE;
     443           0 :     ++fItemsInUseCount;
     444           0 :     value->registerWithCache(this);
     445           0 : }
     446             : 
     447             : // Store a value and error in given hash entry.
     448             : // On entry, gCacheMutex must be held. Hash entry element must be in progress.
     449             : // value must be non NULL.
     450             : // On Exit, soft reference added to value. value and status stored in hash
     451             : // entry. Soft reference removed from previous stored value. Waiting
     452             : // threads notified.
     453           0 : void UnifiedCache::_put(
     454             :         const UHashElement *element, 
     455             :         const SharedObject *value,
     456             :         const UErrorCode status) const {
     457           0 :     U_ASSERT(_inProgress(element));
     458           0 :     const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
     459           0 :     const SharedObject *oldValue = (const SharedObject *) element->value.pointer;
     460           0 :     theKey->fCreationStatus = status;
     461           0 :     if (value->noSoftReferences()) {
     462           0 :         _registerMaster(theKey, value);
     463             :     }
     464           0 :     value->addSoftRef();
     465           0 :     UHashElement *ptr = const_cast<UHashElement *>(element);
     466           0 :     ptr->value.pointer = (void *) value;
     467           0 :     oldValue->removeSoftRef();
     468             : 
     469             :     // Tell waiting threads that we replace in-progress status with
     470             :     // an error.
     471           0 :     umtx_condBroadcast(&gInProgressValueAddedCond);
     472           0 : }
     473             : 
     474             : void
     475           0 : UnifiedCache::copyPtr(const SharedObject *src, const SharedObject *&dest) {
     476           0 :     if(src != dest) {
     477           0 :         if(dest != NULL) {
     478           0 :             dest->removeRefWhileHoldingCacheLock();
     479             :         }
     480           0 :         dest = src;
     481           0 :         if(src != NULL) {
     482           0 :             src->addRefWhileHoldingCacheLock();
     483             :         }
     484             :     }
     485           0 : }
     486             : 
     487             : void
     488           0 : UnifiedCache::clearPtr(const SharedObject *&ptr) {
     489           0 :     if (ptr != NULL) {
     490           0 :         ptr->removeRefWhileHoldingCacheLock();
     491           0 :         ptr = NULL;
     492             :     }
     493           0 : }
     494             : 
     495             : 
     496             : // Fetch value and error code from a particular hash entry.
     497             : // On entry, gCacheMutex must be held. value must be either NULL or must be
     498             : // included in the ref count of the object to which it points.
     499             : // On exit, value and status set to what is in the hash entry. Caller must
     500             : // eventually call removeRef on value.
     501             : // If hash entry is in progress, value will be set to gNoValue and status will
     502             : // be set to U_ZERO_ERROR.
     503           0 : void UnifiedCache::_fetch(
     504             :         const UHashElement *element,
     505             :         const SharedObject *&value,
     506             :         UErrorCode &status) {
     507           0 :     const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
     508           0 :     status = theKey->fCreationStatus;
     509             : 
     510             :     // Since we have the cache lock, calling regular SharedObject methods
     511             :     // could cause us to deadlock on ourselves since they may need to lock
     512             :     // the cache mutex.
     513           0 :     UnifiedCache::copyPtr((const SharedObject *) element->value.pointer, value);
     514           0 : }
     515             : 
     516             : // Determine if given hash entry is in progress.
     517             : // On entry, gCacheMutex must be held.
     518           0 : UBool UnifiedCache::_inProgress(const UHashElement *element) {
     519           0 :     const SharedObject *value = NULL;
     520           0 :     UErrorCode status = U_ZERO_ERROR;
     521           0 :     _fetch(element, value, status);
     522           0 :     UBool result = _inProgress(value, status);
     523             : 
     524             :     // Since we have the cache lock, calling regular SharedObject methods
     525             :     // could cause us to deadlock on ourselves since they may need to lock
     526             :     // the cache mutex.
     527           0 :     UnifiedCache::clearPtr(value);
     528           0 :     return result;
     529             : }
     530             : 
     531             : // Determine if given hash entry is in progress.
     532             : // On entry, gCacheMutex must be held.
     533           0 : UBool UnifiedCache::_inProgress(
     534             :         const SharedObject *theValue, UErrorCode creationStatus) {
     535           0 :     return (theValue == gNoValue && creationStatus == U_ZERO_ERROR);
     536             : }
     537             : 
     538             : // Determine if given hash entry is eligible for eviction.
     539             : // On entry, gCacheMutex must be held.
     540           0 : UBool UnifiedCache::_isEvictable(const UHashElement *element) {
     541           0 :     const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
     542             :     const SharedObject *theValue =
     543           0 :             (const SharedObject *) element->value.pointer;
     544             : 
     545             :     // Entries that are under construction are never evictable
     546           0 :     if (_inProgress(theValue, theKey->fCreationStatus)) {
     547           0 :         return FALSE;
     548             :     }
     549             : 
     550             :     // We can evict entries that are either not a master or have just
     551             :     // one reference (The one reference being from the cache itself).
     552           0 :     return (!theKey->fIsMaster || (theValue->getSoftRefCount() == 1 && theValue->noHardReferences()));
     553             : }
     554             : 
     555             : U_NAMESPACE_END

Generated by: LCOV version 1.13