diff --git a/src/lib/salad/bps_tree.h b/src/lib/salad/bps_tree.h index 762750785cf2206eaa883a29166814c537860b37..1a55035d29b93aa3d358edad15522361b7b8754a 100644 --- a/src/lib/salad/bps_tree.h +++ b/src/lib/salad/bps_tree.h @@ -156,6 +156,8 @@ * bps_tree_elem_t *bps_tree_itr_get_elem(tree, itr); * bool bps_tree_itr_next(tree, itr); * bool bps_tree_itr_prev(tree, itr); + * bool bps_tree_itr_freeze(tree, itr); + * void bps_tree_itr_destroy(tree, itr); */ /* }}} */ @@ -354,6 +356,8 @@ typedef uint32_t bps_tree_block_id_t; #define bps_tree_itr_get_elem _bps_tree(itr_get_elem) #define bps_tree_itr_next _bps_tree(itr_next) #define bps_tree_itr_prev _bps_tree(itr_prev) +#define bps_tree_itr_freeze _bps_tree(itr_freeze) +#define bps_tree_itr_destroy _bps_tree(itr_destroy) #define bps_tree_debug_check _bps_tree(debug_check) #define bps_tree_print _bps_tree(print) #define bps_tree_debug_check_internal_functions \ @@ -369,6 +373,9 @@ typedef uint32_t bps_tree_block_id_t; #define BPS_TREE_BT_LEAF _BPS_TREE(BT_LEAF) #define bps_tree_restore_block _bps_tree(restore_block) +#define bps_tree_restore_block_ver _bps_tree(restore_block_ver) +#define bps_tree_root _bps_tree(root) +#define bps_tree_before_change_block _bps_tree(before_change_block) #define bps_tree_find_ins_point_key _bps_tree(find_ins_point_key) #define bps_tree_find_ins_point_elem _bps_tree(find_ins_point_elem) #define bps_tree_find_after_ins_point_key _bps_tree(find_after_ins_point_key) @@ -450,8 +457,6 @@ typedef uint32_t bps_tree_block_id_t; _bps_tree(debug_check_insert_and_move_to_right_inner) #define bps_tree_debug_check_insert_and_move_to_left_inner \ _bps_tree(debug_check_insert_and_move_to_left_inner) -#define bps_tree_debug_check_insert_and_move_to_left_inner \ - _bps_tree(debug_check_insert_and_move_to_left_inner) /* }}} */ /* {{{ BPS-tree interface (declaration) */ @@ -472,9 +477,7 @@ typedef uint32_t bps_tree_block_id_t; * Main tree struct. One instance - one tree. */ struct bps_tree { - /* Pointer to root block. Is NULL in empty tree. */ - struct bps_block *root; - /* ID of root block. Undefined in empty tree. */ + /* ID of root block. (bps_tree_block_id_t)-1 in empty tree. */ bps_tree_block_id_t root_id; /* IDs of first and last block. (-1) in empty tree. */ bps_tree_block_id_t first_id, last_id; @@ -485,7 +488,7 @@ struct bps_tree { /* Number of elements in tree */ size_t size; /* Head of list of garbaged blocks */ - struct bps_garbage *garbage_head; + bps_tree_block_id_t garbage_head_id; /* User-provided argument for comparator */ bps_tree_arg_t arg; /* Copy of maximal element in tree. Used for beauty */ @@ -521,6 +524,8 @@ struct bps_tree_iterator { bps_tree_block_id_t block_id; /* Position of an element in the block. Could be -1 for last in block*/ bps_tree_pos_t pos; + /* Version of matras memory. 0 for main version, nonzero for MVCC */ + bps_tree_pos_t matras_version; }; /** @@ -736,6 +741,26 @@ bps_tree_itr_next(const struct bps_tree *tree, struct bps_tree_iterator *itr); bool bps_tree_itr_prev(const struct bps_tree *tree, struct bps_tree_iterator *itr); +/** + * @brief Freezes tree state for given iterator. All following tree modification + * will not apply to that iterator iteration. That iterator should be destroyed + * with a bps_tree_itr_destroy call after usage. + * @param tree - pointer to a tree + * @param itr - pointer to tree iterator + * @return - true on success, false if no more version is available in matras + */ +bool +bps_tree_itr_freeze(struct bps_tree *tree, struct bps_tree_iterator *itr); + +/** + * @brief Destroy an iterator that was frozen before. Useless for not frozen + * iterators. + * @param tree - pointer to a tree + * @param itr - pointer to tree iterator + */ +void +bps_tree_itr_destroy(struct bps_tree *tree, struct bps_tree_iterator *itr); + /** * @brief Debug self-checking. Returns bitmask of found errors (0 * on success). @@ -755,7 +780,6 @@ bps_tree_debug_check(const struct bps_tree *tree); void bps_tree_print(const struct bps_tree *tree, const char *elem_fmt); - /** * @brief Debug print tree to output in readable form. * I hope you will not need it. @@ -768,7 +792,6 @@ bps_tree_debug_check_internal_functions(bool assertme); /* }}} */ - /* {{{ BPS-tree implementation (definition) */ /* Data moving */ @@ -873,10 +896,8 @@ CT_ASSERT_G(sizeof(struct bps_inner) <= BPS_TREE_BLOCK_SIZE); struct bps_garbage { /* Block header */ struct bps_block header; - /* Stored id of this block */ - bps_tree_block_id_t id; - /* Next garbaged block in single-linked list */ - struct bps_garbage *next; + /* Next garbaged block id in single-linked list */ + bps_tree_block_id_t next_id; }; /** @@ -936,7 +957,7 @@ bps_tree_create(struct bps_tree *tree, bps_tree_arg_t arg, bps_tree_extent_alloc_f extent_alloc_func, bps_tree_extent_free_f extent_free_func) { - tree->root = 0; + tree->root_id = (bps_tree_block_id_t)(-1); tree->first_id = (bps_tree_block_id_t)(-1); tree->last_id = (bps_tree_block_id_t)(-1); tree->leaf_count = 0; @@ -944,7 +965,7 @@ bps_tree_create(struct bps_tree *tree, bps_tree_arg_t arg, tree->garbage_count = 0; tree->depth = 0; tree->size = 0; - tree->garbage_head = 0; + tree->garbage_head_id = (bps_tree_block_id_t)(-1); tree->arg = arg; matras_create(&tree->matras, @@ -971,15 +992,15 @@ bps_tree_create(struct bps_tree *tree, bps_tree_arg_t arg, * @param tree - pointer to a tree * @param sorted_array - pointer to the sorted array * @param array_size - size of the array (count of elements) - * @return true on success, false on memory error + * @return true on success, false on memory error */ inline bool bps_tree_build(struct bps_tree *tree, bps_tree_elem_t *sorted_array, size_t array_size) { assert(tree->size == 0); - assert(tree->root == 0); - assert(tree->garbage_head == 0); + assert(tree->root_id == (bps_tree_block_id_t)(-1)); + assert(tree->garbage_head_id == (bps_tree_block_id_t)(-1)); assert(tree->matras.block_counts[0] == 0); if (array_size == 0) return true; @@ -1015,7 +1036,6 @@ bps_tree_build(struct bps_tree *tree, bps_tree_elem_t *sorted_array, bps_tree_block_id_t last_leaf_id = (bps_tree_block_id_t)-1; bps_tree_block_id_t inner_count = 0; bps_tree_block_id_t root_if_inner_id = (bps_tree_block_id_t)-1; - struct bps_inner *root_if_inner = 0; do { bps_tree_block_id_t id; struct bps_leaf *new_leaf = (struct bps_leaf *) @@ -1058,7 +1078,6 @@ bps_tree_build(struct bps_tree *tree, bps_tree_elem_t *sorted_array, break; if (i == depth - 2) { root_if_inner_id = new_id; - root_if_inner = parents[i]; } else { insert_id = new_id; } @@ -1101,16 +1120,13 @@ bps_tree_build(struct bps_tree *tree, bps_tree_elem_t *sorted_array, tree->size = array_size; tree->max_elem = sorted_array[array_size - 1]; if (depth == 1) { - tree->root = (struct bps_block *)leaf; tree->root_id = first_leaf_id; } else { - tree->root = (struct bps_block *)root_if_inner; tree->root_id = root_if_inner_id; } return true; } - /** * @brief Tree destruction. Frees allocated memory. * @param tree - pointer to a tree @@ -1155,6 +1171,34 @@ bps_tree_restore_block(const struct bps_tree *tree, bps_tree_block_id_t id) return (struct bps_block *)matras_get(&tree->matras, id); } +/** + * @brief Get a pointer to block by it's ID and matras version. + */ +static inline struct bps_block * +bps_tree_restore_block_ver(const struct bps_tree *tree, bps_tree_block_id_t id, + bps_tree_pos_t ver) +{ + return (struct bps_block *)matras_getv(&tree->matras, id, ver); +} + +/** + * @brief Get a pointer to block by it's ID. + */ +static inline struct bps_block * +bps_tree_root(const struct bps_tree *tree) +{ + return (struct bps_block *)matras_get(&tree->matras, tree->root_id); +} + +/** + * @brief Get a pointer to block by it's ID. + */ +static inline struct bps_block * +bps_tree_before_change_block(struct bps_tree *tree, bps_tree_block_id_t id) +{ + return (struct bps_block *)matras_before_change(&tree->matras, id); +} + /** * @brief Get a random element in a tree. * @param tree - pointer to a tree @@ -1164,10 +1208,10 @@ bps_tree_restore_block(const struct bps_tree *tree, bps_tree_block_id_t id) inline bps_tree_elem_t * bps_tree_random(const struct bps_tree *tree, size_t rnd) { - if (!tree->root) + if (tree->root_id == (bps_tree_block_id_t)(-1)) return 0; - struct bps_block *block = tree->root; + struct bps_block *block = bps_tree_root(tree); for (bps_tree_block_id_t i = 0; i < tree->depth - 1; i++) { struct bps_inner *inner = (struct bps_inner *)block; @@ -1326,6 +1370,7 @@ bps_tree_invalid_iterator() struct bps_tree_iterator res; res.block_id = (bps_tree_block_id_t)(-1); res.pos = 0; + res.matras_version = 0; return res; } @@ -1354,7 +1399,9 @@ bps_tree_get_leaf_safe(const struct bps_tree *tree, if (itr->block_id == (bps_tree_block_id_t)(-1)) return 0; - struct bps_block *block = bps_tree_restore_block(tree, itr->block_id); + struct bps_block *block = + bps_tree_restore_block_ver(tree, itr->block_id, + itr->matras_version); if (block->type != BPS_TREE_BT_LEAF) { itr->block_id = (bps_tree_block_id_t)(-1); return 0; @@ -1420,6 +1467,7 @@ bps_tree_itr_first(const struct bps_tree *tree) struct bps_tree_iterator itr; itr.block_id = tree->first_id; itr.pos = 0; + itr.matras_version = 0; return itr; } @@ -1434,6 +1482,7 @@ bps_tree_itr_last(const struct bps_tree *tree) struct bps_tree_iterator itr; itr.block_id = tree->last_id; itr.pos = (bps_tree_pos_t)(-1); + itr.matras_version = 0; return itr; } @@ -1452,16 +1501,17 @@ bps_tree_lower_bound(const struct bps_tree *tree, bps_tree_key_t key, bool *exact) { struct bps_tree_iterator res; + res.matras_version = 0; bool local_result; if (!exact) exact = &local_result; *exact = false; - if (!tree->root) { + if (tree->root_id == (bps_tree_block_id_t)(-1)) { res.block_id = (bps_tree_block_id_t)(-1); res.pos = 0; return res; } - struct bps_block *block = tree->root; + struct bps_block *block = bps_tree_root(tree); bps_tree_block_id_t block_id = tree->root_id; for (bps_tree_block_id_t i = 0; i < tree->depth - 1; i++) { struct bps_inner *inner = (struct bps_inner *)block; @@ -1502,17 +1552,18 @@ bps_tree_upper_bound(const struct bps_tree *tree, bps_tree_key_t key, bool *exact) { struct bps_tree_iterator res; + res.matras_version = 0; bool local_result; if (!exact) exact = &local_result; *exact = false; bool exact_test; - if (!tree->root) { + if (tree->root_id == (bps_tree_block_id_t)(-1)) { res.block_id = (bps_tree_block_id_t)(-1); res.pos = 0; return res; } - struct bps_block *block = tree->root; + struct bps_block *block = bps_tree_root(tree); bps_tree_block_id_t block_id = tree->root_id; for (bps_tree_block_id_t i = 0; i < tree->depth - 1; i++) { struct bps_inner *inner = (struct bps_inner *)block; @@ -1573,6 +1624,8 @@ inline bool bps_tree_itr_next(const struct bps_tree *tree, struct bps_tree_iterator *itr) { if (itr->block_id == (bps_tree_block_id_t)(-1)) { + if (itr->matras_version) + return false; itr->block_id = tree->first_id; itr->pos = 0; return itr->block_id != (bps_tree_block_id_t)(-1); @@ -1602,6 +1655,8 @@ inline bool bps_tree_itr_prev(const struct bps_tree *tree, struct bps_tree_iterator *itr) { if (itr->block_id == (bps_tree_block_id_t)(-1)) { + if (itr->matras_version) + return false; itr->block_id = tree->last_id; itr->pos = (bps_tree_pos_t)(-1); return itr->block_id != (bps_tree_block_id_t)(-1); @@ -1619,6 +1674,36 @@ bps_tree_itr_prev(const struct bps_tree *tree, struct bps_tree_iterator *itr) return true; } +/** + * @brief Freezes tree state for given iterator. All following tree modification + * will not apply to that iterator iteration. That iterator should be destroyed + * with a bps_tree_itr_destroy call after usage. + * @param tree - pointer to a tree + * @param itr - pointer to tree iterator + */ +inline bool +bps_tree_itr_freeze(struct bps_tree *tree, struct bps_tree_iterator *itr) +{ + assert(itr->matras_version == 0); + itr->matras_version = matras_new_version(&tree->matras); + return itr->matras_version != 0; +} + +/** + * @brief Destroy an iterator that was frozen before. Useless for not frozen + * iterators. + * @param tree - pointer to a tree + * @param itr - pointer to tree iterator + */ +inline void +bps_tree_itr_destroy(struct bps_tree *tree, struct bps_tree_iterator *itr) +{ + if (itr->matras_version) { + matras_delete_version(&tree->matras, itr->matras_version); + itr->matras_version = 0; + } +} + /** * @brief Find the first element that is equal to the key (comparator returns 0) * @param tree - pointer to a tree @@ -1628,9 +1713,9 @@ bps_tree_itr_prev(const struct bps_tree *tree, struct bps_tree_iterator *itr) inline bps_tree_elem_t * bps_tree_find(const struct bps_tree *tree, bps_tree_key_t key) { - if (!tree->root) + if (tree->root_id == (bps_tree_block_id_t)(-1)) return 0; - struct bps_block *block = tree->root; + struct bps_block *block = bps_tree_root(tree); bool exact = false; for (bps_tree_block_id_t i = 0; i < tree->depth - 1; i++) { struct bps_inner *inner = (struct bps_inner *)block; @@ -1658,12 +1743,13 @@ static inline void bps_tree_garbage_push(struct bps_tree *tree, struct bps_block *block, bps_tree_block_id_t id) { - assert(block); - struct bps_garbage *garbage = (struct bps_garbage *)block; + assert(block); (void) block; + + struct bps_garbage *garbage = (struct bps_garbage *) + bps_tree_before_change_block(tree, id); garbage->header.type = BPS_TREE_BT_GARBAGE; - garbage->id = id; - garbage->next = tree->garbage_head; - tree->garbage_head = garbage; + garbage->next_id = tree->garbage_head_id; + tree->garbage_head_id = id; tree->garbage_count++; } @@ -1673,12 +1759,13 @@ bps_tree_garbage_push(struct bps_tree *tree, struct bps_block *block, static inline struct bps_block * bps_tree_garbage_pop(struct bps_tree *tree, bps_tree_block_id_t *id) { - if (tree->garbage_head) { - *id = tree->garbage_head->id; - struct bps_block *result = (bps_block *)tree->garbage_head; - tree->garbage_head = tree->garbage_head->next; + if (tree->garbage_head_id != (bps_tree_block_id_t)(-1)) { + *id = tree->garbage_head_id; + struct bps_garbage *result = (struct bps_garbage *) + bps_tree_before_change_block(tree, tree->garbage_head_id); + tree->garbage_head_id = result->next_id; tree->garbage_count--; - return result; + return (struct bps_block *) result; } else { return 0; } @@ -1768,7 +1855,6 @@ bps_tree_insert_first_elem(struct bps_tree *tree, bps_tree_elem_t new_elem) return false; leaf->header.size = 1; leaf->elems[0] = new_elem; - tree->root = (struct bps_block *)leaf; tree->first_id = tree->root_id; tree->last_id = tree->root_id; leaf->prev_id = (bps_tree_block_id_t)(-1); @@ -1790,7 +1876,7 @@ bps_tree_collect_path(struct bps_tree *tree, bps_tree_elem_t new_elem, bps_inner_path_elem *prev_ext = 0; bps_tree_pos_t prev_pos = 0; - struct bps_block *block = tree->root; + struct bps_block *block = bps_tree_root(tree); bps_tree_block_id_t block_id = tree->root_id; bps_tree_elem_t *max_elem_copy = &tree->max_elem; for (bps_tree_block_id_t i = 0; i < tree->depth - 1; i++) { @@ -1843,7 +1929,8 @@ bps_tree_process_replace(struct bps_tree *tree, struct bps_leaf_path_elem *leaf_path_elem, bps_tree_elem_t new_elem, bps_tree_elem_t *replaced) { - (void)tree; + leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, leaf_path_elem->block_id); struct bps_leaf *leaf = leaf_path_elem->block; assert(leaf_path_elem->insertion_point < leaf->header.size); @@ -1956,7 +2043,10 @@ bps_tree_insert_into_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *leaf_path_elem, bps_tree_elem_t new_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) + leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, leaf_path_elem->block_id); struct bps_leaf *leaf = leaf_path_elem->block; bps_tree_pos_t pos = leaf_path_elem->insertion_point; @@ -1981,7 +2071,10 @@ bps_tree_insert_into_inner(struct bps_tree *tree, bps_tree_block_id_t block_id, bps_tree_pos_t pos, bps_tree_elem_t max_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) + inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, inner_path_elem->block_id); struct bps_inner *inner = inner_path_elem->block; assert(pos >= 0); @@ -2012,7 +2105,10 @@ static inline void bps_tree_delete_from_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *leaf_path_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) + leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, leaf_path_elem->block_id); struct bps_leaf *leaf = leaf_path_elem->block; bps_tree_pos_t pos = leaf_path_elem->insertion_point; @@ -2038,7 +2134,10 @@ static inline void bps_tree_delete_from_inner(struct bps_tree *tree, bps_inner_path_elem *inner_path_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) + inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, inner_path_elem->block_id); struct bps_inner *inner = inner_path_elem->block; bps_tree_pos_t pos = inner_path_elem->insertion_point; @@ -2067,7 +2166,13 @@ bps_tree_move_elems_to_right_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *b_leaf_path_elem, bps_tree_pos_t num) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, a_leaf_path_elem->block_id); + b_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, b_leaf_path_elem->block_id); + } struct bps_leaf *a = a_leaf_path_elem->block; struct bps_leaf *b = b_leaf_path_elem->block; bool move_all = a->header.size == num; @@ -2098,7 +2203,13 @@ bps_tree_move_elems_to_right_inner(struct bps_tree *tree, bps_inner_path_elem *b_inner_path_elem, bps_tree_pos_t num) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, a_inner_path_elem->block_id); + b_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, b_inner_path_elem->block_id); + } struct bps_inner *a = a_inner_path_elem->block; struct bps_inner *b = b_inner_path_elem->block; bool move_to_empty = b->header.size == 0; @@ -2140,7 +2251,13 @@ bps_tree_move_elems_to_left_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *b_leaf_path_elem, bps_tree_pos_t num) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, a_leaf_path_elem->block_id); + b_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, b_leaf_path_elem->block_id); + } struct bps_leaf *a = a_leaf_path_elem->block; struct bps_leaf *b = b_leaf_path_elem->block; @@ -2166,7 +2283,13 @@ bps_tree_move_elems_to_left_inner(struct bps_tree *tree, bps_inner_path_elem *b_inner_path_elem, bps_tree_pos_t num) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, a_inner_path_elem->block_id); + b_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, b_inner_path_elem->block_id); + } struct bps_inner *a = a_inner_path_elem->block; struct bps_inner *b = b_inner_path_elem->block; bool move_to_empty = a->header.size == 0; @@ -2211,7 +2334,13 @@ bps_tree_insert_and_move_elems_to_right_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *b_leaf_path_elem, bps_tree_pos_t num, bps_tree_elem_t new_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, a_leaf_path_elem->block_id); + b_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, b_leaf_path_elem->block_id); + } struct bps_leaf *a = a_leaf_path_elem->block; struct bps_leaf *b = b_leaf_path_elem->block; bps_tree_pos_t pos = a_leaf_path_elem->insertion_point; @@ -2270,7 +2399,13 @@ bps_tree_insert_and_move_elems_to_right_inner(struct bps_tree *tree, bps_tree_pos_t num, bps_tree_block_id_t block_id, bps_tree_pos_t pos, bps_tree_elem_t max_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, a_inner_path_elem->block_id); + b_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, b_inner_path_elem->block_id); + } struct bps_inner *a = a_inner_path_elem->block; struct bps_inner *b = b_inner_path_elem->block; bool move_to_empty = b->header.size == 0; @@ -2398,7 +2533,13 @@ bps_tree_insert_and_move_elems_to_left_leaf(struct bps_tree *tree, struct bps_leaf_path_elem *b_leaf_path_elem, bps_tree_pos_t num, bps_tree_elem_t new_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, a_leaf_path_elem->block_id); + b_leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, b_leaf_path_elem->block_id); + } struct bps_leaf *a = a_leaf_path_elem->block; struct bps_leaf *b = b_leaf_path_elem->block; bps_tree_pos_t pos = b_leaf_path_elem->insertion_point; @@ -2456,7 +2597,13 @@ bps_tree_insert_and_move_elems_to_left_inner(struct bps_tree *tree, bps_tree_block_id_t block_id, bps_tree_pos_t pos, bps_tree_elem_t max_elem) { - (void)tree; + /* exclusive behaviuor for debug checks */ + if (tree->root_id != (bps_tree_block_id_t) -1) { + a_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, a_inner_path_elem->block_id); + b_inner_path_elem->block = (struct bps_inner *) + bps_tree_before_change_block(tree, b_inner_path_elem->block_id); + } struct bps_inner *a = a_inner_path_elem->block; struct bps_inner *b = b_inner_path_elem->block; bool move_to_empty = a->header.size == 0; @@ -2857,17 +3004,19 @@ bps_tree_process_insert_leaf(struct bps_tree *tree, return true; } } - bps_tree_block_id_t new_block_id = (bps_tree_block_id_t)(-1); - struct bps_leaf *new_leaf = bps_tree_create_leaf(tree, &new_block_id); if (!bps_tree_reserve_blocks(tree, tree->depth + 1)) { return false; } + bps_tree_block_id_t new_block_id = (bps_tree_block_id_t)(-1); + struct bps_leaf *new_leaf = bps_tree_create_leaf(tree, &new_block_id); + + leaf_path_elem->block = (struct bps_leaf *) + bps_tree_before_change_block(tree, leaf_path_elem->block_id); if (leaf_path_elem->block->next_id != (bps_tree_block_id_t)(-1)) { struct bps_leaf *next_leaf = (struct bps_leaf *) - bps_tree_restore_block(tree, - leaf_path_elem->block->next_id); + bps_tree_before_change_block(tree, leaf_path_elem->block->next_id); assert(next_leaf->prev_id == leaf_path_elem->block_id); next_leaf->prev_id = new_block_id; } else { @@ -2879,7 +3028,7 @@ bps_tree_process_insert_leaf(struct bps_tree *tree, new_leaf->header.size = 0; struct bps_leaf_path_elem new_path_elem; - bps_tree_elem_t new_max_elem; + bps_tree_elem_t new_max_elem = tree->max_elem; bps_tree_prepare_new_ext_leaf(leaf_path_elem, &new_path_elem, new_leaf, new_block_id, &new_max_elem); if (has_left_ext && has_right_ext) { @@ -3069,7 +3218,6 @@ bps_tree_process_insert_leaf(struct bps_tree *tree, new_root->child_ids[0] = tree->root_id; new_root->child_ids[1] = new_block_id; new_root->elems[0] = tree->max_elem; - tree->root = (struct bps_block *)new_root; tree->root_id = new_root_id; tree->max_elem = new_max_elem; tree->depth++; @@ -3386,7 +3534,6 @@ bps_tree_process_insert_inner(struct bps_tree *tree, new_root->child_ids[0] = tree->root_id; new_root->child_ids[1] = new_block_id; new_root->elems[0] = tree->max_elem; - tree->root = (struct bps_block *)new_root; tree->root_id = new_root_id; tree->max_elem = new_max_elem; tree->depth++; @@ -3558,7 +3705,7 @@ bps_tree_process_delete_leaf(struct bps_tree *tree, assert(leaf_path_elem->parent == 0); assert(tree->depth == 1); assert(tree->size == 0); - tree->root = 0; + tree->root_id = (bps_tree_block_id_t)(-1); tree->depth = 0; tree->first_id = (bps_tree_block_id_t)(-1); tree->last_id = (bps_tree_block_id_t)(-1); @@ -3755,7 +3902,6 @@ bps_tree_process_delete_inner(struct bps_tree *tree, assert(inner_path_elem->parent == 0); tree->depth--; tree->root_id = inner_path_elem->block->child_ids[0]; - tree->root = bps_tree_restore_block(tree, tree->root_id); bps_tree_dispose_inner(tree, inner_path_elem->block, inner_path_elem->block_id); BPS_TREE_BRANCH_TRACE(tree, delete_inner, 1 << 0xF); @@ -3770,7 +3916,6 @@ bps_tree_process_delete_inner(struct bps_tree *tree, BPS_TREE_BRANCH_TRACE(tree, delete_inner, 1 << 0x10); } - /** * @brief Insert an element to the tree or replace an element in the tree * In case of replacing, if 'replaced' argument is not null, it'll @@ -3789,7 +3934,7 @@ inline bool bps_tree_insert(struct bps_tree *tree, bps_tree_elem_t new_elem, bps_tree_elem_t *replaced) { - if (!tree->root) + if (tree->root_id == (bps_tree_block_id_t)(-1)) return bps_tree_insert_first_elem(tree, new_elem); bps_inner_path_elem path[BPS_TREE_MAX_DEPTH]; @@ -3815,7 +3960,7 @@ bps_tree_insert(struct bps_tree *tree, bps_tree_elem_t new_elem, inline bool bps_tree_delete(struct bps_tree *tree, bps_tree_elem_t elem) { - if (!tree->root) + if (tree->root_id == (bps_tree_block_id_t)(-1)) return false; bps_inner_path_elem path[BPS_TREE_MAX_DEPTH]; struct bps_leaf_path_elem leaf_path_elem; @@ -3829,7 +3974,6 @@ bps_tree_delete(struct bps_tree *tree, bps_tree_elem_t elem) return true; } - /** * @brief Recursively find a maximum element in subtree. * Used only for debug purposes @@ -3961,7 +4105,7 @@ inline int bps_tree_debug_check(const struct bps_tree *tree) { int result = 0; - if (!tree->root) { + if (tree->root_id == (bps_tree_block_id_t)(-1)) { if (tree->depth != 0) result |= 0x1; if (tree->size != 0) @@ -3970,14 +4114,13 @@ bps_tree_debug_check(const struct bps_tree *tree) result |= 0x1; return result; } - if (tree->max_elem != bps_tree_debug_find_max_elem(tree, tree->root)) + struct bps_block *root = bps_tree_root(tree); + if (tree->max_elem != bps_tree_debug_find_max_elem(tree, root)) result |= 0x8; - if (bps_tree_restore_block(tree, tree->root_id) != tree->root) - result |= 0x2; size_t calc_count = 0; bps_tree_block_id_t expected_prev_id = (bps_tree_block_id_t)(-1); bps_tree_block_id_t expected_this_id = tree->first_id; - result |= bps_tree_debug_check_block(tree, tree->root, tree->root_id, + result |= bps_tree_debug_check_block(tree, root, tree->root_id, tree->depth, &calc_count, &expected_prev_id, &expected_this_id, @@ -4087,11 +4230,11 @@ bps_tree_print_block(const struct bps_tree *tree, inline void bps_tree_print(const struct bps_tree *tree, const char *elem_fmt) { - if (tree->root == 0) { + if (tree->root_id == (bps_tree_block_id_t)(-1)) { printf("Empty\n"); return; } - bps_tree_print_block(tree, tree->root, 0, elem_fmt); + bps_tree_print_block(tree, bps_tree_root(tree), 0, elem_fmt); } /* @@ -4121,7 +4264,6 @@ bps_tree_debug_get_elem(bps_tree_elem_t *elem) return *(unsigned char *)elem; } - /** * @brief Assign a value to an element in inner block. * Used for debug self-check @@ -4186,6 +4328,7 @@ bps_tree_debug_check_insert_into_leaf(struct bps_tree *tree, bool assertme) bps_tree_debug_set_elem(&max, i + 1); bps_tree_debug_set_elem(&ins, j); path_elem.block = █ + path_elem.block_id = 0; path_elem.insertion_point = j; path_elem.max_elem_copy = &max; @@ -4238,6 +4381,7 @@ bps_tree_debug_check_delete_from_leaf(struct bps_tree *tree, bool assertme) bps_tree_debug_set_elem(&max, j == i - 1 ? i - 2 : i - 1); path_elem.block = █ + path_elem.block_id = 0; path_elem.insertion_point = j; path_elem.max_elem_copy = &max; @@ -4312,6 +4456,8 @@ bps_tree_debug_check_move_to_right_leaf(struct bps_tree *tree, bool assertme) a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; bps_tree_move_elems_to_right_leaf(tree, &a_path_elem, &b_path_elem, @@ -4403,6 +4549,8 @@ bps_tree_debug_check_move_to_left_leaf(struct bps_tree *tree, bool assertme) a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; bps_tree_move_elems_to_left_leaf(tree, &a_path_elem, &b_path_elem, @@ -4503,6 +4651,8 @@ bps_tree_debug_check_insert_and_move_to_right_leaf(struct bps_tree *tree, b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; a_path_elem.insertion_point = k; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; bps_tree_elem_t ins; bps_tree_debug_set_elem(&ins, ic); @@ -4613,6 +4763,8 @@ bps_tree_debug_check_insert_and_move_to_left_leaf(struct bps_tree *tree, b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; b_path_elem.insertion_point = k; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; bps_tree_elem_t ins; bps_tree_debug_set_elem(&ins, ic); @@ -4698,6 +4850,7 @@ bps_tree_debug_check_insert_into_inner(struct bps_tree *tree, bool assertme) bps_inner_path_elem path_elem; path_elem.block = █ + path_elem.block_id = 0; path_elem.max_elem_copy = &max; for (unsigned int k = 0; k < i; k++) { @@ -4762,6 +4915,7 @@ bps_tree_debug_check_delete_from_inner(struct bps_tree *tree, bool assertme) bps_tree_elem_t max; bps_tree_debug_set_elem(&max, i - 1); path_elem.block = █ + path_elem.block_id = 0; path_elem.insertion_point = j; path_elem.max_elem_copy = &max; @@ -4824,6 +4978,8 @@ bps_tree_debug_check_move_to_right_inner(struct bps_tree *tree, bool assertme) a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; unsigned char c = 0; bps_tree_block_id_t kk = 0; @@ -4918,6 +5074,8 @@ bps_tree_debug_check_move_to_left_inner(struct bps_tree *tree, bool assertme) a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; unsigned char c = 0; bps_tree_block_id_t kk = 0; @@ -5018,6 +5176,8 @@ bps_tree_debug_check_insert_and_move_to_right_inner(struct bps_tree *tree, a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; unsigned char c = 0; bps_tree_block_id_t kk = 0; @@ -5144,6 +5304,8 @@ bps_tree_debug_check_insert_and_move_to_left_inner(struct bps_tree *tree, a_path_elem.max_elem_copy = &ma; b_path_elem.block = &b; b_path_elem.max_elem_copy = &mb; + a_path_elem.block_id = 0; + b_path_elem.block_id = 0; unsigned char c = 0; bps_tree_block_id_t kk = 0; @@ -5235,7 +5397,9 @@ inline int bps_tree_debug_check_internal_functions(bool assertme) { int result = 0; + bps_tree tree; + tree.root_id = (bps_tree_block_id_t) -1; result |= bps_tree_debug_check_insert_into_leaf(&tree, assertme); result |= bps_tree_debug_check_delete_from_leaf(&tree, assertme); @@ -5297,6 +5461,8 @@ bps_tree_debug_check_internal_functions(bool assertme) #undef bps_tree_itr_get_elem #undef bps_tree_itr_next #undef bps_tree_itr_prev +#undef bps_tree_itr_freeze +#undef bps_tree_itr_destroy #undef bps_tree_debug_check #undef bps_tree_print #undef bps_tree_debug_check_internal_functions @@ -5311,6 +5477,9 @@ bps_tree_debug_check_internal_functions(bool assertme) #undef BPS_TREE_BT_LEAF #undef bps_tree_restore_block +#undef bps_tree_restore_block_ver +#undef bps_tree_root +#undef bps_tree_before_change_block #undef bps_tree_find_ins_point_key #undef bps_tree_find_ins_point_elem #undef bps_tree_find_after_ins_point_key @@ -5374,5 +5543,4 @@ bps_tree_debug_check_internal_functions(bool assertme) #undef bps_tree_debug_check_move_to_left_inner #undef bps_tree_debug_check_insert_and_move_to_right_inner #undef bps_tree_debug_check_insert_and_move_to_left_inner -#undef bps_tree_debug_check_insert_and_move_to_left_inner /* }}} */ diff --git a/test/unit/bps_tree_itr.cc b/test/unit/bps_tree_itr.cc index aa176b946cd9ca14b3a86beeda8230d87d7a7dda..d696edd6cf63acd397a9db3ea9741da922b9a49e 100644 --- a/test/unit/bps_tree_itr.cc +++ b/test/unit/bps_tree_itr.cc @@ -10,7 +10,7 @@ struct elem_t { long second; bool operator!= (const struct elem_t& another) const { - return first == another.first && second == another.second; + return first != another.first || second != another.second; } }; @@ -38,15 +38,19 @@ static int compare_key(const elem_t &a, long b) return a.first < b ? -1 : a.first > b ? 1 : 0; } +int total_extents_allocated = 0; + static void * extent_alloc() { + total_extents_allocated++; return malloc(BPS_TREE_EXTENT_SIZE); } static void extent_free(void *extent) { + total_extents_allocated--; free(extent); } @@ -115,7 +119,7 @@ itr_check() printf("\n"); } - /* Iteratete forward all elements 5 times */ + /* Iterate forward all elements 5 times */ { bps_tree_test_iterator itr = bps_tree_test_itr_first(&tree); for (long i = 0; i < count1 * count2 * 5; i++) { @@ -135,7 +139,7 @@ itr_check() } } - /* Iteratete backward all elements 5 times */ + /* Iterate backward all elements 5 times */ { bps_tree_test_iterator itr = bps_tree_test_itr_last(&tree); for (long i = 0; i < count1 * count2 * 5; i++) { @@ -389,9 +393,90 @@ itr_invalidate_check() footer(); } +static void +itr_freeze_check() +{ + header(); + + const int test_rounds_size = 10; + const int test_data_size = 1000; + elem_t comp_buf1[test_data_size]; + elem_t comp_buf2[test_data_size]; + const int test_data_mod = 2000; + srand(0); + struct bps_tree_test tree; + + for (int i = 0; i < 10; i++) { + bps_tree_test_create(&tree, 0, extent_alloc, extent_free); + int comp_buf_size1 = 0; + int comp_buf_size2 = 0; + for (int j = 0; j < test_data_size; j++) { + elem_t e; + e.first = rand() % test_data_mod; + e.second = 0; + bps_tree_test_insert(&tree, e, 0); + } + struct bps_tree_test_iterator itr = bps_tree_test_itr_first(&tree); + elem_t *e; + while ((e = bps_tree_test_itr_get_elem(&tree, &itr))) { + comp_buf1[comp_buf_size1++] = *e; + bps_tree_test_itr_next(&tree, &itr); + } + struct bps_tree_test_iterator itr1 = bps_tree_test_itr_first(&tree); + bps_tree_test_itr_freeze(&tree, &itr1); + struct bps_tree_test_iterator itr2 = bps_tree_test_itr_first(&tree); + bps_tree_test_itr_freeze(&tree, &itr2); + for (int j = 0; j < test_data_size; j++) { + elem_t e; + e.first = rand() % test_data_mod; + e.second = 0; + bps_tree_test_insert(&tree, e, 0); + } + int tested_count = 0; + while ((e = bps_tree_test_itr_get_elem(&tree, &itr1))) { + if (*e != comp_buf1[tested_count]) { + fail("version restore failed (1)", "true"); + } + tested_count++; + if (tested_count > comp_buf_size1) { + fail("version restore failed (2)", "true"); + } + bps_tree_test_itr_next(&tree, &itr1); + } + bps_tree_test_itr_destroy(&tree, &itr1); + for (int j = 0; j < test_data_size; j++) { + elem_t e; + e.first = rand() % test_data_mod; + e.second = 0; + bps_tree_test_delete(&tree, e); + } + + tested_count = 0; + while ((e = bps_tree_test_itr_get_elem(&tree, &itr2))) { + if (*e != comp_buf1[tested_count]) { + fail("version restore failed (1)", "true"); + } + tested_count++; + if (tested_count > comp_buf_size1) { + fail("version restore failed (2)", "true"); + } + bps_tree_test_itr_next(&tree, &itr2); + } + + bps_tree_test_destroy(&tree); + } + + footer(); +} + + int main(void) { itr_check(); itr_invalidate_check(); + itr_freeze_check(); + if (total_extents_allocated) { + fail("memory leak", "true"); + } } diff --git a/test/unit/bps_tree_itr.result b/test/unit/bps_tree_itr.result index 098fa9f264f69fce8faf41ec7ced1d3af62d5c62..d67f0d0f4a56231a82ebb18d475cc288974d96fa 100644 --- a/test/unit/bps_tree_itr.result +++ b/test/unit/bps_tree_itr.result @@ -11,4 +11,6 @@ Key 20000, empty range [eof, eof): <-> *** itr_check: done *** *** itr_invalidate_check *** *** itr_invalidate_check: done *** + *** itr_freeze_check *** + *** itr_freeze_check: done *** \ No newline at end of file