Removes the "try free" behavior from the skip lists (#1126)

* Removes the "try free" behavior from the skip lists

This was only used in the ID code when iterating and a callback
could delete IDs. It is not used anywhere else in the library and
is now pointless overhead.

Also quiets the const warnings when returning stored elements. They
only need to be const with respect to the skip list code, which should
never modify them. The library can do whatever it wants with the elements
it stored.

* Formatted source
This commit is contained in:
Dana Robinson 2021-10-22 08:02:28 -07:00 committed by GitHub
parent 4600e10106
commit b0bd984ed6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 205 additions and 683 deletions

File diff suppressed because it is too large Load Diff

View File

@ -60,9 +60,6 @@ typedef int (*H5SL_cmp_t)(const void *key1, const void *key2);
/* Typedef for iteration operations */
typedef herr_t (*H5SL_operator_t)(void *item, void *key, void *operator_data /*in,out*/);
/* Typedef for H5SL_try_free_safe operation callback */
typedef htri_t (*H5SL_try_free_op_t)(void *item, void *key, void *operator_data /*in,out*/);
/********************/
/* Private routines */
/********************/
@ -86,7 +83,6 @@ H5_DLL void * H5SL_item(H5SL_node_t *slist_node);
H5_DLL herr_t H5SL_iterate(H5SL_t *slist, H5SL_operator_t op, void *op_data);
H5_DLL herr_t H5SL_release(H5SL_t *slist);
H5_DLL herr_t H5SL_free(H5SL_t *slist, H5SL_operator_t op, void *op_data);
H5_DLL herr_t H5SL_try_free_safe(H5SL_t *slist, H5SL_try_free_op_t op, void *op_data);
H5_DLL herr_t H5SL_close(H5SL_t *slist);
H5_DLL herr_t H5SL_destroy(H5SL_t *slist, H5SL_operator_t op, void *op_data);
H5_DLL int H5SL_term_interface(void);

View File

@ -1163,213 +1163,6 @@ test_skiplist_free(void)
} /* end test_skiplist_free() */
/****************************************************************
**
** test_skiplist_try_free_safe(): Test H5SL (skip list) code.
** Tests 'try_free_safe' operation in skip lists.
**
****************************************************************/
/* Macro definitions */
#define TEST_TFS_MAX_NOBJS 100
#define TEST_TFS_MIN_NOBJS 5
#define TEST_TFS_NITER 50
/* Structure to hold the list of objects */
typedef struct {
H5SL_t * slist; /* Skiplist holding the objects */
struct test_tfs_obj_t *list; /* Linear list of objects */
int nobjs; /* Number of objects in list */
int nobjs_rem; /* Number of objects in list that have not been freed */
} test_tfs_list_t;
/* Structure for an object */
typedef struct test_tfs_obj_t {
int idx; /* Index (key) for this object */
int nfrees; /* Number of times this object has been freed */
} test_tfs_obj_t;
/* op_data struct for H5SL_iterate() */
typedef struct test_tfs_it_ud_t {
test_tfs_list_t *obj_list; /* List of objects */
int last_idx; /* Index of last object visited in iteration */
int ncalls; /* Number of times this callback was called */
} test_tfs_it_ud_t;
/* iterate callback */
static herr_t
test_tfs_iter(void *_obj, void *key, void *_udata)
{
test_tfs_obj_t * obj = (test_tfs_obj_t *)_obj;
test_tfs_it_ud_t *udata = (test_tfs_it_ud_t *)_udata;
/* Check consistency */
CHECK_PTR_EQ((void *)&obj->idx, key, "obj->idx");
CHECK_PTR_EQ(obj, &udata->obj_list->list[obj->idx], "obj_list->list[obj->idx]");
/* Increment number of calls */
udata->ncalls++;
/* Verify we were given the correct object */
do {
udata->last_idx++;
} while (udata->obj_list->list[udata->last_idx].nfrees != 0);
VERIFY(udata->last_idx, obj->idx, "H5SL_iterate");
return 0;
} /* end test_tfs_iter() */
/* try_free_safe callback */
static htri_t
test_tfs_free(void *_obj, void *key, void *_obj_list)
{
test_tfs_obj_t * obj = (test_tfs_obj_t *)_obj;
test_tfs_list_t *obj_list = (test_tfs_list_t *)_obj_list;
test_tfs_it_ud_t iter_ud;
int nrems, rem_idx, i, j;
test_tfs_obj_t * obj_ret;
herr_t ret; /* return value */
htri_t ret_value;
/* Check consistency */
CHECK_PTR_EQ((void *)&obj->idx, key, "obj->idx");
CHECK_PTR_EQ(obj, &obj_list->list[obj->idx], "obj_list->list[obj->idx]");
/* Mark this object as freed (to make sure it isn't recursively freed, that
* is not something we support, we will undo this if we decide later not to
* free the object) */
obj->nfrees++;
obj_list->nobjs_rem--;
/* Decide how many objects to remove */
nrems = (int)(HDrandom() % (long)3);
/* Remove objects */
for (i = 0; i < nrems; i++)
/* Check nobjs_rem */
if (obj_list->nobjs_rem > 0) {
/* Remove a random object from the list */
rem_idx = (int)(HDrandom() % (long)obj_list->nobjs_rem);
/* Scan the list, finding the rem_idx'th object that has not been
* freed */
for (j = 0; j < obj_list->nobjs; j++)
if (obj_list->list[j].nfrees == 0) {
if (rem_idx == 0)
break;
else
rem_idx--;
} /* end if */
if (j == obj_list->nobjs)
ERROR("invalid obj_list");
else {
/* Remove the object */
obj_ret = (test_tfs_obj_t *)H5SL_remove(obj_list->slist, &j);
CHECK_PTR(obj_ret, "H5SL_remove");
obj_ret->nfrees++;
obj_list->nobjs_rem--;
} /* end else */
} /* end if */
/* Mark this object as not freed so we know to expect it in the iterate call
*/
obj->nfrees--;
obj_list->nobjs_rem++;
/* Iterate over skip list (maybe) */
if (HDrandom() % (long)5) {
iter_ud.obj_list = obj_list;
iter_ud.last_idx = -1;
iter_ud.ncalls = 0;
ret = H5SL_iterate(obj_list->slist, test_tfs_iter, &iter_ud);
CHECK(ret, FAIL, "H5SL_iterate");
VERIFY(iter_ud.ncalls, obj_list->nobjs_rem, "H5SL_iterate");
} /* end if */
/* Verify nobjs_rem is non-negative */
if (obj_list->nobjs_rem < 0)
ERROR("invalid nobjs_rem");
/* Decide whether this object should be freed */
if (HDrandom() % (long)2) {
/* Free the object */
ret_value = TRUE;
obj->nfrees++;
obj_list->nobjs_rem--;
} /* end if */
else
/* Do not free the object */
ret_value = FALSE;
return ret_value;
} /* end test_tfs_free() */
/* Test function */
static void
test_skiplist_try_free_safe(void)
{
test_tfs_list_t obj_list;
test_tfs_obj_t list[TEST_TFS_MAX_NOBJS];
int i, j;
int nobjs_found;
hsize_t count;
herr_t ret; /* Generic return value */
/* Output message about test being performed */
MESSAGE(7, ("Testing Skip List 'Try Free Safe' Operation\n"));
/* Create a skip list */
obj_list.slist = H5SL_create(H5SL_TYPE_INT, NULL);
CHECK_PTR(obj_list.slist, "H5SL_create");
/* Init obj_list.list */
obj_list.list = list;
for (j = 0; j < TEST_TFS_MAX_NOBJS; j++)
list[j].idx = j;
for (i = 0; i < TEST_TFS_NITER; i++) {
/* Build object list */
obj_list.nobjs = obj_list.nobjs_rem =
(int)(TEST_TFS_MIN_NOBJS + (HDrandom() % (long)(TEST_TFS_MAX_NOBJS - TEST_TFS_MIN_NOBJS + 1)));
for (j = 0; j < obj_list.nobjs; j++) {
list[j].nfrees = 0;
ret = H5SL_insert(obj_list.slist, &list[j], &list[j].idx);
CHECK(ret, FAIL, "H5SL_insert");
} /* end for */
/* Call H5S_try_free_safe() - free most of the items in the skip list in
* a safe manner */
ret = H5SL_try_free_safe(obj_list.slist, test_tfs_free, &obj_list);
CHECK(ret, FAIL, "H5SL_try_free_safe");
/* Verify list */
nobjs_found = 0;
for (j = 0; j < obj_list.nobjs; j++)
if (list[j].nfrees == 0)
nobjs_found++;
else
VERIFY(list[j].nfrees, (long)1, "list[j].nfrees");
/* Verify number of objects */
VERIFY(obj_list.nobjs_rem, nobjs_found, "obj_list.nobjs_rem");
count = H5SL_count(obj_list.slist);
VERIFY(count, (size_t)nobjs_found, "H5SL_count");
/* Release the skip list, forcibly freeing all nodes (will not make
* callbacks) */
ret = H5SL_release(obj_list.slist);
CHECK(ret, FAIL, "H5SL_release");
/* Verify number of objects is 0 */
count = H5SL_count(obj_list.slist);
VERIFY(count, (size_t)0, "H5SL_count");
} /* end for */
/* Close the skip list */
ret = H5SL_close(obj_list.slist);
CHECK(ret, FAIL, "H5SL_close");
} /* end test_skiplist_try_free_safe() */
/****************************************************************
**
** test_skiplist_less(): Test H5SL (skip list) code.
@ -1796,7 +1589,6 @@ test_skiplist(void)
test_skiplist_add(); /* Test 'add' operation */
test_skiplist_destroy(); /* Test 'destroy' operation */
test_skiplist_free(); /* Test 'free' operation */
test_skiplist_try_free_safe(); /* Test 'try_free_safe' operation */
test_skiplist_less(); /* Test 'less' operation */
test_skiplist_greater(); /* Test 'greater' operation */
test_skiplist_below(); /* Test 'below' operation */