in src/clds_hash_table.c [1098:1247]
CLDS_HASH_TABLE_SNAPSHOT_RESULT clds_hash_table_snapshot(CLDS_HASH_TABLE_HANDLE clds_hash_table, CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread, CLDS_HASH_TABLE_ITEM*** items, uint64_t* item_count, THANDLE(CANCELLATION_TOKEN) cancellation_token)
{
CLDS_HASH_TABLE_SNAPSHOT_RESULT result;
if (
/* Codes_SRS_CLDS_HASH_TABLE_42_013: [ If clds_hash_table is NULL then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
(clds_hash_table == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_42_014: [ If clds_hazard_pointers_thread is NULL then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
(clds_hazard_pointers_thread == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_42_015: [ If items is NULL then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
(items == NULL) ||
/* Codes_SRS_CLDS_HASH_TABLE_42_016: [ If item_count is NULL then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
(item_count == NULL)
)
{
LogError("Invalid arguments: CLDS_HASH_TABLE_HANDLE clds_hash_table=%p, CLDS_HAZARD_POINTERS_THREAD_HANDLE clds_hazard_pointers_thread=%p, CLDS_HASH_TABLE_ITEM*** items=%p, uint64_t* item_count=%p, THANDLE(CANCELLATION_TOKEN) cancellation_token=%p",
clds_hash_table, clds_hazard_pointers_thread, items, item_count, cancellation_token);
result = CLDS_HASH_TABLE_SNAPSHOT_ERROR;
}
else
{
internal_lock_writes(clds_hash_table);
uint64_t temp_item_count = 0;
/* Codes_SRS_CLDS_HASH_TABLE_01_114: [ clds_hash_table_snapshot shall determine all the items in the hash table by summing up the item count for all bucket arrays in all levels. ]*/
BUCKET_ARRAY* 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);
temp_item_count += interlocked_add(¤t_bucket_array->item_count, 0);
current_bucket_array = next_bucket_array;
}
if (temp_item_count == 0)
{
/* Codes_SRS_CLDS_HASH_TABLE_42_064: [ If there are no items then clds_hash_table_snapshot shall set items to NULL and item_count to 0 and return CLDS_HASH_TABLE_SNAPSHOT_OK. ]*/
*items = NULL;
*item_count = 0;
result = CLDS_HASH_TABLE_SNAPSHOT_OK;
}
else
{
/* Codes_SRS_CLDS_HASH_TABLE_42_023: [ clds_hash_table_snapshot shall allocate an array of CLDS_HASH_TABLE_ITEM* ]*/
CLDS_SORTED_LIST_ITEM** items_to_return = malloc_2((size_t)temp_item_count, sizeof(CLDS_SORTED_LIST_ITEM*));
if (items_to_return == NULL)
{
/* Codes_SRS_CLDS_HASH_TABLE_42_061: [ If there are any other failures then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
LogError("malloc_2((size_t)temp_item_count=%zu, sizeof(CLDS_SORTED_LIST_ITEM*)=%zu) failed for the items to return",
(size_t)temp_item_count, sizeof(CLDS_SORTED_LIST_ITEM*));
result = CLDS_HASH_TABLE_SNAPSHOT_ERROR;
}
else
{
uint64_t result_index = 0;
bool is_cancelled = false;
/* Codes_SRS_CLDS_HASH_TABLE_42_024: [ For each bucket in the array: ]*/
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)
{
int32_t bucket_count = interlocked_add(¤t_bucket_array->bucket_count, 0);
int32_t i;
for (i = 0; i < bucket_count; i++)
{
if ((current_bucket_array->hash_table[i] != NULL) && (temp_item_count > 0))
{
uint64_t retrieved_item_count;
if (
/* Codes_SRS_CLDS_HASH_TABLE_01_115: [ If cancellation_token is non-NULL and cancellation_token_is_cancelled returns true for cancellation_token, clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ABANDONED. ]*/
(cancellation_token != NULL) &&
(cancellation_token_is_canceled(cancellation_token))
)
{
LogVerbose("snapshot cancelled");
is_cancelled = true;
break;
}
/* Codes_SRS_CLDS_HASH_TABLE_42_026: [ clds_hash_table_snapshot shall call clds_sorted_list_get_all with the next portion of the allocated array and false as required_locked_list. ]*/
CLDS_SORTED_LIST_GET_ALL_RESULT get_all_result = clds_sorted_list_get_all(current_bucket_array->hash_table[i], clds_hazard_pointers_thread, temp_item_count, items_to_return + result_index, &retrieved_item_count, false);
if (get_all_result != CLDS_SORTED_LIST_GET_ALL_OK)
{
/* Codes_SRS_CLDS_HASH_TABLE_42_061: [ If there are any other failures then clds_hash_table_snapshot shall fail and return CLDS_HASH_TABLE_SNAPSHOT_ERROR. ]*/
LogError("clds_sorted_list_get_all failed with %" PRI_MU_ENUM, MU_ENUM_VALUE(CLDS_SORTED_LIST_GET_ALL_RESULT, get_all_result));
break;
}
else
{
result_index += retrieved_item_count;
temp_item_count -= retrieved_item_count;
}
}
}
if (i < bucket_count)
{
break;
}
}
current_bucket_array = next_bucket_array;
}
if (current_bucket_array != NULL)
{
if (is_cancelled)
{
result = CLDS_HASH_TABLE_SNAPSHOT_ABANDONED;
}
else
{
result = CLDS_HASH_TABLE_SNAPSHOT_ERROR;
}
for (uint64_t i = 0; i < result_index; i++)
{
clds_sorted_list_node_release(items_to_return[i]);
}
free(items_to_return);
}
else
{
/* Codes_SRS_CLDS_HASH_TABLE_42_028: [ clds_hash_table_snapshot shall store the allocated array of items in items. ]*/
*items = (CLDS_HASH_TABLE_ITEM**)items_to_return;
items_to_return = NULL;
/* Codes_SRS_CLDS_HASH_TABLE_42_029: [ clds_hash_table_snapshot shall store the count of items in item_count. ]*/
*item_count = result_index;
/* Codes_SRS_CLDS_HASH_TABLE_42_031: [ clds_hash_table_snapshot shall succeed and return CLDS_HASH_TABLE_SNAPSHOT_OK. ]*/
result = CLDS_HASH_TABLE_SNAPSHOT_OK;
}
}
}
internal_unlock_writes(clds_hash_table);
}
return result;
}