2 ******************************************************************************
3 * Copyright (C) 2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ******************************************************************************
7 * File UNIFIEDCACHE.H - The ICU Unified cache.
8 ******************************************************************************
11 #ifndef __UNIFIED_CACHE_H__
12 #define __UNIFIED_CACHE_H__
14 #include "utypeinfo.h" // for 'typeid' to work
16 #include "unicode/uobject.h"
17 #include "unicode/locid.h"
18 #include "sharedobject.h"
19 #include "unicode/unistr.h"
31 * A base class for all cache keys.
33 class U_COMMON_API CacheKeyBase
: public UObject
{
35 CacheKeyBase() : fCreationStatus(U_ZERO_ERROR
), fIsMaster(FALSE
) {}
38 * Copy constructor. Needed to support cloning.
40 CacheKeyBase(const CacheKeyBase
&other
)
41 : UObject(other
), fCreationStatus(other
.fCreationStatus
), fIsMaster(FALSE
) { }
42 virtual ~CacheKeyBase();
45 * Returns the hash code for this object.
47 virtual int32_t hashCode() const = 0;
50 * Clones this object polymorphically. Caller owns returned value.
52 virtual CacheKeyBase
*clone() const = 0;
57 virtual UBool
operator == (const CacheKeyBase
&other
) const = 0;
60 * Create a new object for this key. Called by cache on cache miss.
61 * createObject must add a reference to the object it returns. Note
62 * that getting an object from the cache and returning it without calling
63 * removeRef on it satisfies this requirement. It can also return NULL
64 * and set status to an error.
66 * @param creationContext the context in which the object is being
67 * created. May be NULL.
68 * @param status Implementations can return a failure here.
69 * In addition, implementations may return a
70 * non NULL object and set a warning status.
72 virtual const SharedObject
*createObject(
73 const void *creationContext
, UErrorCode
&status
) const = 0;
76 * Writes a description of this key to buffer and returns buffer. Written
77 * description is NULL terminated.
79 virtual char *writeDescription(char *buffer
, int32_t bufSize
) const = 0;
82 * Inequality operator.
84 UBool
operator != (const CacheKeyBase
&other
) const {
85 return !(*this == other
);
88 mutable UErrorCode fCreationStatus
;
89 mutable UBool fIsMaster
;
90 friend class UnifiedCache
;
96 * Templated version of CacheKeyBase.
97 * A key of type LocaleCacheKey<T> maps to a value of type T.
100 class CacheKey
: public CacheKeyBase
{
102 virtual ~CacheKey() { }
104 * The template parameter, T, determines the hash code returned.
106 virtual int32_t hashCode() const {
107 const char *s
= typeid(T
).name();
108 return ustr_hashCharsN(s
, uprv_strlen(s
));
112 * Use the value type, T, as the description.
114 virtual char *writeDescription(char *buffer
, int32_t bufLen
) const {
115 const char *s
= typeid(T
).name();
116 uprv_strncpy(buffer
, s
, bufLen
);
117 buffer
[bufLen
- 1] = 0;
122 * Two objects are equal if they are of the same type.
124 virtual UBool
operator == (const CacheKeyBase
&other
) const {
125 return typeid(*this) == typeid(other
);
130 * Cache key based on locale.
131 * A key of type LocaleCacheKey<T> maps to a value of type T.
134 class LocaleCacheKey
: public CacheKey
<T
> {
138 LocaleCacheKey(const Locale
&loc
) : fLoc(loc
) {};
139 LocaleCacheKey(const LocaleCacheKey
<T
> &other
)
140 : CacheKey
<T
>(other
), fLoc(other
.fLoc
) { }
141 virtual ~LocaleCacheKey() { }
142 virtual int32_t hashCode() const {
143 return 37 *CacheKey
<T
>::hashCode() + fLoc
.hashCode();
145 virtual UBool
operator == (const CacheKeyBase
&other
) const {
147 if (this == &other
) {
150 if (!CacheKey
<T
>::operator == (other
)) {
153 // We know this and other are of same class because operator== on
154 // CacheKey returned true.
155 const LocaleCacheKey
<T
> *fOther
=
156 static_cast<const LocaleCacheKey
<T
> *>(&other
);
157 return fLoc
== fOther
->fLoc
;
159 virtual CacheKeyBase
*clone() const {
160 return new LocaleCacheKey
<T
>(*this);
162 virtual const T
*createObject(
163 const void *creationContext
, UErrorCode
&status
) const;
165 * Use the locale id as the description.
167 virtual char *writeDescription(char *buffer
, int32_t bufLen
) const {
168 const char *s
= fLoc
.getName();
169 uprv_strncpy(buffer
, s
, bufLen
);
170 buffer
[bufLen
- 1] = 0;
177 * The unified cache. A singleton type.
179 * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing
181 class U_COMMON_API UnifiedCache
: public UnifiedCacheBase
{
185 * Do not call directly. Instead use UnifiedCache::getInstance() as
186 * there should be only one UnifiedCache in an application.
188 UnifiedCache(UErrorCode
&status
);
191 * Returns the cache instance.
193 static UnifiedCache
*getInstance(UErrorCode
&status
);
196 * Fetches a value from the cache by key. Equivalent to
197 * get(key, NULL, ptr, status);
201 const CacheKey
<T
>& key
,
203 UErrorCode
&status
) const {
204 get(key
, NULL
, ptr
, status
);
208 * Fetches value from the cache by key.
210 * @param key the cache key.
211 * @param creationContext passed verbatim to createObject method of key
212 * @param ptr On entry, ptr must be NULL or be included if
213 * the reference count of the object it points
214 * to. On exit, ptr points to the fetched object
215 * from the cache or is left unchanged on
216 * failure. Caller must call removeRef on ptr
217 * if set to a non NULL value.
218 * @param status Any error returned here. May be set to a
219 * warning value even if ptr is set.
223 const CacheKey
<T
>& key
,
224 const void *creationContext
,
226 UErrorCode
&status
) const {
227 if (U_FAILURE(status
)) {
230 UErrorCode creationStatus
= U_ZERO_ERROR
;
231 const SharedObject
*value
= NULL
;
232 _get(key
, value
, creationContext
, creationStatus
);
233 const T
*tvalue
= (const T
*) value
;
234 if (U_SUCCESS(creationStatus
)) {
235 SharedObject::copyPtr(tvalue
, ptr
);
237 SharedObject::clearPtr(tvalue
);
238 // Take care not to overwrite a warning status passed in with
239 // another warning or U_ZERO_ERROR.
240 if (status
== U_ZERO_ERROR
|| U_FAILURE(creationStatus
)) {
241 status
= creationStatus
;
245 #ifdef UNIFIED_CACHE_DEBUG
247 * Dumps the contents of this cache to standard error. Used for testing of
250 void dumpContents() const;
254 * Convenience method to get a value of type T from cache for a
255 * particular locale with creationContext == NULL.
256 * @param loc the locale
257 * @param ptr On entry, must be NULL or included in the ref count
258 * of the object to which it points.
259 * On exit, fetched value stored here or is left
260 * unchanged on failure. Caller must call removeRef on
261 * ptr if set to a non NULL value.
262 * @param status Any error returned here. May be set to a
263 * warning value even if ptr is set.
266 static void getByLocale(
267 const Locale
&loc
, const T
*&ptr
, UErrorCode
&status
) {
268 const UnifiedCache
*cache
= getInstance(status
);
269 if (U_FAILURE(status
)) {
272 cache
->get(LocaleCacheKey
<T
>(loc
), ptr
, status
);
275 #ifdef UNIFIED_CACHE_DEBUG
277 * Dumps the cache contents to stderr. For testing only.
283 * Returns the number of keys in this cache. For testing only.
285 int32_t keyCount() const;
288 * Removes any values from cache that are not referenced outside
294 * Configures at what point evcition of unused entries will begin.
295 * Eviction is triggered whenever the number of unused entries exeeds
296 * BOTH count AND (number of in-use items) * (percentageOfInUseItems / 100).
297 * Once the number of unused entries drops below one of these,
298 * eviction ceases. Because eviction happens incrementally,
299 * the actual unused entry count may exceed both these numbers
302 * A cache entry is defined as unused if it is not essential to guarantee
303 * that for a given key X, the cache returns the same reference to the
304 * same value as long as the client already holds a reference to that
307 * If this method is never called, the default settings are 1000 and 100%.
309 * Although this method is thread-safe, it is designed to be called at
310 * application startup. If it is called in the middle of execution, it
311 * will have no immediate effect on the cache. However over time, the
312 * cache will perform eviction slices in an attempt to honor the new
315 * If a client already holds references to many different unique values
316 * in the cache such that the number of those unique values far exeeds
317 * "count" then the cache may not be able to maintain this maximum.
318 * However, if this happens, the cache still guarantees that the number of
319 * unused entries will remain only a small percentage of the total cache
322 * If the parameters passed are negative, setEvctionPolicy sets status to
323 * U_ILLEGAL_ARGUMENT_ERROR.
325 void setEvictionPolicy(
326 int32_t count
, int32_t percentageOfInUseItems
, UErrorCode
&status
);
330 * Returns how many entries have been auto evicted during the lifetime
331 * of this cache. This only includes auto evicted entries, not
332 * entries evicted because of a call to flush().
334 int64_t autoEvictedCount() const;
337 * Returns the unused entry count in this cache. For testing only,
338 * Regular clients will not need this.
340 int32_t unusedCount() const;
342 virtual void incrementItemsInUse() const;
343 virtual void decrementItemsInUseWithLockingAndEviction() const;
344 virtual void decrementItemsInUse() const;
345 virtual ~UnifiedCache();
347 UHashtable
*fHashtable
;
348 mutable int32_t fEvictPos
;
349 mutable int32_t fItemsInUseCount
;
351 int32_t fMaxPercentageOfInUse
;
352 mutable int64_t fAutoEvictedCount
;
353 UnifiedCache(const UnifiedCache
&other
);
354 UnifiedCache
&operator=(const UnifiedCache
&other
);
355 UBool
_flush(UBool all
) const;
357 const CacheKeyBase
&key
,
358 const SharedObject
*&value
,
359 const void *creationContext
,
360 UErrorCode
&status
) const;
362 const CacheKeyBase
&key
,
363 const SharedObject
*&value
,
364 UErrorCode
&status
) const;
366 const CacheKeyBase
&key
,
367 const SharedObject
*value
,
368 const UErrorCode creationStatus
,
369 UErrorCode
&status
) const;
370 void _putIfAbsentAndGet(
371 const CacheKeyBase
&key
,
372 const SharedObject
*&value
,
373 UErrorCode
&status
) const;
374 const UHashElement
*_nextElement() const;
375 int32_t _computeCountOfItemsToEvict() const;
376 void _runEvictionSlice() const;
377 void _registerMaster(
378 const CacheKeyBase
*theKey
, const SharedObject
*value
) const;
380 const UHashElement
*element
,
381 const SharedObject
*value
,
382 const UErrorCode status
) const;
383 #ifdef UNIFIED_CACHE_DEBUG
384 void _dumpContents() const;
386 static void copyPtr(const SharedObject
*src
, const SharedObject
*&dest
);
387 static void clearPtr(const SharedObject
*&ptr
);
389 const UHashElement
*element
,
390 const SharedObject
*&value
,
392 static UBool
_inProgress(const UHashElement
*element
);
393 static UBool
_inProgress(
394 const SharedObject
*theValue
, UErrorCode creationStatus
);
395 static UBool
_isEvictable(const UHashElement
*element
);