in src/lru_cache.c [165:264]
static LRU_CACHE_EVICT_RESULT evict_internal(LRU_CACHE_HANDLE lru_cache, CLDS_HAZARD_POINTERS_THREAD_HANDLE hazard_pointers_thread)
{
LRU_CACHE_EVICT_RESULT result = LRU_CACHE_EVICT_OK;
while(result == LRU_CACHE_EVICT_OK)
{
/*Codes_SRS_LRU_CACHE_13_040: [ lru_cache_put shall acquire the lock in exclusive. ]*/
srw_lock_ll_acquire_exclusive(&lru_cache->srw_lock);
int64_t current_size = interlocked_add_64(&lru_cache->current_size, 0);
if (current_size <= lru_cache->capacity)
{
srw_lock_ll_release_exclusive(&lru_cache->srw_lock);
break;
}
else
{
/*Codes_SRS_LRU_CACHE_13_037: [ While the current size of the cache exceeds capacity: ]*/
if (DList_IsListEmpty(&lru_cache->head))
{
/*Codes_SRS_LRU_CACHE_13_050: [ For any other errors, lru_cache_put shall return LRU_CACHE_PUT_ERROR ]*/
LogError("Something is wrong. The cache is empty but there is no capacity. current_size = %" PRId64 "", current_size);
srw_lock_ll_release_exclusive(&lru_cache->srw_lock);
lru_cache->on_error_callback(lru_cache->on_error_context);
result = LRU_CACHE_EVICT_ERROR;
break;
}
/*Codes_SRS_LRU_CACHE_13_038: [ lru_cache_put shall get the least used node which is Flink of head node. ]*/
DLIST_ENTRY* least_used_node = lru_cache->head.Flink;
LRU_NODE* least_used_node_value = CONTAINING_RECORD(least_used_node, LRU_NODE, node);
if (current_size - least_used_node_value->size < 0)
{
/*Codes_SRS_LRU_CACHE_13_050: [ For any other errors, lru_cache_put shall return LRU_CACHE_PUT_ERROR ]*/
LogError("current_size - least_used_node_value is less than 0. current_size=%" PRId64 ", least_used_node_value->size=%" PRId64 " Failing eviction. ", current_size, least_used_node_value->size);
srw_lock_ll_release_exclusive(&lru_cache->srw_lock);
lru_cache->on_error_callback(lru_cache->on_error_context);
result = LRU_CACHE_EVICT_ERROR;
break;
}
else
{
/*Codes_SRS_LRU_CACHE_13_072: [ lru_cache_put shall decrement the least used node size from current_size. ]*/
if (interlocked_compare_exchange_64(&lru_cache->current_size, current_size - least_used_node_value->size, current_size) != current_size)
{
// something changed
srw_lock_ll_release_exclusive(&lru_cache->srw_lock);
continue;
}
else
{
CLDS_HASH_TABLE_ITEM* entry;
/*Codes_SRS_LRU_CACHE_13_039: [ The least used node is removed from clds_hash_table by calling clds_hash_table_remove. ]*/
CLDS_HASH_TABLE_REMOVE_RESULT remove_result = clds_hash_table_remove(lru_cache->table, hazard_pointers_thread, least_used_node_value->key, &entry, NULL);
switch (remove_result)
{
case CLDS_HASH_TABLE_REMOVE_OK:
{
/*Codes_SRS_LRU_CACHE_13_041: [ lru_cache_put shall remove the old node from the list by calling DList_RemoveEntryList. ]*/
(void)DList_RemoveEntryList(least_used_node);
LogVerbose("Removed DList entry with key=%p and size=%" PRId64 " in order to evict the lru node.", least_used_node_value->key, least_used_node_value->size);
/*Codes_SRS_LRU_CACHE_13_043: [ On success, evict_callback is called with the evicted item. ]*/
least_used_node_value->evict_callback(least_used_node_value->evict_callback_context, least_used_node_value->value);
CLDS_HASH_TABLE_NODE_RELEASE(LRU_NODE, entry);
break;
}
case CLDS_HASH_TABLE_REMOVE_NOT_FOUND:
{
/*Codes_SRS_LRU_CACHE_13_078: [ If clds_hash_table_remove returns CLDS_HASH_TABLE_REMOVE_NOT_FOUND, then lru_cache_put shall retry eviction. ]*/
LogError("item with key =%p has already been evicted.", least_used_node_value->key);
(void)interlocked_add_64(&lru_cache->current_size, least_used_node_value->size);
break;
}
default:
case CLDS_HASH_TABLE_REMOVE_ERROR:
{
/*Codes_SRS_LRU_CACHE_13_050: [ For any other errors, lru_cache_put shall return LRU_CACHE_PUT_ERROR ]*/
LogError("Error removing item with key =%p from hash table", least_used_node_value->key);
result = LRU_CACHE_EVICT_ERROR;
lru_cache->on_error_callback(lru_cache->on_error_context);
(void)interlocked_add_64(&lru_cache->current_size, least_used_node_value->size);
break;
}
}
}
}
}
/*Codes_SRS_LRU_CACHE_13_042: [ lru_cache_put shall release the lock in exclusive mode. ]*/
srw_lock_ll_release_exclusive(&lru_cache->srw_lock);
}
return result;
}