From b4857416c4030057a79cf52cdd7ffff88f55f73c Mon Sep 17 00:00:00 2001 From: John Naylor Date: Wed, 4 Jan 2023 14:43:17 +0700 Subject: [PATCH v17 7/9] Convert radixtree.h into a template The only thing configurable at this point is function scope and prefix, since the point is to see if this makes a shared memory implementation clear and maintainable. The key and value type are still hard-coded to uint64. To make this more useful, at least value type should be configurable. It might be good at some point to offer a different tree type, e.g. "single-value leaves" to allow for variable length keys and values, giving full flexibility to developers. --- src/include/lib/radixtree.h | 987 +++++++++++------- src/include/lib/radixtree_delete_impl.h | 36 +- src/include/lib/radixtree_insert_impl.h | 92 +- src/include/lib/radixtree_iter_impl.h | 34 +- src/include/lib/radixtree_search_impl.h | 36 +- .../modules/test_radixtree/test_radixtree.c | 23 +- 6 files changed, 718 insertions(+), 490 deletions(-) diff --git a/src/include/lib/radixtree.h b/src/include/lib/radixtree.h index fe517793f4..e4350730b7 100644 --- a/src/include/lib/radixtree.h +++ b/src/include/lib/radixtree.h @@ -29,24 +29,41 @@ * * XXX: the radix tree node never be shrunk. * + * To generate a radix tree and associated functions for a use case several + * macros have to be #define'ed before this file is included. Including + * the file #undef's all those, so a new radix tree can be generated + * afterwards. + * The relevant parameters are: + * - RT_PREFIX - prefix for all symbol names generated. A prefix of 'foo' + * will result in radix tree type 'foo_radix_tree' and functions like + * 'foo_create'/'foo_free' and so forth. + * - RT_DECLARE - if defined function prototypes and type declarations are + * generated + * - RT_DEFINE - if defined function definitions are generated + * - RT_SCOPE - in which scope (e.g. extern, static inline) do function + * declarations reside + * + * Optional parameters: + * - RT_DEBUG - if defined add stats tracking and debugging functions + * * Interface * --------- * - * rt_create - Create a new, empty radix tree - * rt_free - Free the radix tree - * rt_search - Search a key-value pair - * rt_set - Set a key-value pair - * rt_delete - Delete a key-value pair - * rt_begin_iterate - Begin iterating through all key-value pairs - * rt_iterate_next - Return next key-value pair, if any - * rt_end_iter - End iteration - * rt_memory_usage - Get the memory usage - * rt_num_entries - Get the number of key-value pairs + * RT_CREATE - Create a new, empty radix tree + * RT_FREE - Free the radix tree + * RT_SEARCH - Search a key-value pair + * RT_SET - Set a key-value pair + * RT_DELETE - Delete a key-value pair + * RT_BEGIN_ITERATE - Begin iterating through all key-value pairs + * RT_ITERATE_NEXT - Return next key-value pair, if any + * RT_END_ITER - End iteration + * RT_MEMORY_USAGE - Get the memory usage + * RT_NUM_ENTRIES - Get the number of key-value pairs * - * rt_create() creates an empty radix tree in the given memory context + * RT_CREATE() creates an empty radix tree in the given memory context * and memory contexts for all kinds of radix tree node under the memory context. * - * rt_iterate_next() ensures returning key-value pairs in the ascending + * RT_ITERATE_NEXT() ensures returning key-value pairs in the ascending * order of the key. * * Copyright (c) 2022, PostgreSQL Global Development Group @@ -66,6 +83,133 @@ #include "port/pg_lfind.h" #include "utils/memutils.h" +/* helpers */ +#define RT_MAKE_PREFIX(a) CppConcat(a,_) +#define RT_MAKE_NAME(name) RT_MAKE_NAME_(RT_MAKE_PREFIX(RT_PREFIX),name) +#define RT_MAKE_NAME_(a,b) CppConcat(a,b) + +/* function declarations */ +#define RT_CREATE RT_MAKE_NAME(create) +#define RT_FREE RT_MAKE_NAME(free) +#define RT_SEARCH RT_MAKE_NAME(search) +#define RT_SET RT_MAKE_NAME(set) +#define RT_BEGIN_ITERATE RT_MAKE_NAME(begin_iterate) +#define RT_ITERATE_NEXT RT_MAKE_NAME(iterate_next) +#define RT_END_ITERATE RT_MAKE_NAME(end_iterate) +#define RT_DELETE RT_MAKE_NAME(delete) +#define RT_MEMORY_USAGE RT_MAKE_NAME(memory_usage) +#define RT_NUM_ENTRIES RT_MAKE_NAME(num_entries) +#define RT_DUMP RT_MAKE_NAME(dump) +#define RT_DUMP_SEARCH RT_MAKE_NAME(dump_search) +#define RT_STATS RT_MAKE_NAME(stats) + +/* internal helper functions (no externally visible prototypes) */ +#define RT_NEW_ROOT RT_MAKE_NAME(new_root) +#define RT_ALLOC_NODE RT_MAKE_NAME(alloc_node) +#define RT_INIT_NODE RT_MAKE_NAME(init_node) +#define RT_FREE_NODE RT_MAKE_NAME(free_node) +#define RT_EXTEND RT_MAKE_NAME(extend) +#define RT_SET_EXTEND RT_MAKE_NAME(set_extend) +#define RT_GROW_NODE_KIND RT_MAKE_NAME(grow_node_kind) +#define RT_COPY_NODE RT_MAKE_NAME(copy_node) +#define RT_REPLACE_NODE RT_MAKE_NAME(replace_node) +#define RT_NODE_4_SEARCH_EQ RT_MAKE_NAME(node_4_search_eq) +#define RT_NODE_32_SEARCH_EQ RT_MAKE_NAME(node_32_search_eq) +#define RT_NODE_4_GET_INSERTPOS RT_MAKE_NAME(node_4_get_insertpos) +#define RT_NODE_32_GET_INSERTPOS RT_MAKE_NAME(node_32_get_insertpos) +#define RT_CHUNK_CHILDREN_ARRAY_SHIFT RT_MAKE_NAME(chunk_children_array_shift) +#define RT_CHUNK_VALUES_ARRAY_SHIFT RT_MAKE_NAME(chunk_values_array_shift) +#define RT_CHUNK_CHILDREN_ARRAY_DELETE RT_MAKE_NAME(chunk_children_array_delete) +#define RT_CHUNK_VALUES_ARRAY_DELETE RT_MAKE_NAME(chunk_values_array_delete) +#define RT_CHUNK_CHILDREN_ARRAY_COPY RT_MAKE_NAME(chunk_children_array_copy) +#define RT_CHUNK_VALUES_ARRAY_COPY RT_MAKE_NAME(chunk_values_array_copy) +#define RT_NODE_125_IS_CHUNK_USED RT_MAKE_NAME(node_125_is_chunk_used) +#define RT_NODE_INNER_125_GET_CHILD RT_MAKE_NAME(node_inner_125_get_child) +#define RT_NODE_LEAF_125_GET_VALUE RT_MAKE_NAME(node_leaf_125_get_value) +#define RT_NODE_INNER_256_IS_CHUNK_USED RT_MAKE_NAME(node_inner_256_is_chunk_used) +#define RT_NODE_LEAF_256_IS_CHUNK_USED RT_MAKE_NAME(node_leaf_256_is_chunk_used) +#define RT_NODE_INNER_256_GET_CHILD RT_MAKE_NAME(node_inner_256_get_child) +#define RT_NODE_LEAF_256_GET_VALUE RT_MAKE_NAME(node_leaf_256_get_value) +#define RT_NODE_INNER_256_SET RT_MAKE_NAME(node_inner_256_set) +#define RT_NODE_LEAF_256_SET RT_MAKE_NAME(node_leaf_256_set) +#define RT_NODE_INNER_256_DELETE RT_MAKE_NAME(node_inner_256_delete) +#define RT_NODE_LEAF_256_DELETE RT_MAKE_NAME(node_leaf_256_delete) +#define RT_KEY_GET_SHIFT RT_MAKE_NAME(key_get_shift) +#define RT_SHIFT_GET_MAX_VAL RT_MAKE_NAME(shift_get_max_val) +#define RT_NODE_SEARCH_INNER RT_MAKE_NAME(node_search_inner) +#define RT_NODE_SEARCH_LEAF RT_MAKE_NAME(node_search_leaf) +#define RT_NODE_DELETE_INNER RT_MAKE_NAME(node_delete_inner) +#define RT_NODE_DELETE_LEAF RT_MAKE_NAME(node_delete_leaf) +#define RT_NODE_INSERT_INNER RT_MAKE_NAME(node_insert_inner) +#define RT_NODE_INSERT_LEAF RT_MAKE_NAME(node_insert_leaf) +#define RT_NODE_INNER_ITERATE_NEXT RT_MAKE_NAME(node_inner_iterate_next) +#define RT_NODE_LEAF_ITERATE_NEXT RT_MAKE_NAME(node_leaf_iterate_next) +#define RT_UPDATE_ITER_STACK RT_MAKE_NAME(update_iter_stack) +#define RT_ITER_UPDATE_KEY RT_MAKE_NAME(iter_update_key) +#define RT_VERIFY_NODE RT_MAKE_NAME(verify_node) + +/* type declarations */ +#define RT_RADIX_TREE RT_MAKE_NAME(radix_tree) +#define RT_ITER RT_MAKE_NAME(iter) +#define RT_NODE RT_MAKE_NAME(node) +#define RT_NODE_ITER RT_MAKE_NAME(node_iter) +#define RT_NODE_BASE_4 RT_MAKE_NAME(node_base_4) +#define RT_NODE_BASE_32 RT_MAKE_NAME(node_base_32) +#define RT_NODE_BASE_125 RT_MAKE_NAME(node_base_125) +#define RT_NODE_BASE_256 RT_MAKE_NAME(node_base_256) +#define RT_NODE_INNER_4 RT_MAKE_NAME(node_inner_4) +#define RT_NODE_INNER_32 RT_MAKE_NAME(node_inner_32) +#define RT_NODE_INNER_125 RT_MAKE_NAME(node_inner_125) +#define RT_NODE_INNER_256 RT_MAKE_NAME(node_inner_256) +#define RT_NODE_LEAF_4 RT_MAKE_NAME(node_leaf_4) +#define RT_NODE_LEAF_32 RT_MAKE_NAME(node_leaf_32) +#define RT_NODE_LEAF_125 RT_MAKE_NAME(node_leaf_125) +#define RT_NODE_LEAF_256 RT_MAKE_NAME(node_leaf_256) +#define RT_SIZE_CLASS RT_MAKE_NAME(size_class) +#define RT_SIZE_CLASS_ELEM RT_MAKE_NAME(size_class_elem) +#define RT_SIZE_CLASS_INFO RT_MAKE_NAME(size_class_info) +#define RT_CLASS_4_FULL RT_MAKE_NAME(class_4_full) +#define RT_CLASS_32_PARTIAL RT_MAKE_NAME(class_32_partial) +#define RT_CLASS_32_FULL RT_MAKE_NAME(class_32_full) +#define RT_CLASS_125_FULL RT_MAKE_NAME(class_125_full) +#define RT_CLASS_256 RT_MAKE_NAME(class_256) +#define RT_KIND_MIN_SIZE_CLASS RT_MAKE_NAME(kind_min_size_class) + +/* generate forward declarations necessary to use the radix tree */ +#ifdef RT_DECLARE + +typedef struct RT_RADIX_TREE RT_RADIX_TREE; +typedef struct RT_ITER RT_ITER; + +RT_SCOPE RT_RADIX_TREE * RT_CREATE(MemoryContext ctx); +RT_SCOPE void RT_FREE(RT_RADIX_TREE *tree); +RT_SCOPE bool RT_SEARCH(RT_RADIX_TREE *tree, uint64 key, uint64 *val_p); +RT_SCOPE bool RT_SET(RT_RADIX_TREE *tree, uint64 key, uint64 val); +RT_SCOPE bool RT_DELETE(RT_RADIX_TREE *tree, uint64 key); + +RT_SCOPE RT_ITER * RT_BEGIN_ITERATE(RT_RADIX_TREE *tree); +RT_SCOPE bool RT_ITERATE_NEXT(RT_ITER *iter, uint64 *key_p, uint64 *value_p); +RT_SCOPE void RT_END_ITERATE(RT_ITER *iter); + +RT_SCOPE uint64 RT_MEMORY_USAGE(RT_RADIX_TREE *tree); +RT_SCOPE uint64 RT_NUM_ENTRIES(RT_RADIX_TREE *tree); + +#ifdef RT_DEBUG +RT_SCOPE void RT_DUMP(RT_RADIX_TREE *tree); +RT_SCOPE void RT_DUMP_SEARCH(RT_RADIX_TREE *tree, uint64 key); +RT_SCOPE void RT_STATS(RT_RADIX_TREE *tree); +#endif + +#endif /* RT_DECLARE */ + + +/* generate implementation of the radix tree */ +#ifdef RT_DEFINE + +/* macros and types common to all implementations */ +#ifndef RT_COMMON +#define RT_COMMON + #ifdef RT_DEBUG #define UINT64_FORMAT_HEX "%" INT64_MODIFIER "X" #endif @@ -80,7 +224,7 @@ #define RT_CHUNK_MASK ((1 << RT_NODE_SPAN) - 1) /* Maximum shift the radix tree uses */ -#define RT_MAX_SHIFT key_get_shift(UINT64_MAX) +#define RT_MAX_SHIFT RT_KEY_GET_SHIFT(UINT64_MAX) /* Tree level the radix tree uses */ #define RT_MAX_LEVEL ((sizeof(uint64) * BITS_PER_BYTE) / RT_NODE_SPAN) @@ -101,7 +245,7 @@ * There are 4 node kinds and each node kind have one or two size classes, * partial and full. The size classes in the same node kind have the same * node structure but have the different number of fanout that is stored - * in 'fanout' of rt_node. For example in size class 15, when a 16th element + * in 'fanout' of RT_NODE. For example in size class 15, when a 16th element * is to be inserted, we allocate a larger area and memcpy the entire old * node to it. * @@ -119,19 +263,20 @@ #define RT_NODE_KIND_256 0x03 #define RT_NODE_KIND_COUNT 4 -typedef enum rt_size_class +#endif /* RT_COMMON */ + + +typedef enum RT_SIZE_CLASS { RT_CLASS_4_FULL = 0, RT_CLASS_32_PARTIAL, RT_CLASS_32_FULL, RT_CLASS_125_FULL, RT_CLASS_256 - -#define RT_SIZE_CLASS_COUNT (RT_CLASS_256 + 1) -} rt_size_class; +} RT_SIZE_CLASS; /* Common type for all nodes types */ -typedef struct rt_node +typedef struct RT_NODE { /* * Number of children. We use uint16 to be able to indicate 256 children @@ -154,53 +299,54 @@ typedef struct rt_node /* Node kind, one per search/set algorithm */ uint8 kind; -} rt_node; -#define NODE_IS_LEAF(n) (((rt_node *) (n))->shift == 0) -#define NODE_IS_EMPTY(n) (((rt_node *) (n))->count == 0) +} RT_NODE; + +#define NODE_IS_LEAF(n) (((RT_NODE *) (n))->shift == 0) +#define NODE_IS_EMPTY(n) (((RT_NODE *) (n))->count == 0) #define VAR_NODE_HAS_FREE_SLOT(node) \ ((node)->base.n.count < (node)->base.n.fanout) #define FIXED_NODE_HAS_FREE_SLOT(node, class) \ - ((node)->base.n.count < rt_size_class_info[class].fanout) + ((node)->base.n.count < RT_SIZE_CLASS_INFO[class].fanout) /* Base type of each node kinds for leaf and inner nodes */ /* The base types must be a be able to accommodate the largest size class for variable-sized node kinds*/ -typedef struct rt_node_base_4 +typedef struct RT_NODE_BASE_4 { - rt_node n; + RT_NODE n; /* 4 children, for key chunks */ uint8 chunks[4]; -} rt_node_base_4; +} RT_NODE_BASE_4; -typedef struct rt_node_base32 +typedef struct RT_NODE_BASE_32 { - rt_node n; + RT_NODE n; /* 32 children, for key chunks */ uint8 chunks[32]; -} rt_node_base_32; +} RT_NODE_BASE_32; /* * node-125 uses slot_idx array, an array of RT_NODE_MAX_SLOTS length, typically * 256, to store indexes into a second array that contains up to 125 values (or * child pointers in inner nodes). */ -typedef struct rt_node_base125 +typedef struct RT_NODE_BASE_125 { - rt_node n; + RT_NODE n; /* The index of slots for each fanout */ uint8 slot_idxs[RT_NODE_MAX_SLOTS]; /* isset is a bitmap to track which slot is in use */ bitmapword isset[BM_IDX(128)]; -} rt_node_base_125; +} RT_NODE_BASE_125; -typedef struct rt_node_base256 +typedef struct RT_NODE_BASE_256 { - rt_node n; -} rt_node_base_256; + RT_NODE n; +} RT_NODE_BASE_256; /* * Inner and leaf nodes. @@ -215,79 +361,79 @@ typedef struct rt_node_base256 * good. It might be better to just indicate non-existing entries the same way * in inner nodes. */ -typedef struct rt_node_inner_4 +typedef struct RT_NODE_INNER_4 { - rt_node_base_4 base; + RT_NODE_BASE_4 base; /* number of children depends on size class */ - rt_node *children[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_inner_4; + RT_NODE *children[FLEXIBLE_ARRAY_MEMBER]; +} RT_NODE_INNER_4; -typedef struct rt_node_leaf_4 +typedef struct RT_NODE_LEAF_4 { - rt_node_base_4 base; + RT_NODE_BASE_4 base; /* number of values depends on size class */ uint64 values[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_leaf_4; +} RT_NODE_LEAF_4; -typedef struct rt_node_inner_32 +typedef struct RT_NODE_INNER_32 { - rt_node_base_32 base; + RT_NODE_BASE_32 base; /* number of children depends on size class */ - rt_node *children[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_inner_32; + RT_NODE *children[FLEXIBLE_ARRAY_MEMBER]; +} RT_NODE_INNER_32; -typedef struct rt_node_leaf_32 +typedef struct RT_NODE_LEAF_32 { - rt_node_base_32 base; + RT_NODE_BASE_32 base; /* number of values depends on size class */ uint64 values[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_leaf_32; +} RT_NODE_LEAF_32; -typedef struct rt_node_inner_125 +typedef struct RT_NODE_INNER_125 { - rt_node_base_125 base; + RT_NODE_BASE_125 base; /* number of children depends on size class */ - rt_node *children[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_inner_125; + RT_NODE *children[FLEXIBLE_ARRAY_MEMBER]; +} RT_NODE_INNER_125; -typedef struct rt_node_leaf_125 +typedef struct RT_NODE_LEAF_125 { - rt_node_base_125 base; + RT_NODE_BASE_125 base; /* number of values depends on size class */ uint64 values[FLEXIBLE_ARRAY_MEMBER]; -} rt_node_leaf_125; +} RT_NODE_LEAF_125; /* * node-256 is the largest node type. This node has RT_NODE_MAX_SLOTS length array * for directly storing values (or child pointers in inner nodes). */ -typedef struct rt_node_inner_256 +typedef struct RT_NODE_INNER_256 { - rt_node_base_256 base; + RT_NODE_BASE_256 base; /* Slots for 256 children */ - rt_node *children[RT_NODE_MAX_SLOTS]; -} rt_node_inner_256; + RT_NODE *children[RT_NODE_MAX_SLOTS]; +} RT_NODE_INNER_256; -typedef struct rt_node_leaf_256 +typedef struct RT_NODE_LEAF_256 { - rt_node_base_256 base; + RT_NODE_BASE_256 base; /* isset is a bitmap to track which slot is in use */ bitmapword isset[BM_IDX(RT_NODE_MAX_SLOTS)]; /* Slots for 256 values */ uint64 values[RT_NODE_MAX_SLOTS]; -} rt_node_leaf_256; +} RT_NODE_LEAF_256; /* Information for each size class */ -typedef struct rt_size_class_elem +typedef struct RT_SIZE_CLASS_ELEM { const char *name; int fanout; @@ -299,7 +445,7 @@ typedef struct rt_size_class_elem /* slab block size */ Size inner_blocksize; Size leaf_blocksize; -} rt_size_class_elem; +} RT_SIZE_CLASS_ELEM; /* * Calculate the slab blocksize so that we can allocate at least 32 chunks @@ -307,51 +453,54 @@ typedef struct rt_size_class_elem */ #define NODE_SLAB_BLOCK_SIZE(size) \ Max((SLAB_DEFAULT_BLOCK_SIZE / (size)) * (size), (size) * 32) -static rt_size_class_elem rt_size_class_info[RT_SIZE_CLASS_COUNT] = { + +static const RT_SIZE_CLASS_ELEM RT_SIZE_CLASS_INFO[] = { [RT_CLASS_4_FULL] = { .name = "radix tree node 4", .fanout = 4, - .inner_size = sizeof(rt_node_inner_4) + 4 * sizeof(rt_node *), - .leaf_size = sizeof(rt_node_leaf_4) + 4 * sizeof(uint64), - .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_inner_4) + 4 * sizeof(rt_node *)), - .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_leaf_4) + 4 * sizeof(uint64)), + .inner_size = sizeof(RT_NODE_INNER_4) + 4 * sizeof(RT_NODE *), + .leaf_size = sizeof(RT_NODE_LEAF_4) + 4 * sizeof(uint64), + .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_INNER_4) + 4 * sizeof(RT_NODE *)), + .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_LEAF_4) + 4 * sizeof(uint64)), }, [RT_CLASS_32_PARTIAL] = { .name = "radix tree node 15", .fanout = 15, - .inner_size = sizeof(rt_node_inner_32) + 15 * sizeof(rt_node *), - .leaf_size = sizeof(rt_node_leaf_32) + 15 * sizeof(uint64), - .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_inner_32) + 15 * sizeof(rt_node *)), - .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_leaf_32) + 15 * sizeof(uint64)), + .inner_size = sizeof(RT_NODE_INNER_32) + 15 * sizeof(RT_NODE *), + .leaf_size = sizeof(RT_NODE_LEAF_32) + 15 * sizeof(uint64), + .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_INNER_32) + 15 * sizeof(RT_NODE *)), + .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_LEAF_32) + 15 * sizeof(uint64)), }, [RT_CLASS_32_FULL] = { .name = "radix tree node 32", .fanout = 32, - .inner_size = sizeof(rt_node_inner_32) + 32 * sizeof(rt_node *), - .leaf_size = sizeof(rt_node_leaf_32) + 32 * sizeof(uint64), - .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_inner_32) + 32 * sizeof(rt_node *)), - .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_leaf_32) + 32 * sizeof(uint64)), + .inner_size = sizeof(RT_NODE_INNER_32) + 32 * sizeof(RT_NODE *), + .leaf_size = sizeof(RT_NODE_LEAF_32) + 32 * sizeof(uint64), + .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_INNER_32) + 32 * sizeof(RT_NODE *)), + .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_LEAF_32) + 32 * sizeof(uint64)), }, [RT_CLASS_125_FULL] = { .name = "radix tree node 125", .fanout = 125, - .inner_size = sizeof(rt_node_inner_125) + 125 * sizeof(rt_node *), - .leaf_size = sizeof(rt_node_leaf_125) + 125 * sizeof(uint64), - .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_inner_125) + 125 * sizeof(rt_node *)), - .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_leaf_125) + 125 * sizeof(uint64)), + .inner_size = sizeof(RT_NODE_INNER_125) + 125 * sizeof(RT_NODE *), + .leaf_size = sizeof(RT_NODE_LEAF_125) + 125 * sizeof(uint64), + .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_INNER_125) + 125 * sizeof(RT_NODE *)), + .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_LEAF_125) + 125 * sizeof(uint64)), }, [RT_CLASS_256] = { .name = "radix tree node 256", .fanout = 256, - .inner_size = sizeof(rt_node_inner_256), - .leaf_size = sizeof(rt_node_leaf_256), - .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_inner_256)), - .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(rt_node_leaf_256)), + .inner_size = sizeof(RT_NODE_INNER_256), + .leaf_size = sizeof(RT_NODE_LEAF_256), + .inner_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_INNER_256)), + .leaf_blocksize = NODE_SLAB_BLOCK_SIZE(sizeof(RT_NODE_LEAF_256)), }, }; +#define RT_SIZE_CLASS_COUNT lengthof(RT_SIZE_CLASS_INFO) + /* Map from the node kind to its minimum size class */ -static rt_size_class kind_min_size_class[RT_NODE_KIND_COUNT] = { +static const RT_SIZE_CLASS RT_KIND_MIN_SIZE_CLASS[RT_NODE_KIND_COUNT] = { [RT_NODE_KIND_4] = RT_CLASS_4_FULL, [RT_NODE_KIND_32] = RT_CLASS_32_PARTIAL, [RT_NODE_KIND_125] = RT_CLASS_125_FULL, @@ -359,11 +508,11 @@ static rt_size_class kind_min_size_class[RT_NODE_KIND_COUNT] = { }; /* A radix tree with nodes */ -typedef struct radix_tree +typedef struct RT_RADIX_TREE { MemoryContext context; - rt_node *root; + RT_NODE *root; uint64 max_val; uint64 num_keys; @@ -374,7 +523,7 @@ typedef struct radix_tree #ifdef RT_DEBUG int32 cnt[RT_SIZE_CLASS_COUNT]; #endif -} radix_tree; +} RT_RADIX_TREE; /* * Iteration support. @@ -382,79 +531,47 @@ typedef struct radix_tree * Iterating the radix tree returns each pair of key and value in the ascending * order of the key. To support this, the we iterate nodes of each level. * - * rt_node_iter struct is used to track the iteration within a node. + * RT_NODE_ITER struct is used to track the iteration within a node. * - * rt_iter is the struct for iteration of the radix tree, and uses rt_node_iter + * RT_ITER is the struct for iteration of the radix tree, and uses RT_NODE_ITER * in order to track the iteration of each level. During the iteration, we also * construct the key whenever updating the node iteration information, e.g., when * advancing the current index within the node or when moving to the next node * at the same level. */ -typedef struct rt_node_iter +typedef struct RT_NODE_ITER { - rt_node *node; /* current node being iterated */ + RT_NODE *node; /* current node being iterated */ int current_idx; /* current position. -1 for initial value */ -} rt_node_iter; +} RT_NODE_ITER; -typedef struct rt_iter +typedef struct RT_ITER { - radix_tree *tree; + RT_RADIX_TREE *tree; /* Track the iteration on nodes of each level */ - rt_node_iter stack[RT_MAX_LEVEL]; + RT_NODE_ITER stack[RT_MAX_LEVEL]; int stack_len; /* The key is being constructed during the iteration */ uint64 key; -} rt_iter; - -extern radix_tree *rt_create(MemoryContext ctx); -extern void rt_free(radix_tree *tree); -extern bool rt_search(radix_tree *tree, uint64 key, uint64 *val_p); -extern bool rt_set(radix_tree *tree, uint64 key, uint64 val); -extern rt_iter *rt_begin_iterate(radix_tree *tree); +} RT_ITER; -extern bool rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p); -extern void rt_end_iterate(rt_iter *iter); -extern bool rt_delete(radix_tree *tree, uint64 key); -extern uint64 rt_memory_usage(radix_tree *tree); -extern uint64 rt_num_entries(radix_tree *tree); - -#ifdef RT_DEBUG -extern void rt_dump(radix_tree *tree); -extern void rt_dump_search(radix_tree *tree, uint64 key); -extern void rt_stats(radix_tree *tree); -#endif - - -static void rt_new_root(radix_tree *tree, uint64 key); -static rt_node *rt_alloc_node(radix_tree *tree, rt_size_class size_class, bool inner); -static inline void rt_init_node(rt_node *node, uint8 kind, rt_size_class size_class, - bool inner); -static void rt_free_node(radix_tree *tree, rt_node *node); -static void rt_extend(radix_tree *tree, uint64 key); -static inline bool rt_node_search_inner(rt_node *node, uint64 key, rt_node **child_p); -static inline bool rt_node_search_leaf(rt_node *node, uint64 key, uint64 *value_p); -static bool rt_node_insert_inner(radix_tree *tree, rt_node *parent, rt_node *node, - uint64 key, rt_node *child); -static bool rt_node_insert_leaf(radix_tree *tree, rt_node *parent, rt_node *node, +static bool RT_NODE_INSERT_INNER(RT_RADIX_TREE *tree, RT_NODE *parent, RT_NODE *node, + uint64 key, RT_NODE *child); +static bool RT_NODE_INSERT_LEAF(RT_RADIX_TREE *tree, RT_NODE *parent, RT_NODE *node, uint64 key, uint64 value); -static inline rt_node *rt_node_inner_iterate_next(rt_iter *iter, rt_node_iter *node_iter); -static inline bool rt_node_leaf_iterate_next(rt_iter *iter, rt_node_iter *node_iter, - uint64 *value_p); -static void rt_update_iter_stack(rt_iter *iter, rt_node *from_node, int from); -static inline void rt_iter_update_key(rt_iter *iter, uint8 chunk, uint8 shift); /* verification (available only with assertion) */ -static void rt_verify_node(rt_node *node); +static void RT_VERIFY_NODE(RT_NODE *node); /* * Return index of the first element in 'base' that equals 'key'. Return -1 * if there is no such element. */ static inline int -node_4_search_eq(rt_node_base_4 *node, uint8 chunk) +RT_NODE_4_SEARCH_EQ(RT_NODE_BASE_4 *node, uint8 chunk) { int idx = -1; @@ -474,7 +591,7 @@ node_4_search_eq(rt_node_base_4 *node, uint8 chunk) * Return index of the chunk to insert into chunks in the given node. */ static inline int -node_4_get_insertpos(rt_node_base_4 *node, uint8 chunk) +RT_NODE_4_GET_INSERTPOS(RT_NODE_BASE_4 *node, uint8 chunk) { int idx; @@ -492,7 +609,7 @@ node_4_get_insertpos(rt_node_base_4 *node, uint8 chunk) * if there is no such element. */ static inline int -node_32_search_eq(rt_node_base_32 *node, uint8 chunk) +RT_NODE_32_SEARCH_EQ(RT_NODE_BASE_32 *node, uint8 chunk) { int count = node->n.count; #ifndef USE_NO_SIMD @@ -541,7 +658,7 @@ node_32_search_eq(rt_node_base_32 *node, uint8 chunk) * Return index of the chunk to insert into chunks in the given node. */ static inline int -node_32_get_insertpos(rt_node_base_32 *node, uint8 chunk) +RT_NODE_32_GET_INSERTPOS(RT_NODE_BASE_32 *node, uint8 chunk) { int count = node->n.count; #ifndef USE_NO_SIMD @@ -596,14 +713,14 @@ node_32_get_insertpos(rt_node_base_32 *node, uint8 chunk) /* Shift the elements right at 'idx' by one */ static inline void -chunk_children_array_shift(uint8 *chunks, rt_node **children, int count, int idx) +RT_CHUNK_CHILDREN_ARRAY_SHIFT(uint8 *chunks, RT_NODE **children, int count, int idx) { memmove(&(chunks[idx + 1]), &(chunks[idx]), sizeof(uint8) * (count - idx)); - memmove(&(children[idx + 1]), &(children[idx]), sizeof(rt_node *) * (count - idx)); + memmove(&(children[idx + 1]), &(children[idx]), sizeof(RT_NODE *) * (count - idx)); } static inline void -chunk_values_array_shift(uint8 *chunks, uint64 *values, int count, int idx) +RT_CHUNK_VALUES_ARRAY_SHIFT(uint8 *chunks, uint64 *values, int count, int idx) { memmove(&(chunks[idx + 1]), &(chunks[idx]), sizeof(uint8) * (count - idx)); memmove(&(values[idx + 1]), &(values[idx]), sizeof(uint64 *) * (count - idx)); @@ -611,14 +728,14 @@ chunk_values_array_shift(uint8 *chunks, uint64 *values, int count, int idx) /* Delete the element at 'idx' */ static inline void -chunk_children_array_delete(uint8 *chunks, rt_node **children, int count, int idx) +RT_CHUNK_CHILDREN_ARRAY_DELETE(uint8 *chunks, RT_NODE **children, int count, int idx) { memmove(&(chunks[idx]), &(chunks[idx + 1]), sizeof(uint8) * (count - idx - 1)); - memmove(&(children[idx]), &(children[idx + 1]), sizeof(rt_node *) * (count - idx - 1)); + memmove(&(children[idx]), &(children[idx + 1]), sizeof(RT_NODE *) * (count - idx - 1)); } static inline void -chunk_values_array_delete(uint8 *chunks, uint64 *values, int count, int idx) +RT_CHUNK_VALUES_ARRAY_DELETE(uint8 *chunks, uint64 *values, int count, int idx) { memmove(&(chunks[idx]), &(chunks[idx + 1]), sizeof(uint8) * (count - idx - 1)); memmove(&(values[idx]), &(values[idx + 1]), sizeof(uint64) * (count - idx - 1)); @@ -626,22 +743,22 @@ chunk_values_array_delete(uint8 *chunks, uint64 *values, int count, int idx) /* Copy both chunks and children/values arrays */ static inline void -chunk_children_array_copy(uint8 *src_chunks, rt_node **src_children, - uint8 *dst_chunks, rt_node **dst_children) +RT_CHUNK_CHILDREN_ARRAY_COPY(uint8 *src_chunks, RT_NODE **src_children, + uint8 *dst_chunks, RT_NODE **dst_children) { - const int fanout = rt_size_class_info[RT_CLASS_4_FULL].fanout; + const int fanout = RT_SIZE_CLASS_INFO[RT_CLASS_4_FULL].fanout; const Size chunk_size = sizeof(uint8) * fanout; - const Size children_size = sizeof(rt_node *) * fanout; + const Size children_size = sizeof(RT_NODE *) * fanout; memcpy(dst_chunks, src_chunks, chunk_size); memcpy(dst_children, src_children, children_size); } static inline void -chunk_values_array_copy(uint8 *src_chunks, uint64 *src_values, +RT_CHUNK_VALUES_ARRAY_COPY(uint8 *src_chunks, uint64 *src_values, uint8 *dst_chunks, uint64 *dst_values) { - const int fanout = rt_size_class_info[RT_CLASS_4_FULL].fanout; + const int fanout = RT_SIZE_CLASS_INFO[RT_CLASS_4_FULL].fanout; const Size chunk_size = sizeof(uint8) * fanout; const Size values_size = sizeof(uint64) * fanout; @@ -653,23 +770,23 @@ chunk_values_array_copy(uint8 *src_chunks, uint64 *src_values, /* Does the given chunk in the node has the value? */ static inline bool -node_125_is_chunk_used(rt_node_base_125 *node, uint8 chunk) +RT_NODE_125_IS_CHUNK_USED(RT_NODE_BASE_125 *node, uint8 chunk) { return node->slot_idxs[chunk] != RT_NODE_125_INVALID_IDX; } -static inline rt_node * -node_inner_125_get_child(rt_node_inner_125 *node, uint8 chunk) +static inline RT_NODE * +RT_NODE_INNER_125_GET_CHILD(RT_NODE_INNER_125 *node, uint8 chunk) { Assert(!NODE_IS_LEAF(node)); return node->children[node->base.slot_idxs[chunk]]; } static inline uint64 -node_leaf_125_get_value(rt_node_leaf_125 *node, uint8 chunk) +RT_NODE_LEAF_125_GET_VALUE(RT_NODE_LEAF_125 *node, uint8 chunk) { Assert(NODE_IS_LEAF(node)); - Assert(((rt_node_base_125 *) node)->slot_idxs[chunk] != RT_NODE_125_INVALID_IDX); + Assert(((RT_NODE_BASE_125 *) node)->slot_idxs[chunk] != RT_NODE_125_INVALID_IDX); return node->values[node->base.slot_idxs[chunk]]; } @@ -677,14 +794,14 @@ node_leaf_125_get_value(rt_node_leaf_125 *node, uint8 chunk) /* Return true if the slot corresponding to the given chunk is in use */ static inline bool -node_inner_256_is_chunk_used(rt_node_inner_256 *node, uint8 chunk) +RT_NODE_INNER_256_IS_CHUNK_USED(RT_NODE_INNER_256 *node, uint8 chunk) { Assert(!NODE_IS_LEAF(node)); return (node->children[chunk] != NULL); } static inline bool -node_leaf_256_is_chunk_used(rt_node_leaf_256 *node, uint8 chunk) +RT_NODE_LEAF_256_IS_CHUNK_USED(RT_NODE_LEAF_256 *node, uint8 chunk) { int idx = BM_IDX(chunk); int bitnum = BM_BIT(chunk); @@ -693,25 +810,25 @@ node_leaf_256_is_chunk_used(rt_node_leaf_256 *node, uint8 chunk) return (node->isset[idx] & ((bitmapword) 1 << bitnum)) != 0; } -static inline rt_node * -node_inner_256_get_child(rt_node_inner_256 *node, uint8 chunk) +static inline RT_NODE * +RT_NODE_INNER_256_GET_CHILD(RT_NODE_INNER_256 *node, uint8 chunk) { Assert(!NODE_IS_LEAF(node)); - Assert(node_inner_256_is_chunk_used(node, chunk)); + Assert(RT_NODE_INNER_256_IS_CHUNK_USED(node, chunk)); return node->children[chunk]; } static inline uint64 -node_leaf_256_get_value(rt_node_leaf_256 *node, uint8 chunk) +RT_NODE_LEAF_256_GET_VALUE(RT_NODE_LEAF_256 *node, uint8 chunk) { Assert(NODE_IS_LEAF(node)); - Assert(node_leaf_256_is_chunk_used(node, chunk)); + Assert(RT_NODE_LEAF_256_IS_CHUNK_USED(node, chunk)); return node->values[chunk]; } /* Set the child in the node-256 */ static inline void -node_inner_256_set(rt_node_inner_256 *node, uint8 chunk, rt_node *child) +RT_NODE_INNER_256_SET(RT_NODE_INNER_256 *node, uint8 chunk, RT_NODE *child) { Assert(!NODE_IS_LEAF(node)); node->children[chunk] = child; @@ -719,7 +836,7 @@ node_inner_256_set(rt_node_inner_256 *node, uint8 chunk, rt_node *child) /* Set the value in the node-256 */ static inline void -node_leaf_256_set(rt_node_leaf_256 *node, uint8 chunk, uint64 value) +RT_NODE_LEAF_256_SET(RT_NODE_LEAF_256 *node, uint8 chunk, uint64 value) { int idx = BM_IDX(chunk); int bitnum = BM_BIT(chunk); @@ -731,14 +848,14 @@ node_leaf_256_set(rt_node_leaf_256 *node, uint8 chunk, uint64 value) /* Set the slot at the given chunk position */ static inline void -node_inner_256_delete(rt_node_inner_256 *node, uint8 chunk) +RT_NODE_INNER_256_DELETE(RT_NODE_INNER_256 *node, uint8 chunk) { Assert(!NODE_IS_LEAF(node)); node->children[chunk] = NULL; } static inline void -node_leaf_256_delete(rt_node_leaf_256 *node, uint8 chunk) +RT_NODE_LEAF_256_DELETE(RT_NODE_LEAF_256 *node, uint8 chunk) { int idx = BM_IDX(chunk); int bitnum = BM_BIT(chunk); @@ -751,7 +868,7 @@ node_leaf_256_delete(rt_node_leaf_256 *node, uint8 chunk) * Return the shift that is satisfied to store the given key. */ static inline int -key_get_shift(uint64 key) +RT_KEY_GET_SHIFT(uint64 key) { return (key == 0) ? 0 @@ -762,7 +879,7 @@ key_get_shift(uint64 key) * Return the max value stored in a node with the given shift. */ static uint64 -shift_get_max_val(int shift) +RT_SHIFT_GET_MAX_VAL(int shift) { if (shift == RT_MAX_SHIFT) return UINT64_MAX; @@ -770,38 +887,20 @@ shift_get_max_val(int shift) return (UINT64CONST(1) << (shift + RT_NODE_SPAN)) - 1; } -/* - * Create a new node as the root. Subordinate nodes will be created during - * the insertion. - */ -static void -rt_new_root(radix_tree *tree, uint64 key) -{ - int shift = key_get_shift(key); - bool inner = shift > 0; - rt_node *newnode; - - newnode = rt_alloc_node(tree, RT_CLASS_4_FULL, inner); - rt_init_node(newnode, RT_NODE_KIND_4, RT_CLASS_4_FULL, inner); - newnode->shift = shift; - tree->max_val = shift_get_max_val(shift); - tree->root = newnode; -} - /* * Allocate a new node with the given node kind. */ -static rt_node * -rt_alloc_node(radix_tree *tree, rt_size_class size_class, bool inner) +static RT_NODE * +RT_ALLOC_NODE(RT_RADIX_TREE *tree, RT_SIZE_CLASS size_class, bool inner) { - rt_node *newnode; + RT_NODE *newnode; if (inner) - newnode = (rt_node *) MemoryContextAlloc(tree->inner_slabs[size_class], - rt_size_class_info[size_class].inner_size); + newnode = (RT_NODE *) MemoryContextAlloc(tree->inner_slabs[size_class], + RT_SIZE_CLASS_INFO[size_class].inner_size); else - newnode = (rt_node *) MemoryContextAlloc(tree->leaf_slabs[size_class], - rt_size_class_info[size_class].leaf_size); + newnode = (RT_NODE *) MemoryContextAlloc(tree->leaf_slabs[size_class], + RT_SIZE_CLASS_INFO[size_class].leaf_size); #ifdef RT_DEBUG /* update the statistics */ @@ -813,20 +912,20 @@ rt_alloc_node(radix_tree *tree, rt_size_class size_class, bool inner) /* Initialize the node contents */ static inline void -rt_init_node(rt_node *node, uint8 kind, rt_size_class size_class, bool inner) +RT_INIT_NODE(RT_NODE *node, uint8 kind, RT_SIZE_CLASS size_class, bool inner) { if (inner) - MemSet(node, 0, rt_size_class_info[size_class].inner_size); + MemSet(node, 0, RT_SIZE_CLASS_INFO[size_class].inner_size); else - MemSet(node, 0, rt_size_class_info[size_class].leaf_size); + MemSet(node, 0, RT_SIZE_CLASS_INFO[size_class].leaf_size); node->kind = kind; - node->fanout = rt_size_class_info[size_class].fanout; + node->fanout = RT_SIZE_CLASS_INFO[size_class].fanout; /* Initialize slot_idxs to invalid values */ if (kind == RT_NODE_KIND_125) { - rt_node_base_125 *n125 = (rt_node_base_125 *) node; + RT_NODE_BASE_125 *n125 = (RT_NODE_BASE_125 *) node; memset(n125->slot_idxs, RT_NODE_125_INVALID_IDX, sizeof(n125->slot_idxs)); } @@ -839,8 +938,26 @@ rt_init_node(rt_node *node, uint8 kind, rt_size_class size_class, bool inner) node->fanout = 0; } +/* + * Create a new node as the root. Subordinate nodes will be created during + * the insertion. + */ +static void +RT_NEW_ROOT(RT_RADIX_TREE *tree, uint64 key) +{ + int shift = RT_KEY_GET_SHIFT(key); + bool inner = shift > 0; + RT_NODE *newnode; + + newnode = RT_ALLOC_NODE(tree, RT_CLASS_4_FULL, inner); + RT_INIT_NODE(newnode, RT_NODE_KIND_4, RT_CLASS_4_FULL, inner); + newnode->shift = shift; + tree->max_val = RT_SHIFT_GET_MAX_VAL(shift); + tree->root = newnode; +} + static inline void -rt_copy_node(rt_node *newnode, rt_node *oldnode) +RT_COPY_NODE(RT_NODE *newnode, RT_NODE *oldnode) { newnode->shift = oldnode->shift; newnode->chunk = oldnode->chunk; @@ -851,22 +968,22 @@ rt_copy_node(rt_node *newnode, rt_node *oldnode) * Create a new node with 'new_kind' and the same shift, chunk, and * count of 'node'. */ -static rt_node* -rt_grow_node_kind(radix_tree *tree, rt_node *node, uint8 new_kind) +static RT_NODE* +RT_GROW_NODE_KIND(RT_RADIX_TREE *tree, RT_NODE *node, uint8 new_kind) { - rt_node *newnode; + RT_NODE *newnode; bool inner = !NODE_IS_LEAF(node); - newnode = rt_alloc_node(tree, kind_min_size_class[new_kind], inner); - rt_init_node(newnode, new_kind, kind_min_size_class[new_kind], inner); - rt_copy_node(newnode, node); + newnode = RT_ALLOC_NODE(tree, RT_KIND_MIN_SIZE_CLASS[new_kind], inner); + RT_INIT_NODE(newnode, new_kind, RT_KIND_MIN_SIZE_CLASS[new_kind], inner); + RT_COPY_NODE(newnode, node); return newnode; } /* Free the given node */ static void -rt_free_node(radix_tree *tree, rt_node *node) +RT_FREE_NODE(RT_RADIX_TREE *tree, RT_NODE *node) { /* If we're deleting the root node, make the tree empty */ if (tree->root == node) @@ -882,7 +999,7 @@ rt_free_node(radix_tree *tree, rt_node *node) /* update the statistics */ for (i = 0; i < RT_SIZE_CLASS_COUNT; i++) { - if (node->fanout == rt_size_class_info[i].fanout) + if (node->fanout == RT_SIZE_CLASS_INFO[i].fanout) break; } @@ -902,8 +1019,8 @@ rt_free_node(radix_tree *tree, rt_node *node) * Replace old_child with new_child, and free the old one. */ static void -rt_replace_node(radix_tree *tree, rt_node *parent, rt_node *old_child, - rt_node *new_child, uint64 key) +RT_REPLACE_NODE(RT_RADIX_TREE *tree, RT_NODE *parent, RT_NODE *old_child, + RT_NODE *new_child, uint64 key) { Assert(old_child->chunk == new_child->chunk); Assert(old_child->shift == new_child->shift); @@ -917,11 +1034,11 @@ rt_replace_node(radix_tree *tree, rt_node *parent, rt_node *old_child, { bool replaced PG_USED_FOR_ASSERTS_ONLY; - replaced = rt_node_insert_inner(tree, NULL, parent, key, new_child); + replaced = RT_NODE_INSERT_INNER(tree, NULL, parent, key, new_child); Assert(replaced); } - rt_free_node(tree, old_child); + RT_FREE_NODE(tree, old_child); } /* @@ -929,32 +1046,32 @@ rt_replace_node(radix_tree *tree, rt_node *parent, rt_node *old_child, * store the key. */ static void -rt_extend(radix_tree *tree, uint64 key) +RT_EXTEND(RT_RADIX_TREE *tree, uint64 key) { int target_shift; int shift = tree->root->shift + RT_NODE_SPAN; - target_shift = key_get_shift(key); + target_shift = RT_KEY_GET_SHIFT(key); /* Grow tree from 'shift' to 'target_shift' */ while (shift <= target_shift) { - rt_node_inner_4 *node; + RT_NODE_INNER_4 *node; - node = (rt_node_inner_4 *) rt_alloc_node(tree, RT_CLASS_4_FULL, true); - rt_init_node((rt_node *) node, RT_NODE_KIND_4, RT_CLASS_4_FULL, true); + node = (RT_NODE_INNER_4 *) RT_ALLOC_NODE(tree, RT_CLASS_4_FULL, true); + RT_INIT_NODE((RT_NODE *) node, RT_NODE_KIND_4, RT_CLASS_4_FULL, true); node->base.n.shift = shift; node->base.n.count = 1; node->base.chunks[0] = 0; node->children[0] = tree->root; tree->root->chunk = 0; - tree->root = (rt_node *) node; + tree->root = (RT_NODE *) node; shift += RT_NODE_SPAN; } - tree->max_val = shift_get_max_val(target_shift); + tree->max_val = RT_SHIFT_GET_MAX_VAL(target_shift); } /* @@ -962,29 +1079,29 @@ rt_extend(radix_tree *tree, uint64 key) * Insert inner and leaf nodes from 'node' to bottom. */ static inline void -rt_set_extend(radix_tree *tree, uint64 key, uint64 value, rt_node *parent, - rt_node *node) +RT_SET_EXTEND(RT_RADIX_TREE *tree, uint64 key, uint64 value, RT_NODE *parent, + RT_NODE *node) { int shift = node->shift; while (shift >= RT_NODE_SPAN) { - rt_node *newchild; + RT_NODE *newchild; int newshift = shift - RT_NODE_SPAN; bool inner = newshift > 0; - newchild = rt_alloc_node(tree, RT_CLASS_4_FULL, inner); - rt_init_node(newchild, RT_NODE_KIND_4, RT_CLASS_4_FULL, inner); + newchild = RT_ALLOC_NODE(tree, RT_CLASS_4_FULL, inner); + RT_INIT_NODE(newchild, RT_NODE_KIND_4, RT_CLASS_4_FULL, inner); newchild->shift = newshift; newchild->chunk = RT_GET_KEY_CHUNK(key, node->shift); - rt_node_insert_inner(tree, parent, node, key, newchild); + RT_NODE_INSERT_INNER(tree, parent, node, key, newchild); parent = node; node = newchild; shift -= RT_NODE_SPAN; } - rt_node_insert_leaf(tree, parent, node, key, value); + RT_NODE_INSERT_LEAF(tree, parent, node, key, value); tree->num_keys++; } @@ -995,7 +1112,7 @@ rt_set_extend(radix_tree *tree, uint64 key, uint64 value, rt_node *parent, * pointer is set to child_p. */ static inline bool -rt_node_search_inner(rt_node *node, uint64 key, rt_node **child_p) +RT_NODE_SEARCH_INNER(RT_NODE *node, uint64 key, RT_NODE **child_p) { #define RT_NODE_LEVEL_INNER #include "lib/radixtree_search_impl.h" @@ -1009,7 +1126,7 @@ rt_node_search_inner(rt_node *node, uint64 key, rt_node **child_p) * to the value is set to value_p. */ static inline bool -rt_node_search_leaf(rt_node *node, uint64 key, uint64 *value_p) +RT_NODE_SEARCH_LEAF(RT_NODE *node, uint64 key, uint64 *value_p) { #define RT_NODE_LEVEL_LEAF #include "lib/radixtree_search_impl.h" @@ -1022,7 +1139,7 @@ rt_node_search_leaf(rt_node *node, uint64 key, uint64 *value_p) * Delete the node and return true if the key is found, otherwise return false. */ static inline bool -rt_node_delete_inner(rt_node *node, uint64 key) +RT_NODE_DELETE_INNER(RT_NODE *node, uint64 key) { #define RT_NODE_LEVEL_INNER #include "lib/radixtree_delete_impl.h" @@ -1035,7 +1152,7 @@ rt_node_delete_inner(rt_node *node, uint64 key) * Delete the node and return true if the key is found, otherwise return false. */ static inline bool -rt_node_delete_leaf(rt_node *node, uint64 key) +RT_NODE_DELETE_LEAF(RT_NODE *node, uint64 key) { #define RT_NODE_LEVEL_LEAF #include "lib/radixtree_delete_impl.h" @@ -1044,8 +1161,8 @@ rt_node_delete_leaf(rt_node *node, uint64 key) /* Insert the child to the inner node */ static bool -rt_node_insert_inner(radix_tree *tree, rt_node *parent, rt_node *node, uint64 key, - rt_node *child) +RT_NODE_INSERT_INNER(RT_RADIX_TREE *tree, RT_NODE *parent, RT_NODE *node, uint64 key, + RT_NODE *child) { #define RT_NODE_LEVEL_INNER #include "lib/radixtree_insert_impl.h" @@ -1054,7 +1171,7 @@ rt_node_insert_inner(radix_tree *tree, rt_node *parent, rt_node *node, uint64 ke /* Insert the value to the leaf node */ static bool -rt_node_insert_leaf(radix_tree *tree, rt_node *parent, rt_node *node, +RT_NODE_INSERT_LEAF(RT_RADIX_TREE *tree, RT_NODE *parent, RT_NODE *node, uint64 key, uint64 value) { #define RT_NODE_LEVEL_LEAF @@ -1065,15 +1182,15 @@ rt_node_insert_leaf(radix_tree *tree, rt_node *parent, rt_node *node, /* * Create the radix tree in the given memory context and return it. */ -radix_tree * -rt_create(MemoryContext ctx) +RT_SCOPE RT_RADIX_TREE * +RT_CREATE(MemoryContext ctx) { - radix_tree *tree; + RT_RADIX_TREE *tree; MemoryContext old_ctx; old_ctx = MemoryContextSwitchTo(ctx); - tree = palloc(sizeof(radix_tree)); + tree = palloc(sizeof(RT_RADIX_TREE)); tree->context = ctx; tree->root = NULL; tree->max_val = 0; @@ -1083,13 +1200,13 @@ rt_create(MemoryContext ctx) for (int i = 0; i < RT_SIZE_CLASS_COUNT; i++) { tree->inner_slabs[i] = SlabContextCreate(ctx, - rt_size_class_info[i].name, - rt_size_class_info[i].inner_blocksize, - rt_size_class_info[i].inner_size); + RT_SIZE_CLASS_INFO[i].name, + RT_SIZE_CLASS_INFO[i].inner_blocksize, + RT_SIZE_CLASS_INFO[i].inner_size); tree->leaf_slabs[i] = SlabContextCreate(ctx, - rt_size_class_info[i].name, - rt_size_class_info[i].leaf_blocksize, - rt_size_class_info[i].leaf_size); + RT_SIZE_CLASS_INFO[i].name, + RT_SIZE_CLASS_INFO[i].leaf_blocksize, + RT_SIZE_CLASS_INFO[i].leaf_size); #ifdef RT_DEBUG tree->cnt[i] = 0; #endif @@ -1103,8 +1220,8 @@ rt_create(MemoryContext ctx) /* * Free the given radix tree. */ -void -rt_free(radix_tree *tree) +RT_SCOPE void +RT_FREE(RT_RADIX_TREE *tree) { for (int i = 0; i < RT_SIZE_CLASS_COUNT; i++) { @@ -1119,21 +1236,21 @@ rt_free(radix_tree *tree) * Set key to value. If the entry already exists, we update its value to 'value' * and return true. Returns false if entry doesn't yet exist. */ -bool -rt_set(radix_tree *tree, uint64 key, uint64 value) +RT_SCOPE bool +RT_SET(RT_RADIX_TREE *tree, uint64 key, uint64 value) { int shift; bool updated; - rt_node *node; - rt_node *parent; + RT_NODE *node; + RT_NODE *parent; /* Empty tree, create the root */ if (!tree->root) - rt_new_root(tree, key); + RT_NEW_ROOT(tree, key); /* Extend the tree if necessary */ if (key > tree->max_val) - rt_extend(tree, key); + RT_EXTEND(tree, key); Assert(tree->root); @@ -1143,14 +1260,14 @@ rt_set(radix_tree *tree, uint64 key, uint64 value) /* Descend the tree until a leaf node */ while (shift >= 0) { - rt_node *child; + RT_NODE *child; if (NODE_IS_LEAF(node)) break; - if (!rt_node_search_inner(node, key, &child)) + if (!RT_NODE_SEARCH_INNER(node, key, &child)) { - rt_set_extend(tree, key, value, parent, node); + RT_SET_EXTEND(tree, key, value, parent, node); return false; } @@ -1159,7 +1276,7 @@ rt_set(radix_tree *tree, uint64 key, uint64 value) shift -= RT_NODE_SPAN; } - updated = rt_node_insert_leaf(tree, parent, node, key, value); + updated = RT_NODE_INSERT_LEAF(tree, parent, node, key, value); /* Update the statistics */ if (!updated) @@ -1173,10 +1290,10 @@ rt_set(radix_tree *tree, uint64 key, uint64 value) * otherwise return false. On success, we set the value to *val_p so it must * not be NULL. */ -bool -rt_search(radix_tree *tree, uint64 key, uint64 *value_p) +RT_SCOPE bool +RT_SEARCH(RT_RADIX_TREE *tree, uint64 key, uint64 *value_p) { - rt_node *node; + RT_NODE *node; int shift; Assert(value_p != NULL); @@ -1190,30 +1307,30 @@ rt_search(radix_tree *tree, uint64 key, uint64 *value_p) /* Descend the tree until a leaf node */ while (shift >= 0) { - rt_node *child; + RT_NODE *child; if (NODE_IS_LEAF(node)) break; - if (!rt_node_search_inner(node, key, &child)) + if (!RT_NODE_SEARCH_INNER(node, key, &child)) return false; node = child; shift -= RT_NODE_SPAN; } - return rt_node_search_leaf(node, key, value_p); + return RT_NODE_SEARCH_LEAF(node, key, value_p); } /* * Delete the given key from the radix tree. Return true if the key is found (and * deleted), otherwise do nothing and return false. */ -bool -rt_delete(radix_tree *tree, uint64 key) +RT_SCOPE bool +RT_DELETE(RT_RADIX_TREE *tree, uint64 key) { - rt_node *node; - rt_node *stack[RT_MAX_LEVEL] = {0}; + RT_NODE *node; + RT_NODE *stack[RT_MAX_LEVEL] = {0}; int shift; int level; bool deleted; @@ -1230,12 +1347,12 @@ rt_delete(radix_tree *tree, uint64 key) level = -1; while (shift > 0) { - rt_node *child; + RT_NODE *child; /* Push the current node to the stack */ stack[++level] = node; - if (!rt_node_search_inner(node, key, &child)) + if (!RT_NODE_SEARCH_INNER(node, key, &child)) return false; node = child; @@ -1244,7 +1361,7 @@ rt_delete(radix_tree *tree, uint64 key) /* Delete the key from the leaf node if exists */ Assert(NODE_IS_LEAF(node)); - deleted = rt_node_delete_leaf(node, key); + deleted = RT_NODE_DELETE_LEAF(node, key); if (!deleted) { @@ -1263,14 +1380,14 @@ rt_delete(radix_tree *tree, uint64 key) return true; /* Free the empty leaf node */ - rt_free_node(tree, node); + RT_FREE_NODE(tree, node); /* Delete the key in inner nodes recursively */ while (level >= 0) { node = stack[level--]; - deleted = rt_node_delete_inner(node, key); + deleted = RT_NODE_DELETE_INNER(node, key); Assert(deleted); /* If the node didn't become empty, we stop deleting the key */ @@ -1278,55 +1395,56 @@ rt_delete(radix_tree *tree, uint64 key) break; /* The node became empty */ - rt_free_node(tree, node); + RT_FREE_NODE(tree, node); } return true; } -/* Create and return the iterator for the given radix tree */ -rt_iter * -rt_begin_iterate(radix_tree *tree) +static inline void +RT_ITER_UPDATE_KEY(RT_ITER *iter, uint8 chunk, uint8 shift) { - MemoryContext old_ctx; - rt_iter *iter; - int top_level; - - old_ctx = MemoryContextSwitchTo(tree->context); - - iter = (rt_iter *) palloc0(sizeof(rt_iter)); - iter->tree = tree; - - /* empty tree */ - if (!iter->tree->root) - return iter; - - top_level = iter->tree->root->shift / RT_NODE_SPAN; - iter->stack_len = top_level; - - /* - * Descend to the left most leaf node from the root. The key is being - * constructed while descending to the leaf. - */ - rt_update_iter_stack(iter, iter->tree->root, top_level); + iter->key &= ~(((uint64) RT_CHUNK_MASK) << shift); + iter->key |= (((uint64) chunk) << shift); +} - MemoryContextSwitchTo(old_ctx); +/* + * Advance the slot in the inner node. Return the child if exists, otherwise + * null. + */ +static inline RT_NODE * +RT_NODE_INNER_ITERATE_NEXT(RT_ITER *iter, RT_NODE_ITER *node_iter) +{ +#define RT_NODE_LEVEL_INNER +#include "lib/radixtree_iter_impl.h" +#undef RT_NODE_LEVEL_INNER +} - return iter; +/* + * Advance the slot in the leaf node. On success, return true and the value + * is set to value_p, otherwise return false. + */ +static inline bool +RT_NODE_LEAF_ITERATE_NEXT(RT_ITER *iter, RT_NODE_ITER *node_iter, + uint64 *value_p) +{ +#define RT_NODE_LEVEL_LEAF +#include "lib/radixtree_iter_impl.h" +#undef RT_NODE_LEVEL_LEAF } /* * Update each node_iter for inner nodes in the iterator node stack. */ static void -rt_update_iter_stack(rt_iter *iter, rt_node *from_node, int from) +RT_UPDATE_ITER_STACK(RT_ITER *iter, RT_NODE *from_node, int from) { int level = from; - rt_node *node = from_node; + RT_NODE *node = from_node; for (;;) { - rt_node_iter *node_iter = &(iter->stack[level--]); + RT_NODE_ITER *node_iter = &(iter->stack[level--]); node_iter->node = node; node_iter->current_idx = -1; @@ -1336,19 +1454,50 @@ rt_update_iter_stack(rt_iter *iter, rt_node *from_node, int from) return; /* Advance to the next slot in the inner node */ - node = rt_node_inner_iterate_next(iter, node_iter); + node = RT_NODE_INNER_ITERATE_NEXT(iter, node_iter); /* We must find the first children in the node */ Assert(node); } } +/* Create and return the iterator for the given radix tree */ +RT_SCOPE RT_ITER * +RT_BEGIN_ITERATE(RT_RADIX_TREE *tree) +{ + MemoryContext old_ctx; + RT_ITER *iter; + int top_level; + + old_ctx = MemoryContextSwitchTo(tree->context); + + iter = (RT_ITER *) palloc0(sizeof(RT_ITER)); + iter->tree = tree; + + /* empty tree */ + if (!iter->tree->root) + return iter; + + top_level = iter->tree->root->shift / RT_NODE_SPAN; + iter->stack_len = top_level; + + /* + * Descend to the left most leaf node from the root. The key is being + * constructed while descending to the leaf. + */ + RT_UPDATE_ITER_STACK(iter, iter->tree->root, top_level); + + MemoryContextSwitchTo(old_ctx); + + return iter; +} + /* * Return true with setting key_p and value_p if there is next key. Otherwise, * return false. */ -bool -rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p) +RT_SCOPE bool +RT_ITERATE_NEXT(RT_ITER *iter, uint64 *key_p, uint64 *value_p) { /* Empty tree */ if (!iter->tree->root) @@ -1356,13 +1505,13 @@ rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p) for (;;) { - rt_node *child = NULL; + RT_NODE *child = NULL; uint64 value; int level; bool found; /* Advance the leaf node iterator to get next key-value pair */ - found = rt_node_leaf_iterate_next(iter, &(iter->stack[0]), &value); + found = RT_NODE_LEAF_ITERATE_NEXT(iter, &(iter->stack[0]), &value); if (found) { @@ -1377,7 +1526,7 @@ rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p) */ for (level = 1; level <= iter->stack_len; level++) { - child = rt_node_inner_iterate_next(iter, &(iter->stack[level])); + child = RT_NODE_INNER_ITERATE_NEXT(iter, &(iter->stack[level])); if (child) break; @@ -1391,7 +1540,7 @@ rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p) * Set the node to the node iterator and update the iterator stack * from this node. */ - rt_update_iter_stack(iter, child, level - 1); + RT_UPDATE_ITER_STACK(iter, child, level - 1); /* Node iterators are updated, so try again from the leaf */ } @@ -1399,49 +1548,17 @@ rt_iterate_next(rt_iter *iter, uint64 *key_p, uint64 *value_p) return false; } -void -rt_end_iterate(rt_iter *iter) +RT_SCOPE void +RT_END_ITERATE(RT_ITER *iter) { pfree(iter); } -static inline void -rt_iter_update_key(rt_iter *iter, uint8 chunk, uint8 shift) -{ - iter->key &= ~(((uint64) RT_CHUNK_MASK) << shift); - iter->key |= (((uint64) chunk) << shift); -} - -/* - * Advance the slot in the inner node. Return the child if exists, otherwise - * null. - */ -static inline rt_node * -rt_node_inner_iterate_next(rt_iter *iter, rt_node_iter *node_iter) -{ -#define RT_NODE_LEVEL_INNER -#include "lib/radixtree_iter_impl.h" -#undef RT_NODE_LEVEL_INNER -} - -/* - * Advance the slot in the leaf node. On success, return true and the value - * is set to value_p, otherwise return false. - */ -static inline bool -rt_node_leaf_iterate_next(rt_iter *iter, rt_node_iter *node_iter, - uint64 *value_p) -{ -#define RT_NODE_LEVEL_LEAF -#include "lib/radixtree_iter_impl.h" -#undef RT_NODE_LEVEL_LEAF -} - /* * Return the number of keys in the radix tree. */ -uint64 -rt_num_entries(radix_tree *tree) +RT_SCOPE uint64 +RT_NUM_ENTRIES(RT_RADIX_TREE *tree) { return tree->num_keys; } @@ -1449,10 +1566,10 @@ rt_num_entries(radix_tree *tree) /* * Return the statistics of the amount of memory used by the radix tree. */ -uint64 -rt_memory_usage(radix_tree *tree) +RT_SCOPE uint64 +RT_MEMORY_USAGE(RT_RADIX_TREE *tree) { - Size total = sizeof(radix_tree); + Size total = sizeof(RT_RADIX_TREE); for (int i = 0; i < RT_SIZE_CLASS_COUNT; i++) { @@ -1467,7 +1584,7 @@ rt_memory_usage(radix_tree *tree) * Verify the radix tree node. */ static void -rt_verify_node(rt_node *node) +RT_VERIFY_NODE(RT_NODE *node) { #ifdef USE_ASSERT_CHECKING Assert(node->count >= 0); @@ -1476,7 +1593,7 @@ rt_verify_node(rt_node *node) { case RT_NODE_KIND_4: { - rt_node_base_4 *n4 = (rt_node_base_4 *) node; + RT_NODE_BASE_4 *n4 = (RT_NODE_BASE_4 *) node; for (int i = 1; i < n4->n.count; i++) Assert(n4->chunks[i - 1] < n4->chunks[i]); @@ -1485,7 +1602,7 @@ rt_verify_node(rt_node *node) } case RT_NODE_KIND_32: { - rt_node_base_32 *n32 = (rt_node_base_32 *) node; + RT_NODE_BASE_32 *n32 = (RT_NODE_BASE_32 *) node; for (int i = 1; i < n32->n.count; i++) Assert(n32->chunks[i - 1] < n32->chunks[i]); @@ -1494,7 +1611,7 @@ rt_verify_node(rt_node *node) } case RT_NODE_KIND_125: { - rt_node_base_125 *n125 = (rt_node_base_125 *) node; + RT_NODE_BASE_125 *n125 = (RT_NODE_BASE_125 *) node; int cnt = 0; for (int i = 0; i < RT_NODE_MAX_SLOTS; i++) @@ -1503,7 +1620,7 @@ rt_verify_node(rt_node *node) int idx = BM_IDX(slot); int bitnum = BM_BIT(slot); - if (!node_125_is_chunk_used(n125, i)) + if (!RT_NODE_125_IS_CHUNK_USED(n125, i)) continue; /* Check if the corresponding slot is used */ @@ -1520,7 +1637,7 @@ rt_verify_node(rt_node *node) { if (NODE_IS_LEAF(node)) { - rt_node_leaf_256 *n256 = (rt_node_leaf_256 *) node; + RT_NODE_LEAF_256 *n256 = (RT_NODE_LEAF_256 *) node; int cnt = 0; for (int i = 0; i < BM_IDX(RT_NODE_MAX_SLOTS); i++) @@ -1539,7 +1656,7 @@ rt_verify_node(rt_node *node) /***************** DEBUG FUNCTIONS *****************/ #ifdef RT_DEBUG void -rt_stats(radix_tree *tree) +rt_stats(RT_RADIX_TREE *tree) { ereport(NOTICE, (errmsg("num_keys = " UINT64_FORMAT ", height = %d, n4 = %u, n15 = %u, n32 = %u, n125 = %u, n256 = %u", tree->num_keys, @@ -1552,7 +1669,7 @@ rt_stats(radix_tree *tree) } static void -rt_dump_node(rt_node *node, int level, bool recurse) +rt_dump_node(RT_NODE *node, int level, bool recurse) { char space[125] = {0}; @@ -1575,14 +1692,14 @@ rt_dump_node(rt_node *node, int level, bool recurse) { if (NODE_IS_LEAF(node)) { - rt_node_leaf_4 *n4 = (rt_node_leaf_4 *) node; + RT_NODE_LEAF_4 *n4 = (RT_NODE_LEAF_4 *) node; fprintf(stderr, "%schunk 0x%X value 0x" UINT64_FORMAT_HEX "\n", space, n4->base.chunks[i], n4->values[i]); } else { - rt_node_inner_4 *n4 = (rt_node_inner_4 *) node; + RT_NODE_INNER_4 *n4 = (RT_NODE_INNER_4 *) node; fprintf(stderr, "%schunk 0x%X ->", space, n4->base.chunks[i]); @@ -1601,14 +1718,14 @@ rt_dump_node(rt_node *node, int level, bool recurse) { if (NODE_IS_LEAF(node)) { - rt_node_leaf_32 *n32 = (rt_node_leaf_32 *) node; + RT_NODE_LEAF_32 *n32 = (RT_NODE_LEAF_32 *) node; fprintf(stderr, "%schunk 0x%X value 0x" UINT64_FORMAT_HEX "\n", space, n32->base.chunks[i], n32->values[i]); } else { - rt_node_inner_32 *n32 = (rt_node_inner_32 *) node; + RT_NODE_INNER_32 *n32 = (RT_NODE_INNER_32 *) node; fprintf(stderr, "%schunk 0x%X ->", space, n32->base.chunks[i]); @@ -1625,19 +1742,19 @@ rt_dump_node(rt_node *node, int level, bool recurse) } case RT_NODE_KIND_125: { - rt_node_base_125 *b125 = (rt_node_base_125 *) node; + RT_NODE_BASE_125 *b125 = (RT_NODE_BASE_125 *) node; fprintf(stderr, "slot_idxs "); for (int i = 0; i < RT_NODE_MAX_SLOTS; i++) { - if (!node_125_is_chunk_used(b125, i)) + if (!RT_NODE_125_IS_CHUNK_USED(b125, i)) continue; fprintf(stderr, " [%d]=%d, ", i, b125->slot_idxs[i]); } if (NODE_IS_LEAF(node)) { - rt_node_leaf_125 *n = (rt_node_leaf_125 *) node; + RT_NODE_LEAF_125 *n = (RT_NODE_LEAF_125 *) node; fprintf(stderr, ", isset-bitmap:"); for (int i = 0; i < BM_IDX(128); i++) @@ -1649,25 +1766,25 @@ rt_dump_node(rt_node *node, int level, bool recurse) for (int i = 0; i < RT_NODE_MAX_SLOTS; i++) { - if (!node_125_is_chunk_used(b125, i)) + if (!RT_NODE_125_IS_CHUNK_USED(b125, i)) continue; if (NODE_IS_LEAF(node)) { - rt_node_leaf_125 *n125 = (rt_node_leaf_125 *) b125; + RT_NODE_LEAF_125 *n125 = (RT_NODE_LEAF_125 *) b125; fprintf(stderr, "%schunk 0x%X value 0x" UINT64_FORMAT_HEX "\n", - space, i, node_leaf_125_get_value(n125, i)); + space, i, RT_NODE_LEAF_125_GET_VALUE(n125, i)); } else { - rt_node_inner_125 *n125 = (rt_node_inner_125 *) b125; + RT_NODE_INNER_125 *n125 = (RT_NODE_INNER_125 *) b125; fprintf(stderr, "%schunk 0x%X ->", space, i); if (recurse) - rt_dump_node(node_inner_125_get_child(n125, i), + rt_dump_node(RT_NODE_INNER_125_GET_CHILD(n125, i), level + 1, recurse); else fprintf(stderr, "\n"); @@ -1681,26 +1798,26 @@ rt_dump_node(rt_node *node, int level, bool recurse) { if (NODE_IS_LEAF(node)) { - rt_node_leaf_256 *n256 = (rt_node_leaf_256 *) node; + RT_NODE_LEAF_256 *n256 = (RT_NODE_LEAF_256 *) node; - if (!node_leaf_256_is_chunk_used(n256, i)) + if (!RT_NODE_LEAF_256_IS_CHUNK_USED(n256, i)) continue; fprintf(stderr, "%schunk 0x%X value 0x" UINT64_FORMAT_HEX "\n", - space, i, node_leaf_256_get_value(n256, i)); + space, i, RT_NODE_LEAF_256_GET_VALUE(n256, i)); } else { - rt_node_inner_256 *n256 = (rt_node_inner_256 *) node; + RT_NODE_INNER_256 *n256 = (RT_NODE_INNER_256 *) node; - if (!node_inner_256_is_chunk_used(n256, i)) + if (!RT_NODE_INNER_256_IS_CHUNK_USED(n256, i)) continue; fprintf(stderr, "%schunk 0x%X ->", space, i); if (recurse) - rt_dump_node(node_inner_256_get_child(n256, i), level + 1, + rt_dump_node(RT_NODE_INNER_256_GET_CHILD(n256, i), level + 1, recurse); else fprintf(stderr, "\n"); @@ -1712,9 +1829,9 @@ rt_dump_node(rt_node *node, int level, bool recurse) } void -rt_dump_search(radix_tree *tree, uint64 key) +rt_dump_search(RT_RADIX_TREE *tree, uint64 key) { - rt_node *node; + RT_NODE *node; int shift; int level = 0; @@ -1739,7 +1856,7 @@ rt_dump_search(radix_tree *tree, uint64 key) shift = tree->root->shift; while (shift >= 0) { - rt_node *child; + RT_NODE *child; rt_dump_node(node, level, false); @@ -1748,12 +1865,12 @@ rt_dump_search(radix_tree *tree, uint64 key) uint64 dummy; /* We reached at a leaf node, find the corresponding slot */ - rt_node_search_leaf(node, key, &dummy); + RT_NODE_SEARCH_LEAF(node, key, &dummy); break; } - if (!rt_node_search_inner(node, key, &child)) + if (!RT_NODE_SEARCH_INNER(node, key, &child)) break; node = child; @@ -1763,16 +1880,16 @@ rt_dump_search(radix_tree *tree, uint64 key) } void -rt_dump(radix_tree *tree) +rt_dump(RT_RADIX_TREE *tree) { for (int i = 0; i < RT_SIZE_CLASS_COUNT; i++) fprintf(stderr, "%s\tinner_size %zu\tinner_blocksize %zu\tleaf_size %zu\tleaf_blocksize %zu\n", - rt_size_class_info[i].name, - rt_size_class_info[i].inner_size, - rt_size_class_info[i].inner_blocksize, - rt_size_class_info[i].leaf_size, - rt_size_class_info[i].leaf_blocksize); + RT_SIZE_CLASS_INFO[i].name, + RT_SIZE_CLASS_INFO[i].inner_size, + RT_SIZE_CLASS_INFO[i].inner_blocksize, + RT_SIZE_CLASS_INFO[i].leaf_size, + RT_SIZE_CLASS_INFO[i].leaf_blocksize); fprintf(stderr, "max_val = " UINT64_FORMAT "\n", tree->max_val); if (!tree->root) @@ -1784,3 +1901,107 @@ rt_dump(radix_tree *tree) rt_dump_node(tree->root, 0, true); } #endif + +#endif /* RT_DEFINE */ + + +/* undefine external parameters, so next radix tree can be defined */ +#undef RT_PREFIX +#undef RT_SCOPE +#undef RT_DECLARE +#undef RT_DEFINE + +/* locally declared macros */ +#undef NODE_IS_LEAF +#undef NODE_IS_EMPTY +#undef VAR_NODE_HAS_FREE_SLOT +#undef FIXED_NODE_HAS_FREE_SLOT +#undef RT_SIZE_CLASS_COUNT + +/* type declarations */ +#undef RT_RADIX_TREE +#undef RT_ITER +#undef RT_NODE +#undef RT_NODE_ITER +#undef RT_NODE_BASE_4 +#undef RT_NODE_BASE_32 +#undef RT_NODE_BASE_125 +#undef RT_NODE_BASE_256 +#undef RT_NODE_INNER_4 +#undef RT_NODE_INNER_32 +#undef RT_NODE_INNER_125 +#undef RT_NODE_INNER_256 +#undef RT_NODE_LEAF_4 +#undef RT_NODE_LEAF_32 +#undef RT_NODE_LEAF_125 +#undef RT_NODE_LEAF_256 +#undef RT_SIZE_CLASS +#undef RT_SIZE_CLASS_ELEM +#undef RT_SIZE_CLASS_INFO +#undef RT_CLASS_4_FULL +#undef RT_CLASS_32_PARTIAL +#undef RT_CLASS_32_FULL +#undef RT_CLASS_125_FULL +#undef RT_CLASS_256 +#undef RT_KIND_MIN_SIZE_CLASS + +/* function declarations */ +#undef RT_CREATE +#undef RT_FREE +#undef RT_SET +#undef RT_BEGIN_ITERATE +#undef RT_ITERATE_NEXT +#undef RT_END_ITERATE +#undef RT_DELETE +#undef RT_MEMORY_USAGE +#undef RT_NUM_ENTRIES +#undef RT_DUMP +#undef RT_DUMP_SEARCH +#undef RT_STATS + +/* internal helper functions */ +#undef RT_NEW_ROOT +#undef RT_ALLOC_NODE +#undef RT_INIT_NODE +#undef RT_FREE_NODE +#undef RT_EXTEND +#undef RT_SET_EXTEND +#undef RT_GROW_NODE_KIND +#undef RT_COPY_NODE +#undef RT_REPLACE_NODE +#undef RT_NODE_4_SEARCH_EQ +#undef RT_NODE_32_SEARCH_EQ +#undef RT_NODE_4_GET_INSERTPOS +#undef RT_NODE_32_GET_INSERTPOS +#undef RT_CHUNK_CHILDREN_ARRAY_SHIFT +#undef RT_CHUNK_VALUES_ARRAY_SHIFT +#undef RT_CHUNK_CHILDREN_ARRAY_DELETE +#undef RT_CHUNK_VALUES_ARRAY_DELETE +#undef RT_CHUNK_CHILDREN_ARRAY_COPY +#undef RT_CHUNK_VALUES_ARRAY_COPY +#undef RT_NODE_125_IS_CHUNK_USED +#undef RT_NODE_INNER_125_GET_CHILD +#undef RT_NODE_LEAF_125_GET_VALUE +#undef RT_NODE_INNER_256_IS_CHUNK_USED +#undef RT_NODE_LEAF_256_IS_CHUNK_USED +#undef RT_NODE_INNER_256_GET_CHILD +#undef RT_NODE_LEAF_256_GET_VALUE +#undef RT_NODE_INNER_256_SET +#undef RT_NODE_LEAF_256_SET +#undef RT_NODE_INNER_256_DELETE +#undef RT_NODE_LEAF_256_DELETE +#undef RT_KEY_GET_SHIFT +#undef RT_SHIFT_GET_MAX_VAL +#undef RT_NODE_SEARCH_INNER +#undef RT_NODE_SEARCH_LEAF +#undef RT_NODE_DELETE_INNER +#undef RT_NODE_DELETE_LEAF +#undef RT_NODE_INSERT_INNER +#undef RT_NODE_INSERT_LEAF +#undef RT_NODE_INNER_ITERATE_NEXT +#undef RT_NODE_LEAF_ITERATE_NEXT +#undef RT_UPDATE_ITER_STACK +#undef RT_ITER_UPDATE_KEY +#undef RT_VERIFY_NODE + +#undef RT_DEBUG diff --git a/src/include/lib/radixtree_delete_impl.h b/src/include/lib/radixtree_delete_impl.h index 24fd9cc02b..6eefc63e19 100644 --- a/src/include/lib/radixtree_delete_impl.h +++ b/src/include/lib/radixtree_delete_impl.h @@ -1,15 +1,15 @@ /* TODO: shrink nodes */ #if defined(RT_NODE_LEVEL_INNER) -#define RT_NODE4_TYPE rt_node_inner_4 -#define RT_NODE32_TYPE rt_node_inner_32 -#define RT_NODE125_TYPE rt_node_inner_125 -#define RT_NODE256_TYPE rt_node_inner_256 +#define RT_NODE4_TYPE RT_NODE_INNER_4 +#define RT_NODE32_TYPE RT_NODE_INNER_32 +#define RT_NODE125_TYPE RT_NODE_INNER_125 +#define RT_NODE256_TYPE RT_NODE_INNER_256 #elif defined(RT_NODE_LEVEL_LEAF) -#define RT_NODE4_TYPE rt_node_leaf_4 -#define RT_NODE32_TYPE rt_node_leaf_32 -#define RT_NODE125_TYPE rt_node_leaf_125 -#define RT_NODE256_TYPE rt_node_leaf_256 +#define RT_NODE4_TYPE RT_NODE_LEAF_4 +#define RT_NODE32_TYPE RT_NODE_LEAF_32 +#define RT_NODE125_TYPE RT_NODE_LEAF_125 +#define RT_NODE256_TYPE RT_NODE_LEAF_256 #else #error node level must be either inner or leaf #endif @@ -21,16 +21,16 @@ case RT_NODE_KIND_4: { RT_NODE4_TYPE *n4 = (RT_NODE4_TYPE *) node; - int idx = node_4_search_eq((rt_node_base_4 *) n4, chunk); + int idx = RT_NODE_4_SEARCH_EQ((RT_NODE_BASE_4 *) n4, chunk); if (idx < 0) return false; #ifdef RT_NODE_LEVEL_LEAF - chunk_values_array_delete(n4->base.chunks, (uint64 *) n4->values, + RT_CHUNK_VALUES_ARRAY_DELETE(n4->base.chunks, (uint64 *) n4->values, n4->base.n.count, idx); #else - chunk_children_array_delete(n4->base.chunks, n4->children, + RT_CHUNK_CHILDREN_ARRAY_DELETE(n4->base.chunks, n4->children, n4->base.n.count, idx); #endif break; @@ -38,16 +38,16 @@ case RT_NODE_KIND_32: { RT_NODE32_TYPE *n32 = (RT_NODE32_TYPE *) node; - int idx = node_32_search_eq((rt_node_base_32 *) n32, chunk); + int idx = RT_NODE_32_SEARCH_EQ((RT_NODE_BASE_32 *) n32, chunk); if (idx < 0) return false; #ifdef RT_NODE_LEVEL_LEAF - chunk_values_array_delete(n32->base.chunks, (uint64 *) n32->values, + RT_CHUNK_VALUES_ARRAY_DELETE(n32->base.chunks, (uint64 *) n32->values, n32->base.n.count, idx); #else - chunk_children_array_delete(n32->base.chunks, n32->children, + RT_CHUNK_CHILDREN_ARRAY_DELETE(n32->base.chunks, n32->children, n32->base.n.count, idx); #endif break; @@ -74,16 +74,16 @@ RT_NODE256_TYPE *n256 = (RT_NODE256_TYPE *) node; #ifdef RT_NODE_LEVEL_LEAF - if (!node_leaf_256_is_chunk_used(n256, chunk)) + if (!RT_NODE_LEAF_256_IS_CHUNK_USED(n256, chunk)) #else - if (!node_inner_256_is_chunk_used(n256, chunk)) + if (!RT_NODE_INNER_256_IS_CHUNK_USED(n256, chunk)) #endif return false; #ifdef RT_NODE_LEVEL_LEAF - node_leaf_256_delete(n256, chunk); + RT_NODE_LEAF_256_DELETE(n256, chunk); #else - node_inner_256_delete(n256, chunk); + RT_NODE_INNER_256_DELETE(n256, chunk); #endif break; } diff --git a/src/include/lib/radixtree_insert_impl.h b/src/include/lib/radixtree_insert_impl.h index c63fe9a3c0..ff76583402 100644 --- a/src/include/lib/radixtree_insert_impl.h +++ b/src/include/lib/radixtree_insert_impl.h @@ -1,20 +1,20 @@ #if defined(RT_NODE_LEVEL_INNER) -#define RT_NODE4_TYPE rt_node_inner_4 -#define RT_NODE32_TYPE rt_node_inner_32 -#define RT_NODE125_TYPE rt_node_inner_125 -#define RT_NODE256_TYPE rt_node_inner_256 +#define RT_NODE4_TYPE RT_NODE_INNER_4 +#define RT_NODE32_TYPE RT_NODE_INNER_32 +#define RT_NODE125_TYPE RT_NODE_INNER_125 +#define RT_NODE256_TYPE RT_NODE_INNER_256 #elif defined(RT_NODE_LEVEL_LEAF) -#define RT_NODE4_TYPE rt_node_leaf_4 -#define RT_NODE32_TYPE rt_node_leaf_32 -#define RT_NODE125_TYPE rt_node_leaf_125 -#define RT_NODE256_TYPE rt_node_leaf_256 +#define RT_NODE4_TYPE RT_NODE_LEAF_4 +#define RT_NODE32_TYPE RT_NODE_LEAF_32 +#define RT_NODE125_TYPE RT_NODE_LEAF_125 +#define RT_NODE256_TYPE RT_NODE_LEAF_256 #else #error node level must be either inner or leaf #endif uint8 chunk = RT_GET_KEY_CHUNK(key, node->shift); bool chunk_exists = false; - rt_node *newnode = NULL; + RT_NODE *newnode = NULL; #ifdef RT_NODE_LEVEL_LEAF Assert(NODE_IS_LEAF(node)); @@ -29,7 +29,7 @@ RT_NODE4_TYPE *n4 = (RT_NODE4_TYPE *) node; int idx; - idx = node_4_search_eq(&n4->base, chunk); + idx = RT_NODE_4_SEARCH_EQ(&n4->base, chunk); if (idx != -1) { /* found the existing chunk */ @@ -47,22 +47,22 @@ RT_NODE32_TYPE *new32; /* grow node from 4 to 32 */ - newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_32); + newnode = RT_GROW_NODE_KIND(tree, node, RT_NODE_KIND_32); new32 = (RT_NODE32_TYPE *) newnode; #ifdef RT_NODE_LEVEL_LEAF - chunk_values_array_copy(n4->base.chunks, n4->values, + RT_CHUNK_VALUES_ARRAY_COPY(n4->base.chunks, n4->values, new32->base.chunks, new32->values); #else - chunk_children_array_copy(n4->base.chunks, n4->children, + RT_CHUNK_CHILDREN_ARRAY_COPY(n4->base.chunks, n4->children, new32->base.chunks, new32->children); #endif Assert(parent != NULL); - rt_replace_node(tree, parent, node, newnode, key); + RT_REPLACE_NODE(tree, parent, node, newnode, key); node = newnode; } else { - int insertpos = node_4_get_insertpos(&n4->base, chunk); + int insertpos = RT_NODE_4_GET_INSERTPOS(&n4->base, chunk); int count = n4->base.n.count; /* shift chunks and children */ @@ -70,10 +70,10 @@ { Assert(count > 0); #ifdef RT_NODE_LEVEL_LEAF - chunk_values_array_shift(n4->base.chunks, n4->values, + RT_CHUNK_VALUES_ARRAY_SHIFT(n4->base.chunks, n4->values, count, insertpos); #else - chunk_children_array_shift(n4->base.chunks, n4->children, + RT_CHUNK_CHILDREN_ARRAY_SHIFT(n4->base.chunks, n4->children, count, insertpos); #endif } @@ -90,12 +90,12 @@ /* FALLTHROUGH */ case RT_NODE_KIND_32: { - const rt_size_class_elem minclass = rt_size_class_info[RT_CLASS_32_PARTIAL]; - const rt_size_class_elem maxclass = rt_size_class_info[RT_CLASS_32_FULL]; + const RT_SIZE_CLASS_ELEM class32_min = RT_SIZE_CLASS_INFO[RT_CLASS_32_PARTIAL]; + const RT_SIZE_CLASS_ELEM class32_max = RT_SIZE_CLASS_INFO[RT_CLASS_32_FULL]; RT_NODE32_TYPE *n32 = (RT_NODE32_TYPE *) node; int idx; - idx = node_32_search_eq(&n32->base, chunk); + idx = RT_NODE_32_SEARCH_EQ(&n32->base, chunk); if (idx != -1) { /* found the existing chunk */ @@ -109,20 +109,20 @@ } if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)) && - n32->base.n.fanout == minclass.fanout) + n32->base.n.fanout == class32_min.fanout) { /* grow to the next size class of this kind */ #ifdef RT_NODE_LEVEL_LEAF - newnode = rt_alloc_node(tree, RT_CLASS_32_FULL, false); - memcpy(newnode, node, minclass.leaf_size); + newnode = RT_ALLOC_NODE(tree, RT_CLASS_32_FULL, false); + memcpy(newnode, node, class32_min.leaf_size); #else - newnode = rt_alloc_node(tree, RT_CLASS_32_FULL, true); - memcpy(newnode, node, minclass.inner_size); + newnode = RT_ALLOC_NODE(tree, RT_CLASS_32_FULL, true); + memcpy(newnode, node, class32_min.inner_size); #endif - newnode->fanout = maxclass.fanout; + newnode->fanout = class32_max.fanout; Assert(parent != NULL); - rt_replace_node(tree, parent, node, newnode, key); + RT_REPLACE_NODE(tree, parent, node, newnode, key); node = newnode; /* also update pointer for this kind */ @@ -133,13 +133,13 @@ { RT_NODE125_TYPE *new125; - Assert(n32->base.n.fanout == maxclass.fanout); + Assert(n32->base.n.fanout == class32_max.fanout); /* grow node from 32 to 125 */ - newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_125); + newnode = RT_GROW_NODE_KIND(tree, node, RT_NODE_KIND_125); new125 = (RT_NODE125_TYPE *) newnode; - for (int i = 0; i < maxclass.fanout; i++) + for (int i = 0; i < class32_max.fanout; i++) { new125->base.slot_idxs[n32->base.chunks[i]] = i; #ifdef RT_NODE_LEVEL_LEAF @@ -149,26 +149,26 @@ #endif } - Assert(maxclass.fanout <= sizeof(bitmapword) * BITS_PER_BYTE); - new125->base.isset[0] = (bitmapword) (((uint64) 1 << maxclass.fanout) - 1); + Assert(class32_max.fanout <= sizeof(bitmapword) * BITS_PER_BYTE); + new125->base.isset[0] = (bitmapword) (((uint64) 1 << class32_max.fanout) - 1); Assert(parent != NULL); - rt_replace_node(tree, parent, node, newnode, key); + RT_REPLACE_NODE(tree, parent, node, newnode, key); node = newnode; } else { - int insertpos = node_32_get_insertpos(&n32->base, chunk); + int insertpos = RT_NODE_32_GET_INSERTPOS(&n32->base, chunk); int count = n32->base.n.count; if (insertpos < count) { Assert(count > 0); #ifdef RT_NODE_LEVEL_LEAF - chunk_values_array_shift(n32->base.chunks, n32->values, + RT_CHUNK_VALUES_ARRAY_SHIFT(n32->base.chunks, n32->values, count, insertpos); #else - chunk_children_array_shift(n32->base.chunks, n32->children, + RT_CHUNK_CHILDREN_ARRAY_SHIFT(n32->base.chunks, n32->children, count, insertpos); #endif } @@ -206,22 +206,22 @@ RT_NODE256_TYPE *new256; /* grow node from 125 to 256 */ - newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_256); + newnode = RT_GROW_NODE_KIND(tree, node, RT_NODE_KIND_256); new256 = (RT_NODE256_TYPE *) newnode; for (int i = 0; i < RT_NODE_MAX_SLOTS && cnt < n125->base.n.count; i++) { - if (!node_125_is_chunk_used(&n125->base, i)) + if (!RT_NODE_125_IS_CHUNK_USED(&n125->base, i)) continue; #ifdef RT_NODE_LEVEL_LEAF - node_leaf_256_set(new256, i, node_leaf_125_get_value(n125, i)); + RT_NODE_LEAF_256_SET(new256, i, RT_NODE_LEAF_125_GET_VALUE(n125, i)); #else - node_inner_256_set(new256, i, node_inner_125_get_child(n125, i)); + RT_NODE_INNER_256_SET(new256, i, RT_NODE_INNER_125_GET_CHILD(n125, i)); #endif cnt++; } Assert(parent != NULL); - rt_replace_node(tree, parent, node, newnode, key); + RT_REPLACE_NODE(tree, parent, node, newnode, key); node = newnode; } else @@ -260,16 +260,16 @@ RT_NODE256_TYPE *n256 = (RT_NODE256_TYPE *) node; #ifdef RT_NODE_LEVEL_LEAF - chunk_exists = node_leaf_256_is_chunk_used(n256, chunk); + chunk_exists = RT_NODE_LEAF_256_IS_CHUNK_USED(n256, chunk); #else - chunk_exists = node_inner_256_is_chunk_used(n256, chunk); + chunk_exists = RT_NODE_INNER_256_IS_CHUNK_USED(n256, chunk); #endif Assert(chunk_exists || FIXED_NODE_HAS_FREE_SLOT(n256, RT_CLASS_256)); #ifdef RT_NODE_LEVEL_LEAF - node_leaf_256_set(n256, chunk, value); + RT_NODE_LEAF_256_SET(n256, chunk, value); #else - node_inner_256_set(n256, chunk, child); + RT_NODE_INNER_256_SET(n256, chunk, child); #endif break; } @@ -283,7 +283,7 @@ * Done. Finally, verify the chunk and value is inserted or replaced * properly in the node. */ - rt_verify_node(node); + RT_VERIFY_NODE(node); return chunk_exists; diff --git a/src/include/lib/radixtree_iter_impl.h b/src/include/lib/radixtree_iter_impl.h index bebf8e725a..a153011376 100644 --- a/src/include/lib/radixtree_iter_impl.h +++ b/src/include/lib/radixtree_iter_impl.h @@ -1,13 +1,13 @@ #if defined(RT_NODE_LEVEL_INNER) -#define RT_NODE4_TYPE rt_node_inner_4 -#define RT_NODE32_TYPE rt_node_inner_32 -#define RT_NODE125_TYPE rt_node_inner_125 -#define RT_NODE256_TYPE rt_node_inner_256 +#define RT_NODE4_TYPE RT_NODE_INNER_4 +#define RT_NODE32_TYPE RT_NODE_INNER_32 +#define RT_NODE125_TYPE RT_NODE_INNER_125 +#define RT_NODE256_TYPE RT_NODE_INNER_256 #elif defined(RT_NODE_LEVEL_LEAF) -#define RT_NODE4_TYPE rt_node_leaf_4 -#define RT_NODE32_TYPE rt_node_leaf_32 -#define RT_NODE125_TYPE rt_node_leaf_125 -#define RT_NODE256_TYPE rt_node_leaf_256 +#define RT_NODE4_TYPE RT_NODE_LEAF_4 +#define RT_NODE32_TYPE RT_NODE_LEAF_32 +#define RT_NODE125_TYPE RT_NODE_LEAF_125 +#define RT_NODE256_TYPE RT_NODE_LEAF_256 #else #error node level must be either inner or leaf #endif @@ -15,7 +15,7 @@ #ifdef RT_NODE_LEVEL_LEAF uint64 value; #else - rt_node *child = NULL; + RT_NODE *child = NULL; #endif bool found = false; uint8 key_chunk; @@ -62,7 +62,7 @@ for (i = node_iter->current_idx + 1; i < RT_NODE_MAX_SLOTS; i++) { - if (node_125_is_chunk_used((rt_node_base_125 *) n125, i)) + if (RT_NODE_125_IS_CHUNK_USED((RT_NODE_BASE_125 *) n125, i)) break; } @@ -71,9 +71,9 @@ node_iter->current_idx = i; #ifdef RT_NODE_LEVEL_LEAF - value = node_leaf_125_get_value(n125, i); + value = RT_NODE_LEAF_125_GET_VALUE(n125, i); #else - child = node_inner_125_get_child(n125, i); + child = RT_NODE_INNER_125_GET_CHILD(n125, i); #endif key_chunk = i; found = true; @@ -87,9 +87,9 @@ for (i = node_iter->current_idx + 1; i < RT_NODE_MAX_SLOTS; i++) { #ifdef RT_NODE_LEVEL_LEAF - if (node_leaf_256_is_chunk_used(n256, i)) + if (RT_NODE_LEAF_256_IS_CHUNK_USED(n256, i)) #else - if (node_inner_256_is_chunk_used(n256, i)) + if (RT_NODE_INNER_256_IS_CHUNK_USED(n256, i)) #endif break; } @@ -99,9 +99,9 @@ node_iter->current_idx = i; #ifdef RT_NODE_LEVEL_LEAF - value = node_leaf_256_get_value(n256, i); + value = RT_NODE_LEAF_256_GET_VALUE(n256, i); #else - child = node_inner_256_get_child(n256, i); + child = RT_NODE_INNER_256_GET_CHILD(n256, i); #endif key_chunk = i; found = true; @@ -111,7 +111,7 @@ if (found) { - rt_iter_update_key(iter, key_chunk, node_iter->node->shift); + RT_ITER_UPDATE_KEY(iter, key_chunk, node_iter->node->shift); #ifdef RT_NODE_LEVEL_LEAF *value_p = value; #endif diff --git a/src/include/lib/radixtree_search_impl.h b/src/include/lib/radixtree_search_impl.h index d0366f9bb6..1a0d2d3f1f 100644 --- a/src/include/lib/radixtree_search_impl.h +++ b/src/include/lib/radixtree_search_impl.h @@ -1,13 +1,13 @@ #if defined(RT_NODE_LEVEL_INNER) -#define RT_NODE4_TYPE rt_node_inner_4 -#define RT_NODE32_TYPE rt_node_inner_32 -#define RT_NODE125_TYPE rt_node_inner_125 -#define RT_NODE256_TYPE rt_node_inner_256 +#define RT_NODE4_TYPE RT_NODE_INNER_4 +#define RT_NODE32_TYPE RT_NODE_INNER_32 +#define RT_NODE125_TYPE RT_NODE_INNER_125 +#define RT_NODE256_TYPE RT_NODE_INNER_256 #elif defined(RT_NODE_LEVEL_LEAF) -#define RT_NODE4_TYPE rt_node_leaf_4 -#define RT_NODE32_TYPE rt_node_leaf_32 -#define RT_NODE125_TYPE rt_node_leaf_125 -#define RT_NODE256_TYPE rt_node_leaf_256 +#define RT_NODE4_TYPE RT_NODE_LEAF_4 +#define RT_NODE32_TYPE RT_NODE_LEAF_32 +#define RT_NODE125_TYPE RT_NODE_LEAF_125 +#define RT_NODE256_TYPE RT_NODE_LEAF_256 #else #error node level must be either inner or leaf #endif @@ -17,7 +17,7 @@ #ifdef RT_NODE_LEVEL_LEAF uint64 value = 0; #else - rt_node *child = NULL; + RT_NODE *child = NULL; #endif switch (node->kind) @@ -25,7 +25,7 @@ case RT_NODE_KIND_4: { RT_NODE4_TYPE *n4 = (RT_NODE4_TYPE *) node; - int idx = node_4_search_eq((rt_node_base_4 *) n4, chunk); + int idx = RT_NODE_4_SEARCH_EQ((RT_NODE_BASE_4 *) n4, chunk); if (idx < 0) return false; @@ -40,7 +40,7 @@ case RT_NODE_KIND_32: { RT_NODE32_TYPE *n32 = (RT_NODE32_TYPE *) node; - int idx = node_32_search_eq((rt_node_base_32 *) n32, chunk); + int idx = RT_NODE_32_SEARCH_EQ((RT_NODE_BASE_32 *) n32, chunk); if (idx < 0) return false; @@ -56,13 +56,13 @@ { RT_NODE125_TYPE *n125 = (RT_NODE125_TYPE *) node; - if (!node_125_is_chunk_used((rt_node_base_125 *) n125, chunk)) + if (!RT_NODE_125_IS_CHUNK_USED((RT_NODE_BASE_125 *) n125, chunk)) return false; #ifdef RT_NODE_LEVEL_LEAF - value = node_leaf_125_get_value(n125, chunk); + value = RT_NODE_LEAF_125_GET_VALUE(n125, chunk); #else - child = node_inner_125_get_child(n125, chunk); + child = RT_NODE_INNER_125_GET_CHILD(n125, chunk); #endif break; } @@ -71,16 +71,16 @@ RT_NODE256_TYPE *n256 = (RT_NODE256_TYPE *) node; #ifdef RT_NODE_LEVEL_LEAF - if (!node_leaf_256_is_chunk_used(n256, chunk)) + if (!RT_NODE_LEAF_256_IS_CHUNK_USED(n256, chunk)) #else - if (!node_inner_256_is_chunk_used(n256, chunk)) + if (!RT_NODE_INNER_256_IS_CHUNK_USED(n256, chunk)) #endif return false; #ifdef RT_NODE_LEVEL_LEAF - value = node_leaf_256_get_value(n256, chunk); + value = RT_NODE_LEAF_256_GET_VALUE(n256, chunk); #else - child = node_inner_256_get_child(n256, chunk); + child = RT_NODE_INNER_256_GET_CHILD(n256, chunk); #endif break; } diff --git a/src/test/modules/test_radixtree/test_radixtree.c b/src/test/modules/test_radixtree/test_radixtree.c index ea993e63df..2256d08100 100644 --- a/src/test/modules/test_radixtree/test_radixtree.c +++ b/src/test/modules/test_radixtree/test_radixtree.c @@ -14,7 +14,6 @@ #include "common/pg_prng.h" #include "fmgr.h" -#include "lib/radixtree.h" #include "miscadmin.h" #include "nodes/bitmapset.h" #include "storage/block.h" @@ -99,6 +98,14 @@ static const test_spec test_specs[] = { } }; +/* define the radix tree implementation to test */ +#define RT_PREFIX rt +#define RT_SCOPE static +#define RT_DECLARE +#define RT_DEFINE +#include "lib/radixtree.h" + + PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(test_radixtree); @@ -106,7 +113,7 @@ PG_FUNCTION_INFO_V1(test_radixtree); static void test_empty(void) { - radix_tree *radixtree; + rt_radix_tree *radixtree; rt_iter *iter; uint64 dummy; uint64 key; @@ -142,7 +149,7 @@ test_empty(void) static void test_basic(int children, bool test_inner) { - radix_tree *radixtree; + rt_radix_tree *radixtree; uint64 *keys; int shift = test_inner ? 8 : 0; @@ -192,7 +199,7 @@ test_basic(int children, bool test_inner) * Check if keys from start to end with the shift exist in the tree. */ static void -check_search_on_node(radix_tree *radixtree, uint8 shift, int start, int end, +check_search_on_node(rt_radix_tree *radixtree, uint8 shift, int start, int end, int incr) { for (int i = start; i < end; i++) @@ -210,7 +217,7 @@ check_search_on_node(radix_tree *radixtree, uint8 shift, int start, int end, } static void -test_node_types_insert(radix_tree *radixtree, uint8 shift, bool insert_asc) +test_node_types_insert(rt_radix_tree *radixtree, uint8 shift, bool insert_asc) { uint64 num_entries; int ninserted = 0; @@ -257,7 +264,7 @@ test_node_types_insert(radix_tree *radixtree, uint8 shift, bool insert_asc) } static void -test_node_types_delete(radix_tree *radixtree, uint8 shift) +test_node_types_delete(rt_radix_tree *radixtree, uint8 shift) { uint64 num_entries; @@ -288,7 +295,7 @@ test_node_types_delete(radix_tree *radixtree, uint8 shift) static void test_node_types(uint8 shift) { - radix_tree *radixtree; + rt_radix_tree *radixtree; elog(NOTICE, "testing radix tree node types with shift \"%d\"", shift); @@ -312,7 +319,7 @@ test_node_types(uint8 shift) static void test_pattern(const test_spec * spec) { - radix_tree *radixtree; + rt_radix_tree *radixtree; rt_iter *iter; MemoryContext radixtree_ctx; TimestampTz starttime; -- 2.39.0