1*0e209d39SAndroid Build Coastguard Worker // © 2016 and later: Unicode, Inc. and others. 2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html 3*0e209d39SAndroid Build Coastguard Worker /* 4*0e209d39SAndroid Build Coastguard Worker ****************************************************************************** 5*0e209d39SAndroid Build Coastguard Worker * Copyright (C) 2015, International Business Machines Corporation and 6*0e209d39SAndroid Build Coastguard Worker * others. All Rights Reserved. 7*0e209d39SAndroid Build Coastguard Worker ****************************************************************************** 8*0e209d39SAndroid Build Coastguard Worker * 9*0e209d39SAndroid Build Coastguard Worker * File UNIFIEDCACHE.H - The ICU Unified cache. 10*0e209d39SAndroid Build Coastguard Worker ****************************************************************************** 11*0e209d39SAndroid Build Coastguard Worker */ 12*0e209d39SAndroid Build Coastguard Worker 13*0e209d39SAndroid Build Coastguard Worker #ifndef __UNIFIED_CACHE_H__ 14*0e209d39SAndroid Build Coastguard Worker #define __UNIFIED_CACHE_H__ 15*0e209d39SAndroid Build Coastguard Worker 16*0e209d39SAndroid Build Coastguard Worker #include "utypeinfo.h" // for 'typeid' to work 17*0e209d39SAndroid Build Coastguard Worker 18*0e209d39SAndroid Build Coastguard Worker #include "unicode/uobject.h" 19*0e209d39SAndroid Build Coastguard Worker #include "unicode/locid.h" 20*0e209d39SAndroid Build Coastguard Worker #include "sharedobject.h" 21*0e209d39SAndroid Build Coastguard Worker #include "unicode/unistr.h" 22*0e209d39SAndroid Build Coastguard Worker #include "cstring.h" 23*0e209d39SAndroid Build Coastguard Worker #include "ustr_imp.h" 24*0e209d39SAndroid Build Coastguard Worker 25*0e209d39SAndroid Build Coastguard Worker struct UHashtable; 26*0e209d39SAndroid Build Coastguard Worker struct UHashElement; 27*0e209d39SAndroid Build Coastguard Worker 28*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN 29*0e209d39SAndroid Build Coastguard Worker 30*0e209d39SAndroid Build Coastguard Worker class UnifiedCache; 31*0e209d39SAndroid Build Coastguard Worker 32*0e209d39SAndroid Build Coastguard Worker /** 33*0e209d39SAndroid Build Coastguard Worker * A base class for all cache keys. 34*0e209d39SAndroid Build Coastguard Worker */ 35*0e209d39SAndroid Build Coastguard Worker class U_COMMON_API CacheKeyBase : public UObject { 36*0e209d39SAndroid Build Coastguard Worker public: CacheKeyBase()37*0e209d39SAndroid Build Coastguard Worker CacheKeyBase() : fCreationStatus(U_ZERO_ERROR), fIsPrimary(false) {} 38*0e209d39SAndroid Build Coastguard Worker 39*0e209d39SAndroid Build Coastguard Worker /** 40*0e209d39SAndroid Build Coastguard Worker * Copy constructor. Needed to support cloning. 41*0e209d39SAndroid Build Coastguard Worker */ CacheKeyBase(const CacheKeyBase & other)42*0e209d39SAndroid Build Coastguard Worker CacheKeyBase(const CacheKeyBase &other) 43*0e209d39SAndroid Build Coastguard Worker : UObject(other), fCreationStatus(other.fCreationStatus), fIsPrimary(false) { } 44*0e209d39SAndroid Build Coastguard Worker virtual ~CacheKeyBase(); 45*0e209d39SAndroid Build Coastguard Worker 46*0e209d39SAndroid Build Coastguard Worker /** 47*0e209d39SAndroid Build Coastguard Worker * Returns the hash code for this object. 48*0e209d39SAndroid Build Coastguard Worker */ 49*0e209d39SAndroid Build Coastguard Worker virtual int32_t hashCode() const = 0; 50*0e209d39SAndroid Build Coastguard Worker 51*0e209d39SAndroid Build Coastguard Worker /** 52*0e209d39SAndroid Build Coastguard Worker * Clones this object polymorphically. Caller owns returned value. 53*0e209d39SAndroid Build Coastguard Worker */ 54*0e209d39SAndroid Build Coastguard Worker virtual CacheKeyBase *clone() const = 0; 55*0e209d39SAndroid Build Coastguard Worker 56*0e209d39SAndroid Build Coastguard Worker /** 57*0e209d39SAndroid Build Coastguard Worker * Create a new object for this key. Called by cache on cache miss. 58*0e209d39SAndroid Build Coastguard Worker * createObject must add a reference to the object it returns. Note 59*0e209d39SAndroid Build Coastguard Worker * that getting an object from the cache and returning it without calling 60*0e209d39SAndroid Build Coastguard Worker * removeRef on it satisfies this requirement. It can also return nullptr 61*0e209d39SAndroid Build Coastguard Worker * and set status to an error. 62*0e209d39SAndroid Build Coastguard Worker * 63*0e209d39SAndroid Build Coastguard Worker * @param creationContext the context in which the object is being 64*0e209d39SAndroid Build Coastguard Worker * created. May be nullptr. 65*0e209d39SAndroid Build Coastguard Worker * @param status Implementations can return a failure here. 66*0e209d39SAndroid Build Coastguard Worker * In addition, implementations may return a 67*0e209d39SAndroid Build Coastguard Worker * non nullptr object and set a warning status. 68*0e209d39SAndroid Build Coastguard Worker */ 69*0e209d39SAndroid Build Coastguard Worker virtual const SharedObject *createObject( 70*0e209d39SAndroid Build Coastguard Worker const void *creationContext, UErrorCode &status) const = 0; 71*0e209d39SAndroid Build Coastguard Worker 72*0e209d39SAndroid Build Coastguard Worker /** 73*0e209d39SAndroid Build Coastguard Worker * Writes a description of this key to buffer and returns buffer. Written 74*0e209d39SAndroid Build Coastguard Worker * description is nullptr terminated. 75*0e209d39SAndroid Build Coastguard Worker */ 76*0e209d39SAndroid Build Coastguard Worker virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0; 77*0e209d39SAndroid Build Coastguard Worker 78*0e209d39SAndroid Build Coastguard Worker friend inline bool operator==(const CacheKeyBase& lhs, 79*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase& rhs) { 80*0e209d39SAndroid Build Coastguard Worker return lhs.equals(rhs); 81*0e209d39SAndroid Build Coastguard Worker } 82*0e209d39SAndroid Build Coastguard Worker 83*0e209d39SAndroid Build Coastguard Worker friend inline bool operator!=(const CacheKeyBase& lhs, 84*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase& rhs) { 85*0e209d39SAndroid Build Coastguard Worker return !lhs.equals(rhs); 86*0e209d39SAndroid Build Coastguard Worker } 87*0e209d39SAndroid Build Coastguard Worker 88*0e209d39SAndroid Build Coastguard Worker protected: 89*0e209d39SAndroid Build Coastguard Worker virtual bool equals(const CacheKeyBase& other) const = 0; 90*0e209d39SAndroid Build Coastguard Worker 91*0e209d39SAndroid Build Coastguard Worker private: 92*0e209d39SAndroid Build Coastguard Worker mutable UErrorCode fCreationStatus; 93*0e209d39SAndroid Build Coastguard Worker mutable UBool fIsPrimary; 94*0e209d39SAndroid Build Coastguard Worker friend class UnifiedCache; 95*0e209d39SAndroid Build Coastguard Worker }; 96*0e209d39SAndroid Build Coastguard Worker 97*0e209d39SAndroid Build Coastguard Worker 98*0e209d39SAndroid Build Coastguard Worker 99*0e209d39SAndroid Build Coastguard Worker /** 100*0e209d39SAndroid Build Coastguard Worker * Templated version of CacheKeyBase. 101*0e209d39SAndroid Build Coastguard Worker * A key of type LocaleCacheKey<T> maps to a value of type T. 102*0e209d39SAndroid Build Coastguard Worker */ 103*0e209d39SAndroid Build Coastguard Worker template<typename T> 104*0e209d39SAndroid Build Coastguard Worker class CacheKey : public CacheKeyBase { 105*0e209d39SAndroid Build Coastguard Worker public: ~CacheKey()106*0e209d39SAndroid Build Coastguard Worker virtual ~CacheKey() { } 107*0e209d39SAndroid Build Coastguard Worker /** 108*0e209d39SAndroid Build Coastguard Worker * The template parameter, T, determines the hash code returned. 109*0e209d39SAndroid Build Coastguard Worker */ hashCode()110*0e209d39SAndroid Build Coastguard Worker virtual int32_t hashCode() const override { 111*0e209d39SAndroid Build Coastguard Worker const char *s = typeid(T).name(); 112*0e209d39SAndroid Build Coastguard Worker return ustr_hashCharsN(s, static_cast<int32_t>(uprv_strlen(s))); 113*0e209d39SAndroid Build Coastguard Worker } 114*0e209d39SAndroid Build Coastguard Worker 115*0e209d39SAndroid Build Coastguard Worker /** 116*0e209d39SAndroid Build Coastguard Worker * Use the value type, T, as the description. 117*0e209d39SAndroid Build Coastguard Worker */ writeDescription(char * buffer,int32_t bufLen)118*0e209d39SAndroid Build Coastguard Worker virtual char *writeDescription(char *buffer, int32_t bufLen) const override { 119*0e209d39SAndroid Build Coastguard Worker const char *s = typeid(T).name(); 120*0e209d39SAndroid Build Coastguard Worker uprv_strncpy(buffer, s, bufLen); 121*0e209d39SAndroid Build Coastguard Worker buffer[bufLen - 1] = 0; 122*0e209d39SAndroid Build Coastguard Worker return buffer; 123*0e209d39SAndroid Build Coastguard Worker } 124*0e209d39SAndroid Build Coastguard Worker 125*0e209d39SAndroid Build Coastguard Worker protected: 126*0e209d39SAndroid Build Coastguard Worker /** 127*0e209d39SAndroid Build Coastguard Worker * Two objects are equal if they are of the same type. 128*0e209d39SAndroid Build Coastguard Worker */ equals(const CacheKeyBase & other)129*0e209d39SAndroid Build Coastguard Worker virtual bool equals(const CacheKeyBase &other) const override { 130*0e209d39SAndroid Build Coastguard Worker return this == &other || typeid(*this) == typeid(other); 131*0e209d39SAndroid Build Coastguard Worker } 132*0e209d39SAndroid Build Coastguard Worker }; 133*0e209d39SAndroid Build Coastguard Worker 134*0e209d39SAndroid Build Coastguard Worker /** 135*0e209d39SAndroid Build Coastguard Worker * Cache key based on locale. 136*0e209d39SAndroid Build Coastguard Worker * A key of type LocaleCacheKey<T> maps to a value of type T. 137*0e209d39SAndroid Build Coastguard Worker */ 138*0e209d39SAndroid Build Coastguard Worker template<typename T> 139*0e209d39SAndroid Build Coastguard Worker class LocaleCacheKey : public CacheKey<T> { 140*0e209d39SAndroid Build Coastguard Worker protected: 141*0e209d39SAndroid Build Coastguard Worker Locale fLoc; equals(const CacheKeyBase & other)142*0e209d39SAndroid Build Coastguard Worker virtual bool equals(const CacheKeyBase &other) const override { 143*0e209d39SAndroid Build Coastguard Worker if (!CacheKey<T>::equals(other)) { 144*0e209d39SAndroid Build Coastguard Worker return false; 145*0e209d39SAndroid Build Coastguard Worker } 146*0e209d39SAndroid Build Coastguard Worker // We know this and other are of same class because equals() on 147*0e209d39SAndroid Build Coastguard Worker // CacheKey returned true. 148*0e209d39SAndroid Build Coastguard Worker return operator==(static_cast<const LocaleCacheKey<T> &>(other)); 149*0e209d39SAndroid Build Coastguard Worker } 150*0e209d39SAndroid Build Coastguard Worker public: LocaleCacheKey(const Locale & loc)151*0e209d39SAndroid Build Coastguard Worker LocaleCacheKey(const Locale &loc) : fLoc(loc) {} LocaleCacheKey(const LocaleCacheKey<T> & other)152*0e209d39SAndroid Build Coastguard Worker LocaleCacheKey(const LocaleCacheKey<T> &other) 153*0e209d39SAndroid Build Coastguard Worker : CacheKey<T>(other), fLoc(other.fLoc) { } ~LocaleCacheKey()154*0e209d39SAndroid Build Coastguard Worker virtual ~LocaleCacheKey() { } hashCode()155*0e209d39SAndroid Build Coastguard Worker virtual int32_t hashCode() const override { 156*0e209d39SAndroid Build Coastguard Worker return (int32_t)(37u * (uint32_t)CacheKey<T>::hashCode() + (uint32_t)fLoc.hashCode()); 157*0e209d39SAndroid Build Coastguard Worker } 158*0e209d39SAndroid Build Coastguard Worker inline bool operator == (const LocaleCacheKey<T> &other) const { 159*0e209d39SAndroid Build Coastguard Worker return fLoc == other.fLoc; 160*0e209d39SAndroid Build Coastguard Worker } clone()161*0e209d39SAndroid Build Coastguard Worker virtual CacheKeyBase *clone() const override { 162*0e209d39SAndroid Build Coastguard Worker return new LocaleCacheKey<T>(*this); 163*0e209d39SAndroid Build Coastguard Worker } 164*0e209d39SAndroid Build Coastguard Worker virtual const T *createObject( 165*0e209d39SAndroid Build Coastguard Worker const void *creationContext, UErrorCode &status) const override; 166*0e209d39SAndroid Build Coastguard Worker /** 167*0e209d39SAndroid Build Coastguard Worker * Use the locale id as the description. 168*0e209d39SAndroid Build Coastguard Worker */ writeDescription(char * buffer,int32_t bufLen)169*0e209d39SAndroid Build Coastguard Worker virtual char *writeDescription(char *buffer, int32_t bufLen) const override { 170*0e209d39SAndroid Build Coastguard Worker const char *s = fLoc.getName(); 171*0e209d39SAndroid Build Coastguard Worker uprv_strncpy(buffer, s, bufLen); 172*0e209d39SAndroid Build Coastguard Worker buffer[bufLen - 1] = 0; 173*0e209d39SAndroid Build Coastguard Worker return buffer; 174*0e209d39SAndroid Build Coastguard Worker } 175*0e209d39SAndroid Build Coastguard Worker 176*0e209d39SAndroid Build Coastguard Worker }; 177*0e209d39SAndroid Build Coastguard Worker 178*0e209d39SAndroid Build Coastguard Worker /** 179*0e209d39SAndroid Build Coastguard Worker * The unified cache. A singleton type. 180*0e209d39SAndroid Build Coastguard Worker * Design doc here: 181*0e209d39SAndroid Build Coastguard Worker * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing 182*0e209d39SAndroid Build Coastguard Worker */ 183*0e209d39SAndroid Build Coastguard Worker class U_COMMON_API UnifiedCache : public UnifiedCacheBase { 184*0e209d39SAndroid Build Coastguard Worker public: 185*0e209d39SAndroid Build Coastguard Worker /** 186*0e209d39SAndroid Build Coastguard Worker * @internal 187*0e209d39SAndroid Build Coastguard Worker * Do not call directly. Instead use UnifiedCache::getInstance() as 188*0e209d39SAndroid Build Coastguard Worker * there should be only one UnifiedCache in an application. 189*0e209d39SAndroid Build Coastguard Worker */ 190*0e209d39SAndroid Build Coastguard Worker UnifiedCache(UErrorCode &status); 191*0e209d39SAndroid Build Coastguard Worker 192*0e209d39SAndroid Build Coastguard Worker /** 193*0e209d39SAndroid Build Coastguard Worker * Return a pointer to the global cache instance. 194*0e209d39SAndroid Build Coastguard Worker */ 195*0e209d39SAndroid Build Coastguard Worker static UnifiedCache *getInstance(UErrorCode &status); 196*0e209d39SAndroid Build Coastguard Worker 197*0e209d39SAndroid Build Coastguard Worker /** 198*0e209d39SAndroid Build Coastguard Worker * Fetches a value from the cache by key. Equivalent to 199*0e209d39SAndroid Build Coastguard Worker * get(key, nullptr, ptr, status); 200*0e209d39SAndroid Build Coastguard Worker */ 201*0e209d39SAndroid Build Coastguard Worker template<typename T> get(const CacheKey<T> & key,const T * & ptr,UErrorCode & status)202*0e209d39SAndroid Build Coastguard Worker void get( 203*0e209d39SAndroid Build Coastguard Worker const CacheKey<T>& key, 204*0e209d39SAndroid Build Coastguard Worker const T *&ptr, 205*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const { 206*0e209d39SAndroid Build Coastguard Worker get(key, nullptr, ptr, status); 207*0e209d39SAndroid Build Coastguard Worker } 208*0e209d39SAndroid Build Coastguard Worker 209*0e209d39SAndroid Build Coastguard Worker /** 210*0e209d39SAndroid Build Coastguard Worker * Fetches value from the cache by key. 211*0e209d39SAndroid Build Coastguard Worker * 212*0e209d39SAndroid Build Coastguard Worker * @param key the cache key. 213*0e209d39SAndroid Build Coastguard Worker * @param creationContext passed verbatim to createObject method of key 214*0e209d39SAndroid Build Coastguard Worker * @param ptr On entry, ptr must be nullptr or be included if 215*0e209d39SAndroid Build Coastguard Worker * the reference count of the object it points 216*0e209d39SAndroid Build Coastguard Worker * to. On exit, ptr points to the fetched object 217*0e209d39SAndroid Build Coastguard Worker * from the cache or is left unchanged on 218*0e209d39SAndroid Build Coastguard Worker * failure. Caller must call removeRef on ptr 219*0e209d39SAndroid Build Coastguard Worker * if set to a non nullptr value. 220*0e209d39SAndroid Build Coastguard Worker * @param status Any error returned here. May be set to a 221*0e209d39SAndroid Build Coastguard Worker * warning value even if ptr is set. 222*0e209d39SAndroid Build Coastguard Worker */ 223*0e209d39SAndroid Build Coastguard Worker template<typename T> get(const CacheKey<T> & key,const void * creationContext,const T * & ptr,UErrorCode & status)224*0e209d39SAndroid Build Coastguard Worker void get( 225*0e209d39SAndroid Build Coastguard Worker const CacheKey<T>& key, 226*0e209d39SAndroid Build Coastguard Worker const void *creationContext, 227*0e209d39SAndroid Build Coastguard Worker const T *&ptr, 228*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const { 229*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(status)) { 230*0e209d39SAndroid Build Coastguard Worker return; 231*0e209d39SAndroid Build Coastguard Worker } 232*0e209d39SAndroid Build Coastguard Worker UErrorCode creationStatus = U_ZERO_ERROR; 233*0e209d39SAndroid Build Coastguard Worker const SharedObject *value = nullptr; 234*0e209d39SAndroid Build Coastguard Worker _get(key, value, creationContext, creationStatus); 235*0e209d39SAndroid Build Coastguard Worker const T *tvalue = (const T *) value; 236*0e209d39SAndroid Build Coastguard Worker if (U_SUCCESS(creationStatus)) { 237*0e209d39SAndroid Build Coastguard Worker SharedObject::copyPtr(tvalue, ptr); 238*0e209d39SAndroid Build Coastguard Worker } 239*0e209d39SAndroid Build Coastguard Worker SharedObject::clearPtr(tvalue); 240*0e209d39SAndroid Build Coastguard Worker // Take care not to overwrite a warning status passed in with 241*0e209d39SAndroid Build Coastguard Worker // another warning or U_ZERO_ERROR. 242*0e209d39SAndroid Build Coastguard Worker if (status == U_ZERO_ERROR || U_FAILURE(creationStatus)) { 243*0e209d39SAndroid Build Coastguard Worker status = creationStatus; 244*0e209d39SAndroid Build Coastguard Worker } 245*0e209d39SAndroid Build Coastguard Worker } 246*0e209d39SAndroid Build Coastguard Worker 247*0e209d39SAndroid Build Coastguard Worker #ifdef UNIFIED_CACHE_DEBUG 248*0e209d39SAndroid Build Coastguard Worker /** 249*0e209d39SAndroid Build Coastguard Worker * Dumps the contents of this cache to standard error. Used for testing of 250*0e209d39SAndroid Build Coastguard Worker * cache only. 251*0e209d39SAndroid Build Coastguard Worker */ 252*0e209d39SAndroid Build Coastguard Worker void dumpContents() const; 253*0e209d39SAndroid Build Coastguard Worker #endif 254*0e209d39SAndroid Build Coastguard Worker 255*0e209d39SAndroid Build Coastguard Worker /** 256*0e209d39SAndroid Build Coastguard Worker * Convenience method to get a value of type T from cache for a 257*0e209d39SAndroid Build Coastguard Worker * particular locale with creationContext == nullptr. 258*0e209d39SAndroid Build Coastguard Worker * @param loc the locale 259*0e209d39SAndroid Build Coastguard Worker * @param ptr On entry, must be nullptr or included in the ref count 260*0e209d39SAndroid Build Coastguard Worker * of the object to which it points. 261*0e209d39SAndroid Build Coastguard Worker * On exit, fetched value stored here or is left 262*0e209d39SAndroid Build Coastguard Worker * unchanged on failure. Caller must call removeRef on 263*0e209d39SAndroid Build Coastguard Worker * ptr if set to a non nullptr value. 264*0e209d39SAndroid Build Coastguard Worker * @param status Any error returned here. May be set to a 265*0e209d39SAndroid Build Coastguard Worker * warning value even if ptr is set. 266*0e209d39SAndroid Build Coastguard Worker */ 267*0e209d39SAndroid Build Coastguard Worker template<typename T> getByLocale(const Locale & loc,const T * & ptr,UErrorCode & status)268*0e209d39SAndroid Build Coastguard Worker static void getByLocale( 269*0e209d39SAndroid Build Coastguard Worker const Locale &loc, const T *&ptr, UErrorCode &status) { 270*0e209d39SAndroid Build Coastguard Worker const UnifiedCache *cache = getInstance(status); 271*0e209d39SAndroid Build Coastguard Worker if (U_FAILURE(status)) { 272*0e209d39SAndroid Build Coastguard Worker return; 273*0e209d39SAndroid Build Coastguard Worker } 274*0e209d39SAndroid Build Coastguard Worker cache->get(LocaleCacheKey<T>(loc), ptr, status); 275*0e209d39SAndroid Build Coastguard Worker } 276*0e209d39SAndroid Build Coastguard Worker 277*0e209d39SAndroid Build Coastguard Worker #ifdef UNIFIED_CACHE_DEBUG 278*0e209d39SAndroid Build Coastguard Worker /** 279*0e209d39SAndroid Build Coastguard Worker * Dumps the cache contents to stderr. For testing only. 280*0e209d39SAndroid Build Coastguard Worker */ 281*0e209d39SAndroid Build Coastguard Worker static void dump(); 282*0e209d39SAndroid Build Coastguard Worker #endif 283*0e209d39SAndroid Build Coastguard Worker 284*0e209d39SAndroid Build Coastguard Worker /** 285*0e209d39SAndroid Build Coastguard Worker * Returns the number of keys in this cache. For testing only. 286*0e209d39SAndroid Build Coastguard Worker */ 287*0e209d39SAndroid Build Coastguard Worker int32_t keyCount() const; 288*0e209d39SAndroid Build Coastguard Worker 289*0e209d39SAndroid Build Coastguard Worker /** 290*0e209d39SAndroid Build Coastguard Worker * Removes any values from cache that are not referenced outside 291*0e209d39SAndroid Build Coastguard Worker * the cache. 292*0e209d39SAndroid Build Coastguard Worker */ 293*0e209d39SAndroid Build Coastguard Worker void flush() const; 294*0e209d39SAndroid Build Coastguard Worker 295*0e209d39SAndroid Build Coastguard Worker /** 296*0e209d39SAndroid Build Coastguard Worker * Configures at what point eviction of unused entries will begin. 297*0e209d39SAndroid Build Coastguard Worker * Eviction is triggered whenever the number of evictable keys exceeds 298*0e209d39SAndroid Build Coastguard Worker * BOTH count AND (number of in-use items) * (percentageOfInUseItems / 100). 299*0e209d39SAndroid Build Coastguard Worker * Once the number of unused entries drops below one of these, 300*0e209d39SAndroid Build Coastguard Worker * eviction ceases. Because eviction happens incrementally, 301*0e209d39SAndroid Build Coastguard Worker * the actual unused entry count may exceed both these numbers 302*0e209d39SAndroid Build Coastguard Worker * from time to time. 303*0e209d39SAndroid Build Coastguard Worker * 304*0e209d39SAndroid Build Coastguard Worker * A cache entry is defined as unused if it is not essential to guarantee 305*0e209d39SAndroid Build Coastguard Worker * that for a given key X, the cache returns the same reference to the 306*0e209d39SAndroid Build Coastguard Worker * same value as long as the client already holds a reference to that 307*0e209d39SAndroid Build Coastguard Worker * value. 308*0e209d39SAndroid Build Coastguard Worker * 309*0e209d39SAndroid Build Coastguard Worker * If this method is never called, the default settings are 1000 and 100%. 310*0e209d39SAndroid Build Coastguard Worker * 311*0e209d39SAndroid Build Coastguard Worker * Although this method is thread-safe, it is designed to be called at 312*0e209d39SAndroid Build Coastguard Worker * application startup. If it is called in the middle of execution, it 313*0e209d39SAndroid Build Coastguard Worker * will have no immediate effect on the cache. However over time, the 314*0e209d39SAndroid Build Coastguard Worker * cache will perform eviction slices in an attempt to honor the new 315*0e209d39SAndroid Build Coastguard Worker * settings. 316*0e209d39SAndroid Build Coastguard Worker * 317*0e209d39SAndroid Build Coastguard Worker * If a client already holds references to many different unique values 318*0e209d39SAndroid Build Coastguard Worker * in the cache such that the number of those unique values far exceeds 319*0e209d39SAndroid Build Coastguard Worker * "count" then the cache may not be able to maintain this maximum. 320*0e209d39SAndroid Build Coastguard Worker * However, if this happens, the cache still guarantees that the number of 321*0e209d39SAndroid Build Coastguard Worker * unused entries will remain only a small percentage of the total cache 322*0e209d39SAndroid Build Coastguard Worker * size. 323*0e209d39SAndroid Build Coastguard Worker * 324*0e209d39SAndroid Build Coastguard Worker * If the parameters passed are negative, setEvctionPolicy sets status to 325*0e209d39SAndroid Build Coastguard Worker * U_ILLEGAL_ARGUMENT_ERROR. 326*0e209d39SAndroid Build Coastguard Worker */ 327*0e209d39SAndroid Build Coastguard Worker void setEvictionPolicy( 328*0e209d39SAndroid Build Coastguard Worker int32_t count, int32_t percentageOfInUseItems, UErrorCode &status); 329*0e209d39SAndroid Build Coastguard Worker 330*0e209d39SAndroid Build Coastguard Worker 331*0e209d39SAndroid Build Coastguard Worker /** 332*0e209d39SAndroid Build Coastguard Worker * Returns how many entries have been auto evicted during the lifetime 333*0e209d39SAndroid Build Coastguard Worker * of this cache. This only includes auto evicted entries, not 334*0e209d39SAndroid Build Coastguard Worker * entries evicted because of a call to flush(). 335*0e209d39SAndroid Build Coastguard Worker */ 336*0e209d39SAndroid Build Coastguard Worker int64_t autoEvictedCount() const; 337*0e209d39SAndroid Build Coastguard Worker 338*0e209d39SAndroid Build Coastguard Worker /** 339*0e209d39SAndroid Build Coastguard Worker * Returns the unused entry count in this cache. For testing only, 340*0e209d39SAndroid Build Coastguard Worker * Regular clients will not need this. 341*0e209d39SAndroid Build Coastguard Worker */ 342*0e209d39SAndroid Build Coastguard Worker int32_t unusedCount() const; 343*0e209d39SAndroid Build Coastguard Worker 344*0e209d39SAndroid Build Coastguard Worker virtual void handleUnreferencedObject() const override; 345*0e209d39SAndroid Build Coastguard Worker virtual ~UnifiedCache(); 346*0e209d39SAndroid Build Coastguard Worker 347*0e209d39SAndroid Build Coastguard Worker private: 348*0e209d39SAndroid Build Coastguard Worker UHashtable *fHashtable; 349*0e209d39SAndroid Build Coastguard Worker mutable int32_t fEvictPos; 350*0e209d39SAndroid Build Coastguard Worker mutable int32_t fNumValuesTotal; 351*0e209d39SAndroid Build Coastguard Worker mutable int32_t fNumValuesInUse; 352*0e209d39SAndroid Build Coastguard Worker int32_t fMaxUnused; 353*0e209d39SAndroid Build Coastguard Worker int32_t fMaxPercentageOfInUse; 354*0e209d39SAndroid Build Coastguard Worker mutable int64_t fAutoEvictedCount; 355*0e209d39SAndroid Build Coastguard Worker SharedObject *fNoValue; 356*0e209d39SAndroid Build Coastguard Worker 357*0e209d39SAndroid Build Coastguard Worker UnifiedCache(const UnifiedCache &other) = delete; 358*0e209d39SAndroid Build Coastguard Worker UnifiedCache &operator=(const UnifiedCache &other) = delete; 359*0e209d39SAndroid Build Coastguard Worker 360*0e209d39SAndroid Build Coastguard Worker /** 361*0e209d39SAndroid Build Coastguard Worker * Flushes the contents of the cache. If cache values hold references to other 362*0e209d39SAndroid Build Coastguard Worker * cache values then _flush should be called in a loop until it returns false. 363*0e209d39SAndroid Build Coastguard Worker * 364*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 365*0e209d39SAndroid Build Coastguard Worker * On exit, those values with are evictable are flushed. 366*0e209d39SAndroid Build Coastguard Worker * 367*0e209d39SAndroid Build Coastguard Worker * @param all if false flush evictable items only, which are those with no external 368*0e209d39SAndroid Build Coastguard Worker * references, plus those that can be safely recreated.<br> 369*0e209d39SAndroid Build Coastguard Worker * if true, flush all elements. Any values (sharedObjects) with remaining 370*0e209d39SAndroid Build Coastguard Worker * hard (external) references are not deleted, but are detached from 371*0e209d39SAndroid Build Coastguard Worker * the cache, so that a subsequent removeRefs can delete them. 372*0e209d39SAndroid Build Coastguard Worker * _flush is not thread safe when all is true. 373*0e209d39SAndroid Build Coastguard Worker * @return true if any value in cache was flushed or false otherwise. 374*0e209d39SAndroid Build Coastguard Worker */ 375*0e209d39SAndroid Build Coastguard Worker UBool _flush(UBool all) const; 376*0e209d39SAndroid Build Coastguard Worker 377*0e209d39SAndroid Build Coastguard Worker /** 378*0e209d39SAndroid Build Coastguard Worker * Gets value out of cache. 379*0e209d39SAndroid Build Coastguard Worker * On entry. gCacheMutex must not be held. value must be nullptr. status 380*0e209d39SAndroid Build Coastguard Worker * must be U_ZERO_ERROR. 381*0e209d39SAndroid Build Coastguard Worker * On exit. value and status set to what is in cache at key or on cache 382*0e209d39SAndroid Build Coastguard Worker * miss the key's createObject() is called and value and status are set to 383*0e209d39SAndroid Build Coastguard Worker * the result of that. In this latter case, best effort is made to add the 384*0e209d39SAndroid Build Coastguard Worker * value and status to the cache. If createObject() fails to create a value, 385*0e209d39SAndroid Build Coastguard Worker * fNoValue is stored in cache, and value is set to nullptr. Caller must call 386*0e209d39SAndroid Build Coastguard Worker * removeRef on value if non nullptr. 387*0e209d39SAndroid Build Coastguard Worker */ 388*0e209d39SAndroid Build Coastguard Worker void _get( 389*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase &key, 390*0e209d39SAndroid Build Coastguard Worker const SharedObject *&value, 391*0e209d39SAndroid Build Coastguard Worker const void *creationContext, 392*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const; 393*0e209d39SAndroid Build Coastguard Worker 394*0e209d39SAndroid Build Coastguard Worker /** 395*0e209d39SAndroid Build Coastguard Worker * Attempts to fetch value and status for key from cache. 396*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must not be held value must be nullptr and status must 397*0e209d39SAndroid Build Coastguard Worker * be U_ZERO_ERROR. 398*0e209d39SAndroid Build Coastguard Worker * On exit, either returns false (In this 399*0e209d39SAndroid Build Coastguard Worker * case caller should try to create the object) or returns true with value 400*0e209d39SAndroid Build Coastguard Worker * pointing to the fetched value and status set to fetched status. When 401*0e209d39SAndroid Build Coastguard Worker * false is returned status may be set to failure if an in progress hash 402*0e209d39SAndroid Build Coastguard Worker * entry could not be made but value will remain unchanged. When true is 403*0e209d39SAndroid Build Coastguard Worker * returned, caller must call removeRef() on value. 404*0e209d39SAndroid Build Coastguard Worker */ 405*0e209d39SAndroid Build Coastguard Worker UBool _poll( 406*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase &key, 407*0e209d39SAndroid Build Coastguard Worker const SharedObject *&value, 408*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const; 409*0e209d39SAndroid Build Coastguard Worker 410*0e209d39SAndroid Build Coastguard Worker /** 411*0e209d39SAndroid Build Coastguard Worker * Places a new value and creationStatus in the cache for the given key. 412*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. key must not exist in the cache. 413*0e209d39SAndroid Build Coastguard Worker * On exit, value and creation status placed under key. Soft reference added 414*0e209d39SAndroid Build Coastguard Worker * to value on successful add. On error sets status. 415*0e209d39SAndroid Build Coastguard Worker */ 416*0e209d39SAndroid Build Coastguard Worker void _putNew( 417*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase &key, 418*0e209d39SAndroid Build Coastguard Worker const SharedObject *value, 419*0e209d39SAndroid Build Coastguard Worker const UErrorCode creationStatus, 420*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const; 421*0e209d39SAndroid Build Coastguard Worker 422*0e209d39SAndroid Build Coastguard Worker /** 423*0e209d39SAndroid Build Coastguard Worker * Places value and status at key if there is no value at key or if cache 424*0e209d39SAndroid Build Coastguard Worker * entry for key is in progress. Otherwise, it leaves the current value and 425*0e209d39SAndroid Build Coastguard Worker * status there. 426*0e209d39SAndroid Build Coastguard Worker * 427*0e209d39SAndroid Build Coastguard Worker * On entry. gCacheMutex must not be held. Value must be 428*0e209d39SAndroid Build Coastguard Worker * included in the reference count of the object to which it points. 429*0e209d39SAndroid Build Coastguard Worker * 430*0e209d39SAndroid Build Coastguard Worker * On exit, value and status are changed to what was already in the cache if 431*0e209d39SAndroid Build Coastguard Worker * something was there and not in progress. Otherwise, value and status are left 432*0e209d39SAndroid Build Coastguard Worker * unchanged in which case they are placed in the cache on a best-effort basis. 433*0e209d39SAndroid Build Coastguard Worker * Caller must call removeRef() on value. 434*0e209d39SAndroid Build Coastguard Worker */ 435*0e209d39SAndroid Build Coastguard Worker void _putIfAbsentAndGet( 436*0e209d39SAndroid Build Coastguard Worker const CacheKeyBase &key, 437*0e209d39SAndroid Build Coastguard Worker const SharedObject *&value, 438*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const; 439*0e209d39SAndroid Build Coastguard Worker 440*0e209d39SAndroid Build Coastguard Worker /** 441*0e209d39SAndroid Build Coastguard Worker * Returns the next element in the cache round robin style. 442*0e209d39SAndroid Build Coastguard Worker * Returns nullptr if the cache is empty. 443*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 444*0e209d39SAndroid Build Coastguard Worker */ 445*0e209d39SAndroid Build Coastguard Worker const UHashElement *_nextElement() const; 446*0e209d39SAndroid Build Coastguard Worker 447*0e209d39SAndroid Build Coastguard Worker /** 448*0e209d39SAndroid Build Coastguard Worker * Return the number of cache items that would need to be evicted 449*0e209d39SAndroid Build Coastguard Worker * to bring usage into conformance with eviction policy. 450*0e209d39SAndroid Build Coastguard Worker * 451*0e209d39SAndroid Build Coastguard Worker * An item corresponds to an entry in the hash table, a hash table element. 452*0e209d39SAndroid Build Coastguard Worker * 453*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 454*0e209d39SAndroid Build Coastguard Worker */ 455*0e209d39SAndroid Build Coastguard Worker int32_t _computeCountOfItemsToEvict() const; 456*0e209d39SAndroid Build Coastguard Worker 457*0e209d39SAndroid Build Coastguard Worker /** 458*0e209d39SAndroid Build Coastguard Worker * Run an eviction slice. 459*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 460*0e209d39SAndroid Build Coastguard Worker * _runEvictionSlice runs a slice of the evict pipeline by examining the next 461*0e209d39SAndroid Build Coastguard Worker * 10 entries in the cache round robin style evicting them if they are eligible. 462*0e209d39SAndroid Build Coastguard Worker */ 463*0e209d39SAndroid Build Coastguard Worker void _runEvictionSlice() const; 464*0e209d39SAndroid Build Coastguard Worker 465*0e209d39SAndroid Build Coastguard Worker /** 466*0e209d39SAndroid Build Coastguard Worker * Register a primary cache entry. A primary key is the first key to create 467*0e209d39SAndroid Build Coastguard Worker * a given SharedObject value. Subsequent keys whose create function 468*0e209d39SAndroid Build Coastguard Worker * produce references to an already existing SharedObject are not primary - 469*0e209d39SAndroid Build Coastguard Worker * they can be evicted and subsequently recreated. 470*0e209d39SAndroid Build Coastguard Worker * 471*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 472*0e209d39SAndroid Build Coastguard Worker * On exit, items in use count incremented, entry is marked as a primary 473*0e209d39SAndroid Build Coastguard Worker * entry, and value registered with cache so that subsequent calls to 474*0e209d39SAndroid Build Coastguard Worker * addRef() and removeRef() on it correctly interact with the cache. 475*0e209d39SAndroid Build Coastguard Worker */ 476*0e209d39SAndroid Build Coastguard Worker void _registerPrimary(const CacheKeyBase *theKey, const SharedObject *value) const; 477*0e209d39SAndroid Build Coastguard Worker 478*0e209d39SAndroid Build Coastguard Worker /** 479*0e209d39SAndroid Build Coastguard Worker * Store a value and creation error status in given hash entry. 480*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. Hash entry element must be in progress. 481*0e209d39SAndroid Build Coastguard Worker * value must be non nullptr. 482*0e209d39SAndroid Build Coastguard Worker * On Exit, soft reference added to value. value and status stored in hash 483*0e209d39SAndroid Build Coastguard Worker * entry. Soft reference removed from previous stored value. Waiting 484*0e209d39SAndroid Build Coastguard Worker * threads notified. 485*0e209d39SAndroid Build Coastguard Worker */ 486*0e209d39SAndroid Build Coastguard Worker void _put( 487*0e209d39SAndroid Build Coastguard Worker const UHashElement *element, 488*0e209d39SAndroid Build Coastguard Worker const SharedObject *value, 489*0e209d39SAndroid Build Coastguard Worker const UErrorCode status) const; 490*0e209d39SAndroid Build Coastguard Worker /** 491*0e209d39SAndroid Build Coastguard Worker * Remove a soft reference, and delete the SharedObject if no references remain. 492*0e209d39SAndroid Build Coastguard Worker * To be used from within the UnifiedCache implementation only. 493*0e209d39SAndroid Build Coastguard Worker * gCacheMutex must be held by caller. 494*0e209d39SAndroid Build Coastguard Worker * @param value the SharedObject to be acted on. 495*0e209d39SAndroid Build Coastguard Worker */ 496*0e209d39SAndroid Build Coastguard Worker void removeSoftRef(const SharedObject *value) const; 497*0e209d39SAndroid Build Coastguard Worker 498*0e209d39SAndroid Build Coastguard Worker /** 499*0e209d39SAndroid Build Coastguard Worker * Increment the hard reference count of the given SharedObject. 500*0e209d39SAndroid Build Coastguard Worker * gCacheMutex must be held by the caller. 501*0e209d39SAndroid Build Coastguard Worker * Update numValuesEvictable on transitions between zero and one reference. 502*0e209d39SAndroid Build Coastguard Worker * 503*0e209d39SAndroid Build Coastguard Worker * @param value The SharedObject to be referenced. 504*0e209d39SAndroid Build Coastguard Worker * @return the hard reference count after the addition. 505*0e209d39SAndroid Build Coastguard Worker */ 506*0e209d39SAndroid Build Coastguard Worker int32_t addHardRef(const SharedObject *value) const; 507*0e209d39SAndroid Build Coastguard Worker 508*0e209d39SAndroid Build Coastguard Worker /** 509*0e209d39SAndroid Build Coastguard Worker * Decrement the hard reference count of the given SharedObject. 510*0e209d39SAndroid Build Coastguard Worker * gCacheMutex must be held by the caller. 511*0e209d39SAndroid Build Coastguard Worker * Update numValuesEvictable on transitions between one and zero reference. 512*0e209d39SAndroid Build Coastguard Worker * 513*0e209d39SAndroid Build Coastguard Worker * @param value The SharedObject to be referenced. 514*0e209d39SAndroid Build Coastguard Worker * @return the hard reference count after the removal. 515*0e209d39SAndroid Build Coastguard Worker */ 516*0e209d39SAndroid Build Coastguard Worker int32_t removeHardRef(const SharedObject *value) const; 517*0e209d39SAndroid Build Coastguard Worker 518*0e209d39SAndroid Build Coastguard Worker 519*0e209d39SAndroid Build Coastguard Worker #ifdef UNIFIED_CACHE_DEBUG 520*0e209d39SAndroid Build Coastguard Worker void _dumpContents() const; 521*0e209d39SAndroid Build Coastguard Worker #endif 522*0e209d39SAndroid Build Coastguard Worker 523*0e209d39SAndroid Build Coastguard Worker /** 524*0e209d39SAndroid Build Coastguard Worker * Fetch value and error code from a particular hash entry. 525*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. value must be either nullptr or must be 526*0e209d39SAndroid Build Coastguard Worker * included in the ref count of the object to which it points. 527*0e209d39SAndroid Build Coastguard Worker * On exit, value and status set to what is in the hash entry. Caller must 528*0e209d39SAndroid Build Coastguard Worker * eventually call removeRef on value. 529*0e209d39SAndroid Build Coastguard Worker * If hash entry is in progress, value will be set to gNoValue and status will 530*0e209d39SAndroid Build Coastguard Worker * be set to U_ZERO_ERROR. 531*0e209d39SAndroid Build Coastguard Worker */ 532*0e209d39SAndroid Build Coastguard Worker void _fetch(const UHashElement *element, const SharedObject *&value, 533*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) const; 534*0e209d39SAndroid Build Coastguard Worker 535*0e209d39SAndroid Build Coastguard Worker /** 536*0e209d39SAndroid Build Coastguard Worker * Determine if given hash entry is in progress. 537*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 538*0e209d39SAndroid Build Coastguard Worker */ 539*0e209d39SAndroid Build Coastguard Worker UBool _inProgress(const UHashElement *element) const; 540*0e209d39SAndroid Build Coastguard Worker 541*0e209d39SAndroid Build Coastguard Worker /** 542*0e209d39SAndroid Build Coastguard Worker * Determine if given hash entry is in progress. 543*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 544*0e209d39SAndroid Build Coastguard Worker */ 545*0e209d39SAndroid Build Coastguard Worker UBool _inProgress(const SharedObject *theValue, UErrorCode creationStatus) const; 546*0e209d39SAndroid Build Coastguard Worker 547*0e209d39SAndroid Build Coastguard Worker /** 548*0e209d39SAndroid Build Coastguard Worker * Determine if given hash entry is eligible for eviction. 549*0e209d39SAndroid Build Coastguard Worker * On entry, gCacheMutex must be held. 550*0e209d39SAndroid Build Coastguard Worker */ 551*0e209d39SAndroid Build Coastguard Worker UBool _isEvictable(const UHashElement *element) const; 552*0e209d39SAndroid Build Coastguard Worker }; 553*0e209d39SAndroid Build Coastguard Worker 554*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END 555*0e209d39SAndroid Build Coastguard Worker 556*0e209d39SAndroid Build Coastguard Worker #endif 557