From: Willy Tarreau Date: Fri, 16 May 2008 17:48:20 +0000 (+0200) Subject: [MEDIUM] upgrade to ebtree v4.0 X-Git-Tag: v1.3.16-rc1~272 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1fb6c87cce82f7f620f30e7b44fa607114fec8d9;p=thirdparty%2Fhaproxy.git [MEDIUM] upgrade to ebtree v4.0 New ebtree also supports unique keys. This is useful for counters. --- diff --git a/include/common/eb32tree.h b/include/common/eb32tree.h index f0c7930357..6a39595b5c 100644 --- a/include/common/eb32tree.h +++ b/include/common/eb32tree.h @@ -1,6 +1,7 @@ /* * Elastic Binary Trees - macros and structures for operations on 32bit nodes. - * (C) 2002-2007 - Willy Tarreau + * Version 4.0 + * (C) 2002-2008 - Willy Tarreau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -204,6 +205,7 @@ static inline struct eb32_node *__eb32i_lookup(struct eb_root *root, s32 x) /* Insert eb32_node into subtree starting at node root . * Only new->key needs be set with the key. The eb32_node is returned. + * If root->b[EB_RGHT]==1, the tree may only contain unique keys. */ static inline struct eb32_node * __eb32_insert(struct eb_root *root, struct eb32_node *new) { @@ -211,9 +213,11 @@ __eb32_insert(struct eb_root *root, struct eb32_node *new) { unsigned int side; eb_troot_t *troot; u32 newkey; /* caching the key saves approximately one cycle */ + eb_troot_t *root_right = root; side = EB_LEFT; troot = root->b[EB_LEFT]; + root_right = root->b[EB_RGHT]; if (unlikely(troot == NULL)) { /* Tree is empty, insert the leaf part below the left branch */ root->b[EB_LEFT] = eb_dotag(&new->node.branches, EB_LEAF); @@ -272,6 +276,12 @@ __eb32_insert(struct eb_root *root, struct eb32_node *new) { new->node.branches.b[EB_LEFT] = new_leaf; new->node.branches.b[EB_RGHT] = old_leaf; } else { + /* we may refuse to duplicate this key if the tree is + * tagged as containing only unique keys. + */ + if ((new->key == old->key) && eb_gettag(root_right)) + return old; + /* new->key >= old->key, new goes the right */ old->node.leaf_p = new_left; new->node.leaf_p = new_rght; @@ -359,7 +369,7 @@ __eb32_insert(struct eb_root *root, struct eb32_node *new) { /* Insert eb32_node into subtree starting at node root , using * signed keys. Only new->key needs be set with the key. The eb32_node - * is returned + * is returned. If root->b[EB_RGHT]==1, the tree may only contain unique keys. */ static inline struct eb32_node * __eb32i_insert(struct eb_root *root, struct eb32_node *new) { @@ -367,9 +377,11 @@ __eb32i_insert(struct eb_root *root, struct eb32_node *new) { unsigned int side; eb_troot_t *troot; int newkey; /* caching the key saves approximately one cycle */ + eb_troot_t *root_right = root; side = EB_LEFT; troot = root->b[EB_LEFT]; + root_right = root->b[EB_RGHT]; if (unlikely(troot == NULL)) { /* Tree is empty, insert the leaf part below the left branch */ root->b[EB_LEFT] = eb_dotag(&new->node.branches, EB_LEAF); @@ -430,6 +442,12 @@ __eb32i_insert(struct eb_root *root, struct eb32_node *new) { new->node.branches.b[EB_LEFT] = new_leaf; new->node.branches.b[EB_RGHT] = old_leaf; } else { + /* we may refuse to duplicate this key if the tree is + * tagged as containing only unique keys. + */ + if ((new->key == old->key) && eb_gettag(root_right)) + return old; + /* new->key >= old->key, new goes the right */ old->node.leaf_p = new_left; new->node.leaf_p = new_rght; diff --git a/include/common/eb64tree.h b/include/common/eb64tree.h index 9a069ca53f..767ba834b9 100644 --- a/include/common/eb64tree.h +++ b/include/common/eb64tree.h @@ -1,6 +1,7 @@ /* * Elastic Binary Trees - macros and structures for operations on 64bit nodes. - * (C) 2002-2007 - Willy Tarreau + * Version 4.0 + * (C) 2002-2008 - Willy Tarreau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -204,6 +205,7 @@ static inline struct eb64_node *__eb64i_lookup(struct eb_root *root, s64 x) /* Insert eb64_node into subtree starting at node root . * Only new->key needs be set with the key. The eb64_node is returned. + * If root->b[EB_RGHT]==1, the tree may only contain unique keys. */ static inline struct eb64_node * __eb64_insert(struct eb_root *root, struct eb64_node *new) { @@ -211,9 +213,11 @@ __eb64_insert(struct eb_root *root, struct eb64_node *new) { unsigned int side; eb_troot_t *troot; u64 newkey; /* caching the key saves approximately one cycle */ + eb_troot_t *root_right = root; side = EB_LEFT; troot = root->b[EB_LEFT]; + root_right = root->b[EB_RGHT]; if (unlikely(troot == NULL)) { /* Tree is empty, insert the leaf part below the left branch */ root->b[EB_LEFT] = eb_dotag(&new->node.branches, EB_LEAF); @@ -272,6 +276,12 @@ __eb64_insert(struct eb_root *root, struct eb64_node *new) { new->node.branches.b[EB_LEFT] = new_leaf; new->node.branches.b[EB_RGHT] = old_leaf; } else { + /* we may refuse to duplicate this key if the tree is + * tagged as containing only unique keys. + */ + if ((new->key == old->key) && eb_gettag(root_right)) + return old; + /* new->key >= old->key, new goes the right */ old->node.leaf_p = new_left; new->node.leaf_p = new_rght; @@ -369,7 +379,7 @@ __eb64_insert(struct eb_root *root, struct eb64_node *new) { /* Insert eb64_node into subtree starting at node root , using * signed keys. Only new->key needs be set with the key. The eb64_node - * is returned. + * is returned. If root->b[EB_RGHT]==1, the tree may only contain unique keys. */ static inline struct eb64_node * __eb64i_insert(struct eb_root *root, struct eb64_node *new) { @@ -377,9 +387,11 @@ __eb64i_insert(struct eb_root *root, struct eb64_node *new) { unsigned int side; eb_troot_t *troot; u64 newkey; /* caching the key saves approximately one cycle */ + eb_troot_t *root_right = root; side = EB_LEFT; troot = root->b[EB_LEFT]; + root_right = root->b[EB_RGHT]; if (unlikely(troot == NULL)) { /* Tree is empty, insert the leaf part below the left branch */ root->b[EB_LEFT] = eb_dotag(&new->node.branches, EB_LEAF); @@ -440,6 +452,12 @@ __eb64i_insert(struct eb_root *root, struct eb64_node *new) { new->node.branches.b[EB_LEFT] = new_leaf; new->node.branches.b[EB_RGHT] = old_leaf; } else { + /* we may refuse to duplicate this key if the tree is + * tagged as containing only unique keys. + */ + if ((new->key == old->key) && eb_gettag(root_right)) + return old; + /* new->key >= old->key, new goes the right */ old->node.leaf_p = new_left; new->node.leaf_p = new_rght; diff --git a/include/common/ebpttree.h b/include/common/ebpttree.h index be164ad4c8..a5ea0bd352 100644 --- a/include/common/ebpttree.h +++ b/include/common/ebpttree.h @@ -1,6 +1,7 @@ /* * Elastic Binary Trees - macros and structures for operations on pointer nodes. - * (C) 2002-2007 - Willy Tarreau + * Version 4.0 + * (C) 2002-2008 - Willy Tarreau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -160,6 +161,7 @@ static inline struct ebpt_node *__ebpt_lookup(struct eb_root *root, void *x) /* Insert ebpt_node into subtree starting at node root . * Only new->key needs be set with the key. The ebpt_node is returned. + * If root->b[EB_RGHT]==1, the tree may only contain unique keys. */ static inline struct ebpt_node * __ebpt_insert(struct eb_root *root, struct ebpt_node *new) { @@ -167,9 +169,11 @@ __ebpt_insert(struct eb_root *root, struct ebpt_node *new) { unsigned int side; eb_troot_t *troot; void *newkey; /* caching the key saves approximately one cycle */ + eb_troot_t *root_right = root; side = EB_LEFT; troot = root->b[EB_LEFT]; + root_right = root->b[EB_RGHT]; if (unlikely(troot == NULL)) { /* Tree is empty, insert the leaf part below the left branch */ root->b[EB_LEFT] = eb_dotag(&new->node.branches, EB_LEAF); @@ -228,6 +232,12 @@ __ebpt_insert(struct eb_root *root, struct ebpt_node *new) { new->node.branches.b[EB_LEFT] = new_leaf; new->node.branches.b[EB_RGHT] = old_leaf; } else { + /* we may refuse to duplicate this key if the tree is + * tagged as containing only unique keys. + */ + if ((new->key == old->key) && eb_gettag(root_right)) + return old; + /* new->key >= old->key, new goes the right */ old->node.leaf_p = new_left; new->node.leaf_p = new_rght; diff --git a/include/common/ebtree.h b/include/common/ebtree.h index 1a5ce86501..5ef965be79 100644 --- a/include/common/ebtree.h +++ b/include/common/ebtree.h @@ -1,5 +1,6 @@ /* * Elastic Binary Trees - generic macros and structures. + * Version 4.0 * (C) 2002-2008 - Willy Tarreau * * This program is free software; you can redistribute it and/or modify @@ -205,7 +206,8 @@ root, it is not possible to see a NULL left branch when walking up a tree. Thus, an empty tree is immediately identified by a NULL left branch at the root. Conversely, the one and only way to identify the - root node is to check that it right branch is NULL. + root node is to check that it right branch is NULL. Note that the + NULL pointer may have a few low-order bits set. - a node connected to its own leaf will have branch[0|1] pointing to itself, and leaf_p pointing to itself. @@ -244,6 +246,11 @@ higher to lower keys. It returns duplicates in the opposite order they were inserted. The "eb_last" primitive returns the right-most entry. + - a tree which has 1 in the lower bit of its root's right branch is a + tree with unique nodes. This means that when a node is inserted with + a key which already exists will not be inserted, and the previous + entry will be returned. + */ #ifndef _COMMON_EBTREE_H @@ -369,6 +376,13 @@ static inline int fls64(unsigned long long x) #define EB_LEAF 0 #define EB_NODE 1 +/* Tags to set in root->b[EB_RGHT] : + * - EB_NORMAL is a normal tree which stores duplicate keys. + * - EB_UNIQUE is a tree which stores unique keys. + */ +#define EB_NORMAL 0 +#define EB_UNIQUE 1 + /* This is the same as an eb_node pointer, except that the lower bit embeds * a tag. See eb_dotag()/eb_untag()/eb_gettag(). This tag has two meanings : * - 0=left, 1=right to designate the parent's branch for leaf_p/node_p @@ -378,7 +392,7 @@ typedef void eb_troot_t; /* The eb_root connects the node which contains it, to two nodes below it, one * of which may be the same node. At the top of the tree, we use an eb_root - * too, which always has its right branch NULL. + * too, which always has its right branch NULL (+/1 low-order bits). */ struct eb_root { eb_troot_t *b[EB_NODE_BRANCHES]; /* left and right branches */ @@ -408,6 +422,11 @@ struct eb_node { .b = {[0] = NULL, [1] = NULL }, \ } +#define EB_ROOT_UNIQUE \ + (struct eb_root) { \ + .b = {[0] = NULL, [1] = (void *)1 }, \ + } + #define EB_TREE_HEAD(name) \ struct eb_root name = EB_ROOT @@ -552,7 +571,7 @@ static inline struct eb_node *eb_prev(struct eb_node *node) /* Walking up from left branch. We must ensure that we never * walk beyond root. */ - if (unlikely((eb_untag(t, EB_LEFT))->b[EB_RGHT] == NULL)) + if (unlikely(eb_clrtag((eb_untag(t, EB_LEFT))->b[EB_RGHT]) == NULL)) return NULL; t = (eb_root_to_node(eb_untag(t, EB_LEFT)))->node_p; } @@ -572,6 +591,8 @@ static inline struct eb_node *eb_next(struct eb_node *node) /* Note that cannot be NULL at this stage */ t = (eb_untag(t, EB_LEFT))->b[EB_RGHT]; + if (eb_clrtag(t) == NULL) + return NULL; return eb_walk_down(t, EB_LEFT); } @@ -593,7 +614,7 @@ static inline struct eb_node *eb_prev_unique(struct eb_node *node) /* Walking up from left branch. We must ensure that we never * walk beyond root. */ - if (unlikely((eb_untag(t, EB_LEFT))->b[EB_RGHT] == NULL)) + if (unlikely(eb_clrtag((eb_untag(t, EB_LEFT))->b[EB_RGHT]) == NULL)) return NULL; t = (eb_root_to_node(eb_untag(t, EB_LEFT)))->node_p; } @@ -612,7 +633,7 @@ static inline struct eb_node *eb_next_unique(struct eb_node *node) while (1) { if (eb_gettag(t) == EB_LEFT) { - if (unlikely((eb_untag(t, EB_LEFT))->b[EB_RGHT] == NULL)) + if (unlikely(eb_clrtag((eb_untag(t, EB_LEFT))->b[EB_RGHT]) == NULL)) return NULL; /* we reached root */ node = eb_root_to_node(eb_untag(t, EB_LEFT)); /* if we're left and not in duplicates, stop here */ @@ -628,6 +649,8 @@ static inline struct eb_node *eb_next_unique(struct eb_node *node) /* Note that cannot be NULL at this stage */ t = (eb_untag(t, EB_LEFT))->b[EB_RGHT]; + if (eb_clrtag(t) == NULL) + return NULL; return eb_walk_down(t, EB_LEFT); } @@ -654,7 +677,7 @@ static inline void __eb_delete(struct eb_node *node) * only be attached to the root by its left branch. */ - if (parent->branches.b[EB_RGHT] == NULL) { + if (eb_clrtag(parent->branches.b[EB_RGHT]) == NULL) { /* we're just below the root, it's trivial. */ parent->branches.b[EB_LEFT] = NULL; goto delete_unlink;