unifiedcache.h 19 KB

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