예제 #1
0
UBool UnifiedCache::_poll(
        const CacheKeyBase &key,
        const SharedObject *&value,
        UErrorCode &status) const {
    U_ASSERT(value == NULL);
    U_ASSERT(status == U_ZERO_ERROR);
    Mutex lock(gCacheMutex());
    const UHashElement *element = uhash_find(fHashtable, &key);

    // If the hash table contains an inProgress placeholder entry for this key,
    // this means that another thread is currently constructing the value object.
    // Loop, waiting for that construction to complete.
     while (element != NULL && _inProgress(element)) {
        umtx_condWait(gInProgressValueAddedCond(), gCacheMutex());
        element = uhash_find(fHashtable, &key);
    }

    // If the hash table contains an entry for the key,
    // fetch out the contents and return them.
    if (element != NULL) {
         _fetch(element, value, status);
        return TRUE;
    }

    // The hash table contained nothing for this key.
    // Insert an inProgress place holder value.
    // Our caller will create the final value and update the hash table.
    _putNew(key, fNoValue, U_ZERO_ERROR, status);
    return FALSE;
}
예제 #2
0
StringTrieBuilder::Node *
StringTrieBuilder::registerFinalValue(int32_t value, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return NULL;
    }
    FinalValueNode key(value);
    const UHashElement *old=uhash_find(nodes, &key);
    if(old!=NULL) {
        return (Node *)old->key.pointer;
    }
    Node *newNode=new FinalValueNode(value);
    if(newNode==NULL) {
        errorCode=U_MEMORY_ALLOCATION_ERROR;
        return NULL;
    }
    // If uhash_puti() returns a non-zero value from an equivalent, previously
    // registered node, then uhash_find() failed to find that and we will leak newNode.
#if !U_RELEASE
    int32_t oldValue=  // Only in debug mode to avoid a compiler warning about unused oldValue.
