]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] upgrade to ebtree v4.0
authorWilly Tarreau <w@1wt.eu>
Fri, 16 May 2008 17:48:20 +0000 (19:48 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 16 May 2008 17:48:20 +0000 (19:48 +0200)
New ebtree also supports unique keys. This is useful for counters.

include/common/eb32tree.h
include/common/eb64tree.h
include/common/ebpttree.h
include/common/ebtree.h

index f0c79303574306bbec8534d6c92d80bf2507dddb..6a39595b5ce7d6463a94981f40dedd9e24bd9b7f 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Elastic Binary Trees - macros and structures for operations on 32bit nodes.
- * (C) 2002-2007 - Willy Tarreau <w@1wt.eu>
+ * Version 4.0
+ * (C) 2002-2008 - Willy Tarreau <w@1wt.eu>
  *
  * 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 <new> into subtree starting at node root <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 <new> into subtree starting at node root <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;
index 9a069ca53f54bddac34de3fa6d5b57c72ea7c36d..767ba834b9d469563ae3189b7097d5a66e3286a9 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Elastic Binary Trees - macros and structures for operations on 64bit nodes.
- * (C) 2002-2007 - Willy Tarreau <w@1wt.eu>
+ * Version 4.0
+ * (C) 2002-2008 - Willy Tarreau <w@1wt.eu>
  *
  * 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 <new> into subtree starting at node root <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 <new> into subtree starting at node root <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;
index be164ad4c8eec1fc22de650552e1d7383ad84929..a5ea0bd3520ae52ed3e4e800a49d3157dd89e914 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Elastic Binary Trees - macros and structures for operations on pointer nodes.
- * (C) 2002-2007 - Willy Tarreau <w@1wt.eu>
+ * Version 4.0
+ * (C) 2002-2008 - Willy Tarreau <w@1wt.eu>
  *
  * 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 <new> into subtree starting at node root <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;
index 1a5ce86501ca18fc3398fefa29dc120f343f3200..5ef965be7973ad0c4b6d272a89fbff7e3dcdadf7 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Elastic Binary Trees - generic macros and structures.
+ * Version 4.0
  * (C) 2002-2008 - Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or modify
        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.
        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 <t> 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 <t> 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;