Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(519)

Side by Side Diff: source/common/unifiedcache.cpp

Issue 1621843002: ICU 56 update step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@561
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « source/common/unifiedcache.h ('k') | source/common/uniset.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 ****************************************************************************** 2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines Corporation and 3 * Copyright (C) 2015, International Business Machines Corporation and
4 * others. All Rights Reserved. 4 * others. All Rights Reserved.
5 ****************************************************************************** 5 ******************************************************************************
6 * 6 *
7 * File UNIFIEDCACHE.CPP 7 * File UNIFIEDCACHE.CPP
8 ****************************************************************************** 8 ******************************************************************************
9 */ 9 */
10 10
11 #include "uhash.h" 11 #include "uhash.h"
12 #include "unifiedcache.h" 12 #include "unifiedcache.h"
13 #include "umutex.h" 13 #include "umutex.h"
14 #include "mutex.h" 14 #include "mutex.h"
15 #include "uassert.h" 15 #include "uassert.h"
16 #include "ucln_cmn.h" 16 #include "ucln_cmn.h"
17 17
18 static icu::UnifiedCache *gCache = NULL; 18 static icu::UnifiedCache *gCache = NULL;
19 static icu::SharedObject *gNoValue = NULL; 19 static icu::SharedObject *gNoValue = NULL;
20 static UMutex gCacheMutex = U_MUTEX_INITIALIZER; 20 static UMutex gCacheMutex = U_MUTEX_INITIALIZER;
21 static UConditionVar gInProgressValueAddedCond = U_CONDITION_INITIALIZER; 21 static UConditionVar gInProgressValueAddedCond = U_CONDITION_INITIALIZER;
22 static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER; 22 static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
23 static const int32_t MAX_EVICT_ITERATIONS = 10;
24
25 static int32_t DEFAULT_MAX_UNUSED = 1000;
26 static int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
27
23 28
24 U_CDECL_BEGIN 29 U_CDECL_BEGIN
25 static UBool U_CALLCONV unifiedcache_cleanup() { 30 static UBool U_CALLCONV unifiedcache_cleanup() {
26 gCacheInitOnce.reset(); 31 gCacheInitOnce.reset();
27 if (gCache) { 32 if (gCache) {
28 delete gCache; 33 delete gCache;
29 gCache = NULL; 34 gCache = NULL;
30 } 35 }
31 if (gNoValue) { 36 if (gNoValue) {
32 delete gNoValue; 37 delete gNoValue;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 delete gNoValue; 83 delete gNoValue;
79 gCache = NULL; 84 gCache = NULL;
80 gNoValue = NULL; 85 gNoValue = NULL;
81 return; 86 return;
82 } 87 }
83 // We add a softref because we want hash elements with gNoValue to be 88 // We add a softref because we want hash elements with gNoValue to be
84 // elligible for purging but we don't ever want gNoValue to be deleted. 89 // elligible for purging but we don't ever want gNoValue to be deleted.
85 gNoValue->addSoftRef(); 90 gNoValue->addSoftRef();
86 } 91 }
87 92
88 const UnifiedCache *UnifiedCache::getInstance(UErrorCode &status) { 93 UnifiedCache *UnifiedCache::getInstance(UErrorCode &status) {
89 umtx_initOnce(gCacheInitOnce, &cacheInit, status); 94 umtx_initOnce(gCacheInitOnce, &cacheInit, status);
90 if (U_FAILURE(status)) { 95 if (U_FAILURE(status)) {
91 return NULL; 96 return NULL;
92 } 97 }
93 U_ASSERT(gCache != NULL); 98 U_ASSERT(gCache != NULL);
94 return gCache; 99 return gCache;
95 } 100 }
96 101
97 UnifiedCache::UnifiedCache(UErrorCode &status) { 102 UnifiedCache::UnifiedCache(UErrorCode &status) :
103 fHashtable(NULL),
104 fEvictPos(UHASH_FIRST),
105 fItemsInUseCount(0),
106 fMaxUnused(DEFAULT_MAX_UNUSED),
107 fMaxPercentageOfInUse(DEFAULT_PERCENTAGE_OF_IN_USE),
108 fAutoEvictedCount(0) {
98 if (U_FAILURE(status)) { 109 if (U_FAILURE(status)) {
99 return; 110 return;
100 } 111 }
101 U_ASSERT(gNoValue != NULL); 112 U_ASSERT(gNoValue != NULL);
102 fHashtable = uhash_open( 113 fHashtable = uhash_open(
103 &ucache_hashKeys, 114 &ucache_hashKeys,
104 &ucache_compareKeys, 115 &ucache_compareKeys,
105 NULL, 116 NULL,
106 &status); 117 &status);
107 if (U_FAILURE(status)) { 118 if (U_FAILURE(status)) {
108 return; 119 return;
109 } 120 }
110 uhash_setKeyDeleter(fHashtable, &ucache_deleteKey); 121 uhash_setKeyDeleter(fHashtable, &ucache_deleteKey);
111 } 122 }
112 123
124 void UnifiedCache::setEvictionPolicy(
125 int32_t count, int32_t percentageOfInUseItems, UErrorCode &status) {
126 if (U_FAILURE(status)) {
127 return;
128 }
129 if (count < 0 || percentageOfInUseItems < 0) {
130 status = U_ILLEGAL_ARGUMENT_ERROR;
131 return;
132 }
133 Mutex lock(&gCacheMutex);
134 fMaxUnused = count;
135 fMaxPercentageOfInUse = percentageOfInUseItems;
136 }
137
138 int32_t UnifiedCache::unusedCount() const {
139 Mutex lock(&gCacheMutex);
140 return uhash_count(fHashtable) - fItemsInUseCount;
141 }
142
143 int64_t UnifiedCache::autoEvictedCount() const {
144 Mutex lock(&gCacheMutex);
145 return fAutoEvictedCount;
146 }
147
113 int32_t UnifiedCache::keyCount() const { 148 int32_t UnifiedCache::keyCount() const {
114 Mutex lock(&gCacheMutex); 149 Mutex lock(&gCacheMutex);
115 return uhash_count(fHashtable); 150 return uhash_count(fHashtable);
116 } 151 }
117 152
118 void UnifiedCache::flush() const { 153 void UnifiedCache::flush() const {
119 Mutex lock(&gCacheMutex); 154 Mutex lock(&gCacheMutex);
120 155
121 // Use a loop in case cache items that are flushed held hard references to 156 // Use a loop in case cache items that are flushed held hard references to
122 // other cache items making those additional cache items eligible for 157 // other cache items making those additional cache items eligible for
123 // flushing. 158 // flushing.
124 while (_flush(FALSE)); 159 while (_flush(FALSE));
125 umtx_condBroadcast(&gInProgressValueAddedCond);
126 } 160 }
127 161
128 #ifdef UNIFIED_CACHE_DEBUG 162 #ifdef UNIFIED_CACHE_DEBUG
129 #include <stdio.h> 163 #include <stdio.h>
130 164
131 void UnifiedCache::dump() { 165 void UnifiedCache::dump() {
132 UErrorCode status = U_ZERO_ERROR; 166 UErrorCode status = U_ZERO_ERROR;
133 const UnifiedCache *cache = getInstance(status); 167 const UnifiedCache *cache = getInstance(status);
134 if (U_FAILURE(status)) { 168 if (U_FAILURE(status)) {
135 fprintf(stderr, "Unified Cache: Error fetching cache.\n"); 169 fprintf(stderr, "Unified Cache: Error fetching cache.\n");
136 return; 170 return;
137 } 171 }
138 cache->dumpContents(); 172 cache->dumpContents();
139 } 173 }
140 174
141 void UnifiedCache::dumpContents() const { 175 void UnifiedCache::dumpContents() const {
142 Mutex lock(&gCacheMutex); 176 Mutex lock(&gCacheMutex);
143 _dumpContents(); 177 _dumpContents();
144 } 178 }
145 179
146 // Dumps content of cache. 180 // Dumps content of cache.
147 // On entry, gCacheMutex must be held. 181 // On entry, gCacheMutex must be held.
148 // On exit, cache contents dumped to stderr. 182 // On exit, cache contents dumped to stderr.
149 void UnifiedCache::_dumpContents() const { 183 void UnifiedCache::_dumpContents() const {
150 int32_t pos = -1; 184 int32_t pos = UHASH_FIRST;
151 const UHashElement *element = uhash_nextElement(fHashtable, &pos); 185 const UHashElement *element = uhash_nextElement(fHashtable, &pos);
152 char buffer[256]; 186 char buffer[256];
153 int32_t cnt = 0; 187 int32_t cnt = 0;
154 for (; element != NULL; element = uhash_nextElement(fHashtable, &pos)) { 188 for (; element != NULL; element = uhash_nextElement(fHashtable, &pos)) {
155 const SharedObject *sharedObject = 189 const SharedObject *sharedObject =
156 (const SharedObject *) element->value.pointer; 190 (const SharedObject *) element->value.pointer;
157 const CacheKeyBase *key = 191 const CacheKeyBase *key =
158 (const CacheKeyBase *) element->key.pointer; 192 (const CacheKeyBase *) element->key.pointer;
159 if (!sharedObject->allSoftReferences()) { 193 if (sharedObject->hasHardReferences()) {
160 ++cnt; 194 ++cnt;
161 fprintf( 195 fprintf(
162 stderr, 196 stderr,
163 "Unified Cache: Key '%s', error %d, value %p, total refcount %d, soft refcount %d\n", 197 "Unified Cache: Key '%s', error %d, value %p, total refcount %d, soft refcount %d\n",
164 key->writeDescription(buffer, 256), 198 key->writeDescription(buffer, 256),
165 key->creationStatus, 199 key->creationStatus,
166 sharedObject == gNoValue ? NULL :sharedObject, 200 sharedObject == gNoValue ? NULL :sharedObject,
167 sharedObject->getRefCount(), 201 sharedObject->getRefCount(),
168 sharedObject->getSoftRefCount()); 202 sharedObject->getSoftRefCount());
169 } 203 }
170 } 204 }
171 fprintf(stderr, "Unified Cache: %d out of a total of %d still have hard refe rences\n", cnt, uhash_count(fHashtable)); 205 fprintf(stderr, "Unified Cache: %d out of a total of %d still have hard refe rences\n", cnt, uhash_count(fHashtable));
172 } 206 }
173 #endif 207 #endif
174 208
175 UnifiedCache::~UnifiedCache() { 209 UnifiedCache::~UnifiedCache() {
176 // Try our best to clean up first. 210 // Try our best to clean up first.
177 flush(); 211 flush();
178 { 212 {
179 // Now all that should be left in the cache are entries that refer to 213 // Now all that should be left in the cache are entries that refer to
180 // each other and entries with hard references from outside the cache. 214 // each other and entries with hard references from outside the cache.
181 // Nothing we can do about these so proceed to wipe out the cache. 215 // Nothing we can do about these so proceed to wipe out the cache.
182 Mutex lock(&gCacheMutex); 216 Mutex lock(&gCacheMutex);
183 _flush(TRUE); 217 _flush(TRUE);
184 } 218 }
185 uhash_close(fHashtable); 219 uhash_close(fHashtable);
186 } 220 }
187 221
222 // Returns the next element in the cache round robin style.
223 // On entry, gCacheMutex must be held.
224 const UHashElement *
225 UnifiedCache::_nextElement() const {
226 const UHashElement *element = uhash_nextElement(fHashtable, &fEvictPos);
227 if (element == NULL) {
228 fEvictPos = UHASH_FIRST;
229 return uhash_nextElement(fHashtable, &fEvictPos);
230 }
231 return element;
232 }
233
188 // Flushes the contents of the cache. If cache values hold references to other 234 // Flushes the contents of the cache. If cache values hold references to other
189 // cache values then _flush should be called in a loop until it returns FALSE. 235 // cache values then _flush should be called in a loop until it returns FALSE.
190 // On entry, gCacheMutex must be held. 236 // On entry, gCacheMutex must be held.
191 // On exit, those values with only soft references are flushed. If all is true 237 // On exit, those values with are evictable are flushed. If all is true
192 // then every value is flushed even if hard references are held. 238 // then every value is flushed even if it is not evictable.
193 // Returns TRUE if any value in cache was flushed or FALSE otherwise. 239 // Returns TRUE if any value in cache was flushed or FALSE otherwise.
194 UBool UnifiedCache::_flush(UBool all) const { 240 UBool UnifiedCache::_flush(UBool all) const {
195 UBool result = FALSE; 241 UBool result = FALSE;
196 int32_t pos = -1; 242 int32_t origSize = uhash_count(fHashtable);
197 const UHashElement *element = uhash_nextElement(fHashtable, &pos); 243 for (int32_t i = 0; i < origSize; ++i) {
198 for (; element != NULL; element = uhash_nextElement(fHashtable, &pos)) { 244 const UHashElement *element = _nextElement();
199 const SharedObject *sharedObject = 245 if (all || _isEvictable(element)) {
200 (const SharedObject *) element->value.pointer; 246 const SharedObject *sharedObject =
201 if (all || sharedObject->allSoftReferences()) { 247 (const SharedObject *) element->value.pointer;
202 uhash_removeElement(fHashtable, element); 248 uhash_removeElement(fHashtable, element);
203 sharedObject->removeSoftRef(); 249 sharedObject->removeSoftRef();
204 result = TRUE; 250 result = TRUE;
205 } 251 }
206 } 252 }
207 return result; 253 return result;
208 } 254 }
209 255
256 // Computes how many items should be evicted.
257 // On entry, gCacheMutex must be held.
258 // Returns number of items that should be evicted or a value <= 0 if no
259 // items need to be evicted.
260 int32_t UnifiedCache::_computeCountOfItemsToEvict() const {
261 int32_t maxPercentageOfInUseCount =
262 fItemsInUseCount * fMaxPercentageOfInUse / 100;
263 int32_t maxUnusedCount = fMaxUnused;
264 if (maxUnusedCount < maxPercentageOfInUseCount) {
265 maxUnusedCount = maxPercentageOfInUseCount;
266 }
267 return uhash_count(fHashtable) - fItemsInUseCount - maxUnusedCount;
268 }
269
270 // Run an eviction slice.
271 // On entry, gCacheMutex must be held.
272 // _runEvictionSlice runs a slice of the evict pipeline by examining the next
273 // 10 entries in the cache round robin style evicting them if they are eligible.
274 void UnifiedCache::_runEvictionSlice() const {
275 int32_t maxItemsToEvict = _computeCountOfItemsToEvict();
276 if (maxItemsToEvict <= 0) {
277 return;
278 }
279 for (int32_t i = 0; i < MAX_EVICT_ITERATIONS; ++i) {
280 const UHashElement *element = _nextElement();
281 if (_isEvictable(element)) {
282 const SharedObject *sharedObject =
283 (const SharedObject *) element->value.pointer;
284 uhash_removeElement(fHashtable, element);
285 sharedObject->removeSoftRef();
286 ++fAutoEvictedCount;
287 if (--maxItemsToEvict == 0) {
288 break;
289 }
290 }
291 }
292 }
293
294
210 // Places a new value and creationStatus in the cache for the given key. 295 // Places a new value and creationStatus in the cache for the given key.
211 // On entry, gCacheMutex must be held. key must not exist in the cache. 296 // On entry, gCacheMutex must be held. key must not exist in the cache.
212 // On exit, value and creation status placed under key. Soft reference added 297 // On exit, value and creation status placed under key. Soft reference added
213 // to value on successful add. On error sets status. 298 // to value on successful add. On error sets status.
214 void UnifiedCache::_putNew( 299 void UnifiedCache::_putNew(
215 const CacheKeyBase &key, 300 const CacheKeyBase &key,
216 const SharedObject *value, 301 const SharedObject *value,
217 const UErrorCode creationStatus, 302 const UErrorCode creationStatus,
218 UErrorCode &status) const { 303 UErrorCode &status) const {
219 if (U_FAILURE(status)) { 304 if (U_FAILURE(status)) {
220 return; 305 return;
221 } 306 }
222 CacheKeyBase *keyToAdopt = key.clone(); 307 CacheKeyBase *keyToAdopt = key.clone();
223 if (keyToAdopt == NULL) { 308 if (keyToAdopt == NULL) {
224 status = U_MEMORY_ALLOCATION_ERROR; 309 status = U_MEMORY_ALLOCATION_ERROR;
225 return; 310 return;
226 } 311 }
227 keyToAdopt->creationStatus = creationStatus; 312 keyToAdopt->fCreationStatus = creationStatus;
313 if (value->noSoftReferences()) {
314 _registerMaster(keyToAdopt, value);
315 }
228 uhash_put(fHashtable, keyToAdopt, (void *) value, &status); 316 uhash_put(fHashtable, keyToAdopt, (void *) value, &status);
229 if (U_SUCCESS(status)) { 317 if (U_SUCCESS(status)) {
230 value->addSoftRef(); 318 value->addSoftRef();
231 } 319 }
232 } 320 }
233 321
234 // Places value and status at key if there is no value at key or if cache 322 // Places value and status at key if there is no value at key or if cache
235 // entry for key is in progress. Otherwise, it leaves the current value and 323 // entry for key is in progress. Otherwise, it leaves the current value and
236 // status there. 324 // status there.
237 // On entry. gCacheMutex must not be held. value must be 325 // On entry. gCacheMutex must not be held. value must be
238 // included in the reference count of the object to which it points. 326 // included in the reference count of the object to which it points.
239 // On exit, value and status are changed to what was already in the cache if 327 // On exit, value and status are changed to what was already in the cache if
240 // something was there and not in progress. Otherwise, value and status are left 328 // something was there and not in progress. Otherwise, value and status are left
241 // unchanged in which case they are placed in the cache on a best-effort basis. 329 // unchanged in which case they are placed in the cache on a best-effort basis.
242 // Caller must call removeRef() on value. 330 // Caller must call removeRef() on value.
243 void UnifiedCache::_putIfAbsentAndGet( 331 void UnifiedCache::_putIfAbsentAndGet(
244 const CacheKeyBase &key, 332 const CacheKeyBase &key,
245 const SharedObject *&value, 333 const SharedObject *&value,
246 UErrorCode &status) const { 334 UErrorCode &status) const {
247 Mutex lock(&gCacheMutex); 335 Mutex lock(&gCacheMutex);
248 const UHashElement *element = uhash_find(fHashtable, &key); 336 const UHashElement *element = uhash_find(fHashtable, &key);
249 if (element != NULL && !_inProgress(element)) { 337 if (element != NULL && !_inProgress(element)) {
250 _fetch(element, value, status); 338 _fetch(element, value, status);
251 return; 339 return;
252 } 340 }
253 if (element == NULL) { 341 if (element == NULL) {
254 UErrorCode putError = U_ZERO_ERROR; 342 UErrorCode putError = U_ZERO_ERROR;
255 // best-effort basis only. 343 // best-effort basis only.
256 _putNew(key, value, status, putError); 344 _putNew(key, value, status, putError);
257 return; 345 } else {
346 _put(element, value, status);
258 } 347 }
259 _put(element, value, status); 348 // Run an eviction slice. This will run even if we added a master entry
349 // which doesn't increase the unused count, but that is still o.k
350 _runEvictionSlice();
260 } 351 }
261 352
262 // Attempts to fetch value and status for key from cache. 353 // Attempts to fetch value and status for key from cache.
263 // On entry, gCacheMutex must not be held value must be NULL and status must 354 // On entry, gCacheMutex must not be held value must be NULL and status must
264 // be U_ZERO_ERROR. 355 // be U_ZERO_ERROR.
265 // On exit, either returns FALSE (In this 356 // On exit, either returns FALSE (In this
266 // case caller should try to create the object) or returns TRUE with value 357 // case caller should try to create the object) or returns TRUE with value
267 // pointing to the fetched value and status set to fetched status. When 358 // pointing to the fetched value and status set to fetched status. When
268 // FALSE is returned status may be set to failure if an in progress hash 359 // FALSE is returned status may be set to failure if an in progress hash
269 // entry could not be made but value will remain unchanged. When TRUE is 360 // entry could not be made but value will remain unchanged. When TRUE is
(...skipping 17 matching lines...) Expand all
287 _putNew(key, gNoValue, U_ZERO_ERROR, status); 378 _putNew(key, gNoValue, U_ZERO_ERROR, status);
288 return FALSE; 379 return FALSE;
289 } 380 }
290 381
291 // Gets value out of cache. 382 // Gets value out of cache.
292 // On entry. gCacheMutex must not be held. value must be NULL. status 383 // On entry. gCacheMutex must not be held. value must be NULL. status
293 // must be U_ZERO_ERROR. 384 // must be U_ZERO_ERROR.
294 // On exit. value and status set to what is in cache at key or on cache 385 // On exit. value and status set to what is in cache at key or on cache
295 // miss the key's createObject() is called and value and status are set to 386 // miss the key's createObject() is called and value and status are set to
296 // the result of that. In this latter case, best effort is made to add the 387 // the result of that. In this latter case, best effort is made to add the
297 // value and status to the cache. value will be set to NULL instead of 388 // value and status to the cache. If createObject() fails to create a value,
298 // gNoValue. Caller must call removeRef on value if non NULL. 389 // gNoValue is stored in cache, and value is set to NULL. Caller must call
390 // removeRef on value if non NULL.
299 void UnifiedCache::_get( 391 void UnifiedCache::_get(
300 const CacheKeyBase &key, 392 const CacheKeyBase &key,
301 const SharedObject *&value, 393 const SharedObject *&value,
302 const void *creationContext, 394 const void *creationContext,
303 UErrorCode &status) const { 395 UErrorCode &status) const {
304 U_ASSERT(value == NULL); 396 U_ASSERT(value == NULL);
305 U_ASSERT(status == U_ZERO_ERROR); 397 U_ASSERT(status == U_ZERO_ERROR);
306 if (_poll(key, value, status)) { 398 if (_poll(key, value, status)) {
307 if (value == gNoValue) { 399 if (value == gNoValue) {
308 SharedObject::clearPtr(value); 400 SharedObject::clearPtr(value);
309 } 401 }
310 return; 402 return;
311 } 403 }
312 if (U_FAILURE(status)) { 404 if (U_FAILURE(status)) {
313 return; 405 return;
314 } 406 }
315 value = key.createObject(creationContext, status); 407 value = key.createObject(creationContext, status);
316 U_ASSERT(value == NULL || !value->allSoftReferences()); 408 U_ASSERT(value == NULL || value->hasHardReferences());
317 U_ASSERT(value != NULL || status != U_ZERO_ERROR); 409 U_ASSERT(value != NULL || status != U_ZERO_ERROR);
318 if (value == NULL) { 410 if (value == NULL) {
319 SharedObject::copyPtr(gNoValue, value); 411 SharedObject::copyPtr(gNoValue, value);
320 } 412 }
321 _putIfAbsentAndGet(key, value, status); 413 _putIfAbsentAndGet(key, value, status);
322 if (value == gNoValue) { 414 if (value == gNoValue) {
323 SharedObject::clearPtr(value); 415 SharedObject::clearPtr(value);
324 } 416 }
325 } 417 }
326 418
419 void UnifiedCache::decrementItemsInUseWithLockingAndEviction() const {
420 Mutex mutex(&gCacheMutex);
421 decrementItemsInUse();
422 _runEvictionSlice();
423 }
424
425 void UnifiedCache::incrementItemsInUse() const {
426 ++fItemsInUseCount;
427 }
428
429 void UnifiedCache::decrementItemsInUse() const {
430 --fItemsInUseCount;
431 }
432
433 // Register a master cache entry.
434 // On entry, gCacheMutex must be held.
435 // On exit, items in use count incremented, entry is marked as a master
436 // entry, and value registered with cache so that subsequent calls to
437 // addRef() and removeRef() on it correctly updates items in use count
438 void UnifiedCache::_registerMaster(
439 const CacheKeyBase *theKey, const SharedObject *value) const {
440 theKey->fIsMaster = TRUE;
441 ++fItemsInUseCount;
442 value->registerWithCache(this);
443 }
444
327 // Store a value and error in given hash entry. 445 // Store a value and error in given hash entry.
328 // On entry, gCacheMutex must be held. Hash entry element must be in progress. 446 // On entry, gCacheMutex must be held. Hash entry element must be in progress.
329 // value must be non NULL. 447 // value must be non NULL.
330 // On Exit, soft reference added to value. value and status stored in hash 448 // On Exit, soft reference added to value. value and status stored in hash
331 // entry. Soft reference removed from previous stored value. Waiting 449 // entry. Soft reference removed from previous stored value. Waiting
332 // threads notified. 450 // threads notified.
333 void UnifiedCache::_put( 451 void UnifiedCache::_put(
334 const UHashElement *element, 452 const UHashElement *element,
335 const SharedObject *value, 453 const SharedObject *value,
336 const UErrorCode status) { 454 const UErrorCode status) const {
337 U_ASSERT(_inProgress(element)); 455 U_ASSERT(_inProgress(element));
338 const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer; 456 const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
339 const SharedObject *oldValue = (const SharedObject *) element->value.pointer ; 457 const SharedObject *oldValue = (const SharedObject *) element->value.pointer ;
340 theKey->creationStatus = status; 458 theKey->fCreationStatus = status;
459 if (value->noSoftReferences()) {
460 _registerMaster(theKey, value);
461 }
341 value->addSoftRef(); 462 value->addSoftRef();
342 UHashElement *ptr = const_cast<UHashElement *>(element); 463 UHashElement *ptr = const_cast<UHashElement *>(element);
343 ptr->value.pointer = (void *) value; 464 ptr->value.pointer = (void *) value;
344 oldValue->removeSoftRef(); 465 oldValue->removeSoftRef();
345 466
346 // Tell waiting threads that we replace in-progress status with 467 // Tell waiting threads that we replace in-progress status with
347 // an error. 468 // an error.
348 umtx_condBroadcast(&gInProgressValueAddedCond); 469 umtx_condBroadcast(&gInProgressValueAddedCond);
349 } 470 }
350 471
472 void
473 UnifiedCache::copyPtr(const SharedObject *src, const SharedObject *&dest) {
474 if(src != dest) {
475 if(dest != NULL) {
476 dest->removeRefWhileHoldingCacheLock();
477 }
478 dest = src;
479 if(src != NULL) {
480 src->addRefWhileHoldingCacheLock();
481 }
482 }
483 }
484
485 void
486 UnifiedCache::clearPtr(const SharedObject *&ptr) {
487 if (ptr != NULL) {
488 ptr->removeRefWhileHoldingCacheLock();
489 ptr = NULL;
490 }
491 }
492
493
351 // Fetch value and error code from a particular hash entry. 494 // Fetch value and error code from a particular hash entry.
352 // On entry, gCacheMutex must be held. value must be either NULL or must be 495 // On entry, gCacheMutex must be held. value must be either NULL or must be
353 // included in the ref count of the object to which it points. 496 // included in the ref count of the object to which it points.
354 // On exit, value and status set to what is in the hash entry. Caller must 497 // On exit, value and status set to what is in the hash entry. Caller must
355 // eventually call removeRef on value. 498 // eventually call removeRef on value.
356 // If hash entry is in progress, value will be set to gNoValue and status will 499 // If hash entry is in progress, value will be set to gNoValue and status will
357 // be set to U_ZERO_ERROR. 500 // be set to U_ZERO_ERROR.
358 void UnifiedCache::_fetch( 501 void UnifiedCache::_fetch(
359 const UHashElement *element, 502 const UHashElement *element,
360 const SharedObject *&value, 503 const SharedObject *&value,
361 UErrorCode &status) { 504 UErrorCode &status) {
362 const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer; 505 const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
363 status = theKey->creationStatus; 506 status = theKey->fCreationStatus;
364 SharedObject::copyPtr( 507
365 (const SharedObject *) element->value.pointer, value); 508 // Since we have the cache lock, calling regular SharedObject methods
509 // could cause us to deadlock on ourselves since they may need to lock
510 // the cache mutex.
511 UnifiedCache::copyPtr((const SharedObject *) element->value.pointer, value);
366 } 512 }
367 513
368 // Determine if given hash entry is in progress. 514 // Determine if given hash entry is in progress.
369 // On entry, gCacheMutex must be held. 515 // On entry, gCacheMutex must be held.
370 UBool UnifiedCache::_inProgress(const UHashElement *element) { 516 UBool UnifiedCache::_inProgress(const UHashElement *element) {
371 const SharedObject *value = NULL; 517 const SharedObject *value = NULL;
372 UErrorCode status = U_ZERO_ERROR; 518 UErrorCode status = U_ZERO_ERROR;
373 _fetch(element, value, status); 519 _fetch(element, value, status);
374 UBool result = (value == gNoValue && status == U_ZERO_ERROR); 520 UBool result = _inProgress(value, status);
375 SharedObject::clearPtr(value); 521
522 // Since we have the cache lock, calling regular SharedObject methods
523 // could cause us to deadlock on ourselves since they may need to lock
524 // the cache mutex.
525 UnifiedCache::clearPtr(value);
376 return result; 526 return result;
377 } 527 }
378 528
529 // Determine if given hash entry is in progress.
530 // On entry, gCacheMutex must be held.
531 UBool UnifiedCache::_inProgress(
532 const SharedObject *theValue, UErrorCode creationStatus) {
533 return (theValue == gNoValue && creationStatus == U_ZERO_ERROR);
534 }
535
536 // Determine if given hash entry is eligible for eviction.
537 // On entry, gCacheMutex must be held.
538 UBool UnifiedCache::_isEvictable(const UHashElement *element) {
539 const CacheKeyBase *theKey = (const CacheKeyBase *) element->key.pointer;
540 const SharedObject *theValue =
541 (const SharedObject *) element->value.pointer;
542
543 // Entries that are under construction are never evictable
544 if (_inProgress(theValue, theKey->fCreationStatus)) {
545 return FALSE;
546 }
547
548 // We can evict entries that are either not a master or have just
549 // one reference (The one reference being from the cache itself).
550 return (!theKey->fIsMaster || (theValue->getSoftRefCount() == 1 && theValue- >noHardReferences()));
551 }
552
379 U_NAMESPACE_END 553 U_NAMESPACE_END
OLDNEW
« no previous file with comments | « source/common/unifiedcache.h ('k') | source/common/uniset.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698