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);