]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/unifiedcache.h
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / common / unifiedcache.h
CommitLineData
b331163b
A
1/*
2******************************************************************************
2ca993e8 3* Copyright (C) 2015, International Business Machines Corporation and
b331163b
A
4* others. All Rights Reserved.
5******************************************************************************
6*
7* File UNIFIEDCACHE.H - The ICU Unified cache.
8******************************************************************************
9*/
10
11#ifndef __UNIFIED_CACHE_H__
12#define __UNIFIED_CACHE_H__
13
14#include "utypeinfo.h" // for 'typeid' to work
15
16#include "unicode/uobject.h"
17#include "unicode/locid.h"
18#include "sharedobject.h"
19#include "unicode/unistr.h"
20#include "cstring.h"
21#include "ustr_imp.h"
22
23struct UHashtable;
24struct UHashElement;
25
26U_NAMESPACE_BEGIN
27
28class UnifiedCache;
29
30/**
2ca993e8 31 * A base class for all cache keys.
b331163b
A
32 */
33class U_COMMON_API CacheKeyBase : public UObject {
34 public:
2ca993e8 35 CacheKeyBase() : fCreationStatus(U_ZERO_ERROR), fIsMaster(FALSE) {}
b331163b
A
36
37 /**
38 * Copy constructor. Needed to support cloning.
39 */
40 CacheKeyBase(const CacheKeyBase &other)
2ca993e8 41 : UObject(other), fCreationStatus(other.fCreationStatus), fIsMaster(FALSE) { }
b331163b
A
42 virtual ~CacheKeyBase();
43
44 /**
45 * Returns the hash code for this object.
46 */
47 virtual int32_t hashCode() const = 0;
48
49 /**
50 * Clones this object polymorphically. Caller owns returned value.
51 */
52 virtual CacheKeyBase *clone() const = 0;
53
54 /**
55 * Equality operator.
56 */
57 virtual UBool operator == (const CacheKeyBase &other) const = 0;
58
59 /**
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.
65 *
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.
71 */
72 virtual const SharedObject *createObject(
73 const void *creationContext, UErrorCode &status) const = 0;
74
75 /**
76 * Writes a description of this key to buffer and returns buffer. Written
77 * description is NULL terminated.
78 */
79 virtual char *writeDescription(char *buffer, int32_t bufSize) const = 0;
80
81 /**
82 * Inequality operator.
83 */
84 UBool operator != (const CacheKeyBase &other) const {
85 return !(*this == other);
86 }
87 private:
2ca993e8
A
88 mutable UErrorCode fCreationStatus;
89 mutable UBool fIsMaster;
b331163b
A
90 friend class UnifiedCache;
91};
92
93
94
95/**
96 * Templated version of CacheKeyBase.
97 * A key of type LocaleCacheKey<T> maps to a value of type T.
98 */
99template<typename T>
100class CacheKey : public CacheKeyBase {
101 public:
102 virtual ~CacheKey() { }
103 /**
104 * The template parameter, T, determines the hash code returned.
105 */
106 virtual int32_t hashCode() const {
107 const char *s = typeid(T).name();
108 return ustr_hashCharsN(s, uprv_strlen(s));
109 }
110
111 /**
112 * Use the value type, T, as the description.
113 */
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;
118 return buffer;
119 }
120
121 /**
122 * Two objects are equal if they are of the same type.
123 */
124 virtual UBool operator == (const CacheKeyBase &other) const {
125 return typeid(*this) == typeid(other);
126 }
127};
128
129/**
130 * Cache key based on locale.
131 * A key of type LocaleCacheKey<T> maps to a value of type T.
132 */
133template<typename T>
134class LocaleCacheKey : public CacheKey<T> {
135 protected:
136 Locale fLoc;
137 public:
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();
144 }
145 virtual UBool operator == (const CacheKeyBase &other) const {
146 // reflexive
147 if (this == &other) {
148 return TRUE;
149 }
150 if (!CacheKey<T>::operator == (other)) {
151 return FALSE;
152 }
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;
158 }
159 virtual CacheKeyBase *clone() const {
160 return new LocaleCacheKey<T>(*this);
161 }
162 virtual const T *createObject(
163 const void *creationContext, UErrorCode &status) const;
164 /**
165 * Use the locale id as the description.
166 */
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;
171 return buffer;
172 }
173
174};
175
176/**
177 * The unified cache. A singleton type.
2ca993e8
A
178 * Design doc here:
179 * https://docs.google.com/document/d/1RwGQJs4N4tawNbf809iYDRCvXoMKqDJihxzYt1ysmd8/edit?usp=sharing
b331163b 180 */
2ca993e8 181class U_COMMON_API UnifiedCache : public UnifiedCacheBase {
b331163b
A
182 public:
183 /**
184 * @internal
2ca993e8
A
185 * Do not call directly. Instead use UnifiedCache::getInstance() as
186 * there should be only one UnifiedCache in an application.
b331163b
A
187 */
188 UnifiedCache(UErrorCode &status);
189
190 /**
191 * Returns the cache instance.
192 */
2ca993e8 193 static UnifiedCache *getInstance(UErrorCode &status);
b331163b
A
194
195 /**
196 * Fetches a value from the cache by key. Equivalent to
197 * get(key, NULL, ptr, status);
198 */
199 template<typename T>
200 void get(
201 const CacheKey<T>& key,
202 const T *&ptr,
203 UErrorCode &status) const {
204 get(key, NULL, ptr, status);
205 }
206
207 /**
208 * Fetches value from the cache by key.
209 *
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.
220 */
221 template<typename T>
222 void get(
223 const CacheKey<T>& key,
224 const void *creationContext,
225 const T *&ptr,
226 UErrorCode &status) const {
227 if (U_FAILURE(status)) {
228 return;
229 }
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);
236 }
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;
242 }
243 }
244
245#ifdef UNIFIED_CACHE_DEBUG
246 /**
247 * Dumps the contents of this cache to standard error. Used for testing of
248 * cache only.
249 */
250 void dumpContents() const;
251#endif
252
253 /**
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.
264 */
265 template<typename T>
266 static void getByLocale(
267 const Locale &loc, const T *&ptr, UErrorCode &status) {
268 const UnifiedCache *cache = getInstance(status);
269 if (U_FAILURE(status)) {
270 return;
271 }
272 cache->get(LocaleCacheKey<T>(loc), ptr, status);
273 }
274
275#ifdef UNIFIED_CACHE_DEBUG
276 /**
277 * Dumps the cache contents to stderr. For testing only.
278 */
279 static void dump();
280#endif
281
282 /**
283 * Returns the number of keys in this cache. For testing only.
284 */
285 int32_t keyCount() const;
286
287 /**
288 * Removes any values from cache that are not referenced outside
289 * the cache.
290 */
291 void flush() const;
292
2ca993e8
A
293 /**
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
300 * from time to time.
301 *
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
305 * value.
306 *
307 * If this method is never called, the default settings are 1000 and 100%.
308 *
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
313 * settings.
314 *
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
320 * size.
321 *
322 * If the parameters passed are negative, setEvctionPolicy sets status to
323 * U_ILLEGAL_ARGUMENT_ERROR.
324 */
325 void setEvictionPolicy(
326 int32_t count, int32_t percentageOfInUseItems, UErrorCode &status);
327
328
329 /**
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().
333 */
334 int64_t autoEvictedCount() const;
335
336 /**
337 * Returns the unused entry count in this cache. For testing only,
338 * Regular clients will not need this.
339 */
340 int32_t unusedCount() const;
341
342 virtual void incrementItemsInUse() const;
343 virtual void decrementItemsInUseWithLockingAndEviction() const;
344 virtual void decrementItemsInUse() const;
b331163b
A
345 virtual ~UnifiedCache();
346 private:
347 UHashtable *fHashtable;
2ca993e8
A
348 mutable int32_t fEvictPos;
349 mutable int32_t fItemsInUseCount;
350 int32_t fMaxUnused;
351 int32_t fMaxPercentageOfInUse;
352 mutable int64_t fAutoEvictedCount;
b331163b
A
353 UnifiedCache(const UnifiedCache &other);
354 UnifiedCache &operator=(const UnifiedCache &other);
355 UBool _flush(UBool all) const;
356 void _get(
357 const CacheKeyBase &key,
358 const SharedObject *&value,
359 const void *creationContext,
360 UErrorCode &status) const;
361 UBool _poll(
362 const CacheKeyBase &key,
363 const SharedObject *&value,
364 UErrorCode &status) const;
365 void _putNew(
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;
2ca993e8
A
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;
379 void _put(
380 const UHashElement *element,
381 const SharedObject *value,
382 const UErrorCode status) const;
b331163b
A
383#ifdef UNIFIED_CACHE_DEBUG
384 void _dumpContents() const;
385#endif
2ca993e8
A
386 static void copyPtr(const SharedObject *src, const SharedObject *&dest);
387 static void clearPtr(const SharedObject *&ptr);
b331163b
A
388 static void _fetch(
389 const UHashElement *element,
390 const SharedObject *&value,
391 UErrorCode &status);
392 static UBool _inProgress(const UHashElement *element);
2ca993e8
A
393 static UBool _inProgress(
394 const SharedObject *theValue, UErrorCode creationStatus);
395 static UBool _isEvictable(const UHashElement *element);
b331163b
A
396};
397
398U_NAMESPACE_END
399
400#endif