in src/clds_hash_table.c [527:619]
CLDS_HASH_TABLE_DELETE_RESULT clds_hash_table_delete(CLDS_HASH_TABLE_HANDLE clds_hash_table, CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread, void* key, int64_t* sequence_number)
{
CLDS_HASH_TABLE_DELETE_RESULT result;
if (
/* Codes_SRS_CLDS_HASH_TABLE_01_015: [ If clds_hash_table is NULL, clds_hash_table_delete shall fail and return CLDS_HASH_TABLE_DELETE_ERROR. ]*/
(clds_hash_table == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_01_017: [ If clds_hazard_pointers_thread is NULL, clds_hash_table_delete shall fail and return CLDS_HASH_TABLE_DELETE_ERROR. ]*/
(clds_hazard_pointers_thread == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_01_016: [ If key is NULL, clds_hash_table_delete shall fail and return CLDS_HASH_TABLE_DELETE_ERROR. ]*/
(key == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_01_066: [ If the sequence_number argument is non-NULL, but no start sequence number was specified in clds_hash_table_create, clds_hash_table_delete shall fail and return CLDS_HASH_TABLE_DELETE_ERROR. ]*/
((sequence_number != NULL) && (clds_hash_table->sequence_number == NULL))
)
{
LogError("Invalid arguments: CLDS_HASH_TABLE_HANDLE clds_hash_table=%p, CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread=%p, void* key=%p, int64_t* sequence_number=%p",
clds_hash_table, key, clds_hazard_pointers_thread, sequence_number);
result = CLDS_HASH_TABLE_DELETE_ERROR;
}
else
{
/* Codes_SRS_CLDS_HASH_TABLE_42_037: [ clds_hash_table_delete shall try the following until it acquires a write lock for the table: ]*/
/* Codes_SRS_CLDS_HASH_TABLE_42_038: [ clds_hash_table_delete shall increment the count of pending write operations. ]*/
/* Codes_SRS_CLDS_HASH_TABLE_42_039: [ If the counter to lock the table for writes is non-zero then: ]*/
/* Codes_SRS_CLDS_HASH_TABLE_42_040: [ clds_hash_table_delete shall decrement the count of pending write operations. ]*/
/* Codes_SRS_CLDS_HASH_TABLE_42_041: [ clds_hash_table_delete shall wait for the counter to lock the table for writes to reach 0 and repeat. ]*/
check_lock_and_begin_write_operation(clds_hash_table);
CLDS_SORTED_LIST_HANDLE bucket_list;
BUCKET_ARRAY* current_bucket_array;
// compute the hash
/* Codes_SRS_CLDS_HASH_TABLE_01_039: [ clds_hash_table_delete shall hash the key by calling the compute_hash function passed to clds_hash_table_create. ]*/
uint64_t hash = clds_hash_table->compute_hash(key);
result = CLDS_HASH_TABLE_DELETE_NOT_FOUND;
// always delete starting with the first bucket array
/* Codes_SRS_CLDS_HASH_TABLE_01_101: [ Otherwise, key shall be looked up in each of the arrays of buckets starting with the first. ]*/
current_bucket_array = interlocked_compare_exchange_pointer((void* volatile_atomic*)&clds_hash_table->first_hash_table, NULL, NULL);
while (current_bucket_array != NULL)
{
BUCKET_ARRAY* next_bucket_array = interlocked_compare_exchange_pointer((void* volatile_atomic*)¤t_bucket_array->next_bucket, NULL, NULL);
if (interlocked_add(¤t_bucket_array->item_count, 0) != 0)
{
// find the bucket
uint64_t bucket_index = hash % interlocked_add(¤t_bucket_array->bucket_count, 0);
bucket_list = interlocked_compare_exchange_pointer((void* volatile_atomic*)¤t_bucket_array->hash_table[bucket_index], NULL, NULL);
if (bucket_list == NULL)
{
/* Codes_SRS_CLDS_HASH_TABLE_01_023: [ If the desired key is not found in the hash table (not found in any of the arrays of buckets), clds_hash_table_delete shall return CLDS_HASH_TABLE_DELETE_NOT_FOUND. ]*/
result = CLDS_HASH_TABLE_DELETE_NOT_FOUND;
}
else
{
CLDS_SORTED_LIST_DELETE_RESULT list_delete_result;
/* Codes_SRS_CLDS_HASH_TABLE_01_063: [ For each delete the order of the operation shall be computed by passing sequence_number to clds_sorted_list_delete_key. ]*/
list_delete_result = clds_sorted_list_delete_key(bucket_list, clds_hazard_pointers_thread, key, sequence_number);
if (list_delete_result == CLDS_SORTED_LIST_DELETE_NOT_FOUND)
{
// not found
/* Codes_SRS_CLDS_HASH_TABLE_01_023: [ If the desired key is not found in the hash table (not found in any of the arrays of buckets), clds_hash_table_delete shall return CLDS_HASH_TABLE_DELETE_NOT_FOUND. ]*/
}
else if (list_delete_result == CLDS_SORTED_LIST_DELETE_OK)
{
(void)interlocked_decrement(¤t_bucket_array->item_count);
/* Codes_SRS_CLDS_HASH_TABLE_01_014: [ On success clds_hash_table_delete shall return CLDS_HASH_TABLE_DELETE_OK. ]*/
result = CLDS_HASH_TABLE_DELETE_OK;
break;
}
else
{
/* Codes_SRS_CLDS_HASH_TABLE_01_024: [ If a bucket is identified and the delete of the item from the underlying list fails, clds_hash_table_delete shall fail and return CLDS_HASH_TABLE_DELETE_ERROR. ]*/
result = CLDS_HASH_TABLE_DELETE_ERROR;
break;
}
}
}
/* Codes_SRS_CLDS_HASH_TABLE_01_025: [ If the element to be deleted is not found in an array of buckets, then it shall be looked up in the next available array of buckets. ] */
current_bucket_array = next_bucket_array;
}
/* Codes_SRS_CLDS_HASH_TABLE_42_042: [ clds_hash_table_insert shall decrement the count of pending write operations. ]*/
end_write_operation(clds_hash_table);
}
return result;
}