#endif
    uhash_puti(nodes, newNode, 1, &errorCode);
    U_ASSERT(oldValue==0);
    if(U_FAILURE(errorCode)) {
        delete newNode;
        return NULL;
    }
    return newNode;
}
예제 #3
0
// Attempts to fetch value and status for key from cache.
// On entry, gCacheMutex must not be held value must be NULL and status must
// be U_ZERO_ERROR.
// On exit, either returns FALSE (In this
// case caller should try to create the object) or returns TRUE with value
// pointing to the fetched value and status set to fetched status. When
// FALSE is returned status may be set to failure if an in progress hash
// entry could not be made but value will remain unchanged. When TRUE is
// returned, caler must call removeRef() on value.
UBool UnifiedCache::_poll(
        const CacheKeyBase &key,
        const SharedObject *&value,
        UErrorCode &status) const {
    U_ASSERT(value == NULL);
    U_ASSERT(status == U_ZERO_ERROR);
    Mutex lock(&gCacheMutex);
    const UHashElement *element = uhash_find(fHashtable, &key);
    while (element != NULL && _inProgress(element)) {
        umtx_condWait(&gInProgressValueAddedCond, &gCacheMutex);
        element = uhash_find(fHashtable, &key);
    }
    if (element != NULL) {
        _fetch(element, value, status);
        return TRUE;
    }
    _putNew(key, gNoValue, U_ZERO_ERROR, status);
    return FALSE;
}
예제 #4
0
// Places value and status at key if there is no value at key or if cache
// entry for key is in progress. Otherwise, it leaves the current value and
// status there.
// On entry. gCacheMutex must not be held. value must be
// included in the reference count of the object to which it points.
// On exit, value and status are changed to what was already in the cache if
// something was there and not in progress. Otherwise, value and status are left
// unchanged in which case they are placed in the cache on a best-effort basis.
// Caller must call removeRef() on value.
void UnifiedCache::_putIfAbsentAndGet(
        const CacheKeyBase &key,
        const SharedObject *&value,
        UErrorCode &status) const {
    Mutex lock(&gCacheMutex);
    const UHashElement *element = uhash_find(fHashtable, &key);
    if (element != NULL && !_inProgress(element)) {
        _fetch(element, value, status);
        return;
    }
    if (element == NULL) {
        UErrorCode putError = U_ZERO_ERROR;
        // best-effort basis only.
        _putNew(key, value, status, putError);
        return;
    }
    _put(element, value, status);
}
예제 #5
0
// Places value and status at key if there is no value at key or if cache
// entry for key is in progress. Otherwise, it leaves the current value and
// status there.
// On entry. gCacheMutex must not be held. value must be
// included in the reference count of the object to which it points.
// On exit, value and status are changed to what was already in the cache if
// something was there and not in progress. Otherwise, value and status are left
// unchanged in which case they are placed in the cache on a best-effort basis.
// Caller must call removeRef() on value.
void UnifiedCache::_putIfAbsentAndGet(
        const CacheKeyBase &key,
        const SharedObject *&value,
        UErrorCode &status) const {
    Mutex lock(&gCacheMutex);
    const UHashElement *element = uhash_find(fHashtable, &key);
    if (element != NULL && !_inProgress(element)) {
        _fetch(element, value, status);
        return;
    }
    if (element == NULL) {
        UErrorCode putError = U_ZERO_ERROR;
        // best-effort basis only.
        _putNew(key, value, status, putError);
    } else {
        _put(element, value, status);
    }
    // Run an eviction slice. This will run even if we added a master entry
    // which doesn't increase the unused count, but that is still o.k
    _runEvictionSlice();
}
예제 #6
0
static void TestOtherAPI(void){
    
    UErrorCode status = U_ZERO_ERROR;
    UHashtable *hash;

    /* Use the correct type when cast to void * */
    static const UChar one[4]   = {0x006F, 0x006E, 0x0065, 0}; /* L"one" */
    static const UChar one2[4]  = {0x006F, 0x006E, 0x0065, 0}; /* Get around compiler optimizations */
    static const UChar two[4]   = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
    static const UChar two2[4]  = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */
    static const UChar three[6] = {0x0074, 0x0068, 0x0072, 0x0065, 0x0065, 0}; /* L"three" */
    static const UChar four[6]  = {0x0066, 0x006F, 0x0075, 0x0072, 0}; /* L"four" */
    static const UChar five[6]  = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */
    static const UChar five2[6] = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */

    hash = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL,  &status);
    if (U_FAILURE(status)) {
        log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n",
                u_errorName(status), hash);
        return;
    }
    if (hash == NULL) {
        log_err("FAIL: uhash_open returned NULL\n");
        return;
    }
    log_verbose("Ok: uhash_open returned 0x%08X\n", hash);

    uhash_puti(hash, (void*)one, 1, &status);
    if(uhash_count(hash) != 1){
         log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
    }
    if(uhash_find(hash, (void*)two) != NULL){
        log_err("FAIL: uhash_find failed\n");
    }
    uhash_puti(hash, (void*)two, 2, &status);
    uhash_puti(hash, (void*)three, 3, &status);
    uhash_puti(hash, (void*)four, 4, &status);
    uhash_puti(hash, (void*)five, 5, &status);
    
    if(uhash_count(hash) != 5){
        log_err("FAIL: uhas_count() failed. Expected: 5, Got: %d\n", uhash_count(hash));
    }
    
    if(uhash_geti(hash, (void*)two2) != 2){
        log_err("FAIL: uhash_geti failed\n");
    }
    
    if(uhash_find(hash, (void*)two2) == NULL){
        log_err("FAIL: uhash_find of \"two\" failed\n");
    }
    
    if(uhash_removei(hash, (void*)five2) != 5){
        log_err("FAIL: uhash_remove() failed\n");
    }
    if(uhash_count(hash) != 4){
        log_err("FAIL: uhas_count() failed. Expected: 4, Got: %d\n", uhash_count(hash));
    }

    uhash_put(hash, (void*)one, NULL, &status);
    if(uhash_count(hash) != 3){
        log_err("FAIL: uhash_put() with value=NULL didn't remove the key value pair\n");
    }
    status=U_ILLEGAL_ARGUMENT_ERROR;
    uhash_puti(hash, (void*)one, 1, &status);
    if(uhash_count(hash) != 3){
        log_err("FAIL: uhash_put() with value!=NULL should fail when status != U_ZERO_ERROR \n");
    }
    
    status=U_ZERO_ERROR;
    uhash_puti(hash, (void*)one, 1, &status);
    if(uhash_count(hash) != 4){
        log_err("FAIL: uhash_put() with value!=NULL didn't replace the key value pair\n");
    }

    if(_compareUChars((void*)one, (void*)two) == TRUE ||
        _compareUChars((void*)one, (void*)one) != TRUE ||
        _compareUChars((void*)one, (void*)one2) != TRUE ||
        _compareUChars((void*)one, NULL) == TRUE  )  {
        log_err("FAIL: compareUChars failed\n");
    }
   
    uhash_removeAll(hash);
    if(uhash_count(hash) != 0){
        log_err("FAIL: uhas_count() failed. Expected: 0, Got: %d\n", uhash_count(hash));
    }

    uhash_setKeyComparator(hash, uhash_compareLong);
    uhash_setKeyHasher(hash, uhash_hashLong);
    uhash_iputi(hash, 1001, 1, &status);
    uhash_iputi(hash, 1002, 2, &status);
    uhash_iputi(hash, 1003, 3, &status);
    if(_compareLong(1001, 1002) == TRUE ||
        _compareLong(1001, 1001) != TRUE ||
        _compareLong(1001, 0) == TRUE  )  {
        log_err("FAIL: compareLong failed\n");
    }
    /*set the resize policy to just GROW and SHRINK*/
         /*how to test this??*/
    uhash_setResizePolicy(hash, U_GROW_AND_SHRINK);
    uhash_iputi(hash, 1004, 4, &status);
    uhash_iputi(hash, 1005, 5, &status);
    uhash_iputi(hash, 1006, 6, &status);
    if(uhash_count(hash) != 6){
        log_err("FAIL: uhash_count() failed. Expected: 6, Got: %d\n", uhash_count(hash));
    }
    if(uhash_iremovei(hash, 1004) != 4){
        log_err("FAIL: uhash_remove failed\n");
    }
    if(uhash_iremovei(hash, 1004) != 0){
        log_err("FAIL: uhash_remove failed\n");
    }

    uhash_removeAll(hash);
    uhash_iput(hash, 2004, (void*)one, &status);
    uhash_iput(hash, 2005, (void*)two, &status);
    if(uhash_count(hash) != 2){
        log_err("FAIL: uhash_count() failed. Expected: 2, Got: %d\n", uhash_count(hash));
    }
    if(uhash_iremove(hash, 2004) != (void*)one){
        log_err("FAIL: uhash_remove failed\n");
    }
    if(uhash_iremove(hash, 2004) != NULL){
        log_err("FAIL: uhash_remove failed\n");
    }
    if(uhash_count(hash) != 1){
        log_err("FAIL: uhash_count() failed. Expected: 1, Got: %d\n", uhash_count(hash));
    }

    uhash_close(hash);

}