]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MAJOR] replace ultree with ebtree in wait-queues
authorWilly Tarreau <w@1wt.eu>
Tue, 24 Jun 2008 06:17:16 +0000 (08:17 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 24 Jun 2008 06:17:16 +0000 (08:17 +0200)
The ultree code has been removed in favor of a simpler and
cleaner ebtree implementation. The eternity queue does not
need to exist anymore, and the pool_tree64 has been removed.

The ebtree node is stored in the task itself. The qlist list
header is still used by the run-queue, but will be able to
disappear once the run-queue uses ebtree too.

include/import/bitops.h [deleted file]
include/import/tree.h [deleted file]
include/proto/task.h
include/types/task.h
src/appsession.c
src/checks.c
src/client.c
src/haproxy.c
src/proto_uxst.c
src/task.c

diff --git a/include/import/bitops.h b/include/import/bitops.h
deleted file mode 100644 (file)
index 96f1f65..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * bitops.h : macros and functions for bit operations.
- * (C) 2002 - Willy Tarreau - willy@ant-computing.com
- *
- */
-
-#ifndef __BITOPS_H__
-#define __BITOPS_H__
-
-/* how many bits are needed to code the size of an int (eg: 32bits -> 5) */
-#define        LONGSHIFT       5
-#define LLONGSHIFT     6
-#define LONGBITS       32
-#define LLONGBITS      64
-
-/* very fast FFS function : returns the position of the lowest 1 */
-#define __ffs_fast32(___a) ({ \
-    register int ___x, ___bits = 32; \
-    if (___a) { \
-        ___x = (___a); \
-        ___bits--; \
-       if (___x & 0x0000ffff) { ___x &= 0x0000ffff; ___bits -= 16;} \
-       if (___x & 0x00ff00ff) { ___x &= 0x00ff00ff; ___bits -=  8;} \
-       if (___x & 0x0f0f0f0f) { ___x &= 0x0f0f0f0f; ___bits -=  4;} \
-       if (___x & 0x33333333) { ___x &= 0x33333333; ___bits -=  2;} \
-       if (___x & 0x55555555) { ___x &= 0x55555555; ___bits -=  1;} \
-    }\
-    ___bits; \
-    })
-
-/* very fast FLS function : returns the position of the highest 1  */
-#define __fls_fast32(___a) ({ \
-    register int ___x, ___bits = 0; \
-    if (___a) { \
-        ___x = (___a); \
-       if (___x & 0xffff0000) { ___x &= 0xffff0000; ___bits += 16;} \
-       if (___x & 0xff00ff00) { ___x &= 0xff00ff00; ___bits +=  8;} \
-       if (___x & 0xf0f0f0f0) { ___x &= 0xf0f0f0f0; ___bits +=  4;} \
-       if (___x & 0xcccccccc) { ___x &= 0xcccccccc; ___bits +=  2;} \
-       if (___x & 0xaaaaaaaa) { ___x &= 0xaaaaaaaa; ___bits +=  1;} \
-    } else { \
-       ___bits = 32; \
-    } \
-    ___bits; \
-    })
-
-/* very fast FFS function working on 64 bits */
-#define __ffs_fast64(___a) ({ \
-    register int ___bits = 64; \
-    register unsigned long  ___x = ((___a) >> 32); \
-    if ((___a) & 0xffffffffUL) { \
-        ___x = (___a) & 0xffffffffUL; \
-       ___bits -= 32; \
-    } \
-    if (___x) { \
-        ___bits--; \
-       if (___x & 0x0000ffff) { ___x &= 0x0000ffff; ___bits -= 16;} \
-       if (___x & 0x00ff00ff) { ___x &= 0x00ff00ff; ___bits -=  8;} \
-       if (___x & 0x0f0f0f0f) { ___x &= 0x0f0f0f0f; ___bits -=  4;} \
-       if (___x & 0x33333333) { ___x &= 0x33333333; ___bits -=  2;} \
-       if (___x & 0x55555555) { ___x &= 0x55555555; ___bits -=  1;} \
-    }\
-    ___bits; \
-    })
-
-
-/* very fast FLS function working on 64 bits */
-#define __fls_fast64(___a) ({ \
-    register int ___bits = 0; \
-    register unsigned long ___x = (___a); \
-    if (((unsigned long long)(___a)) >> 32) { \
-        ___x = ((unsigned long long)(___a)) >> 32; \
-       ___bits += 32; \
-    } \
-    if (___x) { \
-       if (___x & 0xffff0000) { ___x &= 0xffff0000; ___bits += 16;} \
-       if (___x & 0xff00ff00) { ___x &= 0xff00ff00; ___bits +=  8;} \
-       if (___x & 0xf0f0f0f0) { ___x &= 0xf0f0f0f0; ___bits +=  4;} \
-       if (___x & 0xcccccccc) { ___x &= 0xcccccccc; ___bits +=  2;} \
-       if (___x & 0xaaaaaaaa) { ___x &= 0xaaaaaaaa; ___bits +=  1;} \
-    } else { \
-        ___bits += 32; \
-    } \
-    ___bits; \
-    })
-
-static int ffs_fast32(register unsigned long a) {
-    return __ffs_fast32(a);
-}
-
-static int fls_fast32(unsigned long a) {
-    return __fls_fast32(a);
-}
-
-static int ffs_fast64(unsigned long long a) {
-    return __ffs_fast64(a);
-}
-
-static int fls_fast64(unsigned long long a) {
-    return __fls_fast64(a);
-}
-
-#endif /* __BITOPS_H__ */
diff --git a/include/import/tree.h b/include/import/tree.h
deleted file mode 100644 (file)
index 11ca6e0..0000000
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * tree.h : tree manipulation macros and structures.
- * (C) 2002 - Willy Tarreau - willy@ant-computing.com
- *
- * 2007/05/13: adapted to mempools v2.
- *
- */
-
-#ifndef __TREE_H__
-#define __TREE_H__
-
-#include <import/bitops.h>
-#include <common/memory.h>
-
-/* binary tree node : either 32 bits unsigned long int values, or
- * 64 bits in two 32 bits unsigned long int values
- */
-struct ultree {
-    unsigned long low;         /* 32 bits low value of this node */
-    unsigned long high;                /* 32 bits high value of this node, not used in 32 bits */
-    int level;                 /* bit level of this node */
-    void *data;                        /* carried data */
-    struct ultree *left, *right;       /* children : left and right. NULL = leaf */
-    struct ultree *up;         /* parent node. NULL = root */
-};
-
-/* binary tree node : 64 bits unsigned long long values */
-struct ulltree {
-    unsigned long long value;  /* 64 bits value of this node */
-    int level;                 /* bit level of this node */
-    void *data;                        /* carried data */
-    struct ulltree *left, *right;      /* children : left and right. NULL = leaf */
-    struct ulltree *up;                /* parent node. NULL = root */
-};
-
-/* binary tree node : 64 bits in either one ull or two 32 bits unsigned long int values. This
- * is the common type for all the above trees, which should be cast into it. This makes
- * pool_free() far simpler since all types share a same pool.
- */
-struct tree64 {
-    union {
-       struct {
-           unsigned long low;          /* 32 bits low value of this node */
-           unsigned long high;         /* 32 bits high value of this node */
-       } ul;
-       struct {
-           unsigned long long value;   /* 64 bits value of this node */
-       } ull;
-    } value;
-    int level;                         /* bit level of this node */
-    void *data;                                /* carried data */
-    struct tree64 *left, *right;       /* children : left and right. NULL = leaf */
-    struct tree64 *up;                 /* parent node. NULL = root */
-};
-
-extern struct pool_head *pool2_tree64;
-
-#define ULTREE_HEAD(l)         struct ultree (l) = { .left=NULL, .right=NULL, .up=NULL, .low=0, .level=LONGBITS, .data=NULL }
-#define ULTREE_INIT(l)         { (l)->data = (l)->left = (l)->right = NULL; }
-#define ULTREE_INIT_ROOT(l)    { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->low=0; (l)->level=LONGBITS; }
-
-#define ULLTREE_HEAD(l)                struct ulltree (l) = { .left=NULL, .right=NULL, .up=NULL, .value=0, .level=LLONGBITS, .data=NULL }
-#define ULLTREE_INIT(l)                { (l)->data = (l)->left = (l)->right = NULL; }
-#define ULLTREE_INIT_ROOT(l)   { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->value=0; (l)->level=LLONGBITS; }
-
-#define UL2TREE_HEAD(l)                struct ultree (l) = { .left=NULL, .right=NULL, .up=NULL, .high=0, .low=0, .level=LLONGBITS, .data=NULL }
-#define UL2TREE_INIT(l)                { (l)->left = (l)->right = (l)->data = NULL; }
-#define UL2TREE_INIT_ROOT(l)   { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->high=(l)->low=0; (l)->level=LLONGBITS; }
-
-/*
- * inserts necessary nodes to reach <x> in tree starting at <root>. The node
- * is not created if it exists. It is returned.
- */
-inline static struct ulltree *__ulltree_insert(struct ulltree *root, unsigned long long x) {
-    int m;
-    struct ulltree *next, *new, *node;
-    struct ulltree **branch;
-    int ffs;
-
-    next = root;
-    ffs = ffs_fast64(x);
-
-    do {
-       root = next;
-
-       if (x == next->value) {
-           return next;
-       }
-
-       if (x & (1ULL << (next->level - 1))) { /* right branch */
-           branch = &next->right;
-           next = *branch;
-       } else {
-           branch = &next->left;
-           next = *branch;
-       }
-
-       if (next == NULL) {
-           /* we'll have to insert our node here */
-           *branch = new = (struct ulltree *)pool_alloc2(pool2_tree64);
-           ULLTREE_INIT(new);
-           new->up = root;
-           new->value = x;
-           new->level = ffs;
-           return new;
-       }
-
-       /* we'll keep walking down as long as we have all bits in common */
-    } while ((x & ~((1ULL << next->level) - 1)) == next->value);
-
-
-    /* ok, now we know that we must insert between both. */
-
-    /* the new interconnect node */
-    *branch = node = (struct ulltree *)pool_alloc2(pool2_tree64); /* was <next> */
-    ULLTREE_INIT(node);
-    node->up = root;
-    next->up = node;
-
-    /* we need the common higher bits between x and next->value. */
-
-    /* what differences are there between x and the node here ?
-     * NOTE that m is always < level(parent) because highest bit
-     * of x and next-value are identical here (else they would be
-     * on a different branch).
-     */
-    m = fls_fast64(x ^ next->value) + 1; /* m = lowest identical bit */
-    node->value = x & ~((1ULL << m) - 1); /* value of common bits */
-
-    if (node->value == x) { /* <x> is exactly on this node */
-       /* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
-       node->level = ffs;
-
-       if (next->value & (1ULL << (node->level - 1))) /* right branch */
-           node->right = next;
-       else
-           node->left = next;
-       return node;
-    }
-
-    /* the new leaf now */
-    node->level = m; /* set the level to the lowest common bit */
-    new = (struct ulltree *)pool_alloc2(pool2_tree64);
-    ULLTREE_INIT(new);
-    new->value = x;
-    new->level = ffs;
-
-    if (x > next->value) {
-       node->left  = next;
-       node->right = new;
-    }
-    else {
-       node->left  = new;
-       node->right = next;
-    }
-    new->up = node;
-    return new;
-}
-
-/*
- * inserts necessary nodes to reach <x> in tree starting at <root>. The node
- * is not created if it exists. It is returned.
- */
-inline static struct ultree *__ultree_insert(struct ultree *root, unsigned long x) {
-    int m;
-    struct ultree *next, *new, *node;
-    struct ultree **branch;
-    int ffs;
-
-    next = root;
-    ffs = ffs_fast32(x);
-
-    do {
-       root = next;
-
-       if (x == next->low) {
-           return next;
-       }
-
-       if ((x >> (next->level - 1)) & 1) { /* right branch */
-           branch = &next->right;
-           next = *branch;
-       } else {
-           branch = &next->left;
-           next = *branch;
-       }
-
-       if (next == NULL) {
-           /* we'll have to insert our node here */
-           *branch = new = (struct ultree *)pool_alloc2(pool2_tree64);
-           ULTREE_INIT(new);
-           new->up = root;
-           new->low = x;
-           new->level = ffs;
-           return new;
-       }
-
-       /* we'll keep walking down as long as we have all bits in common */
-    } while ((x & ~((1 << next->level) - 1)) == next->low);
-
-    /* ok, now we know that we must insert between both. */
-
-    /* the new interconnect node */
-    *branch = node = (struct ultree *)pool_alloc2(pool2_tree64); /* was <next> */
-    ULTREE_INIT(node);
-    node->up = root;
-    next->up = node;
-
-    /* we need the common higher bits between x and next->low. */
-
-    /* what differences are there between x and the node here ?
-     * NOTE that m is always < level(parent) because highest bit
-     * of x and next->low are identical here (else they would be
-     * on a different branch).
-     */
-    m = fls_fast32(x ^ next->low) + 1; /* m = lower identical bit */
-    node->low = x & ~((1 << m) - 1); /* value of common bits */
-
-    if (node->low == x) { /* <x> is exactly on this node */
-       /* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
-       node->level = ffs;
-
-       if (next->low & (1 << (node->level - 1))) /* right branch */
-           node->right = next;
-       else
-           node->left = next;
-       return node;
-    }
-
-    /* the new leaf now */
-    node->level = m; /* set the level to the lowest common bit */
-    new = (struct ultree *)pool_alloc2(pool2_tree64);
-    ULTREE_INIT(new);
-    new->low = x;
-    new->level = ffs;
-
-    if (x > next->low) {
-       node->left  = next;
-       node->right = new;
-    }
-    else {
-       node->left  = new;
-       node->right = next;
-    }
-    new->up = node;
-    return new;
-}
-
-
-/*
- * inserts necessary nodes to reach <h:l> in tree starting at <root>. The node
- * is not created if it exists. It is returned.
- */
-inline static struct ultree *__ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l) {
-    int m;
-    struct ultree *next, *new, *node;
-    struct ultree **branch;
-
-    next = root;
-
-    do {
-       root = next;
-
-       if (h == next->high && l == next->low) {
-           return next;
-       }
-
-       branch = &next->left;
-       if (next->level >= 33) {
-           if ((h >> (next->level - 33)) & 1) { /* right branch */
-               branch = &next->right;
-           }
-       }
-       else {
-           if ((l >> (next->level - 1)) & 1) { /* right branch */
-               branch = &next->right;
-           }
-       }
-       next = *branch;
-
-       if (next == NULL) {
-           /* we'll have to insert our node here */
-           *branch = new =(struct ultree *)pool_alloc2(pool2_tree64);
-           UL2TREE_INIT(new);
-           new->up = root;
-           new->high = h;
-           new->low = l;
-           if (l)
-               new->level = __ffs_fast32(l);
-           else
-               new->level = __ffs_fast32(h) + 32;
-
-           return new;
-       }
-
-       /* we'll keep walking down as long as we have all bits in common */
-       if (next->level >= 32) {
-           if ((h & ~((1 << (next->level-32)) - 1)) != next->high)
-               break;
-       }
-       else {
-           if (h != next->high)
-               break;
-           if ((l & ~((1 << next->level) - 1)) != next->low)
-               break;
-       }
-    } while (1);
-
-    /* ok, now we know that we must insert between both. */
-
-    /* the new interconnect node */
-    *branch = node = (struct ultree *)pool_alloc2(pool2_tree64); /* was <next> */
-    UL2TREE_INIT(node);
-    node->up = root;
-    next->up = node;
-
-    /* we need the common higher bits between x and next->high:low. */
-
-    /* what differences are there between x and the node here ?
-     * NOTE that m is always < level(parent) because highest bit
-     * of x and next->high:low are identical here (else they would be
-     * on a different branch).
-     */
-    if (h != next->high) {
-       m = fls_fast32(h ^ next->high) + 1; /* m = lower identical bit */
-       node->high = h & ~((1 << m) - 1); /* value of common bits */
-       m += 32;
-       node->low = 0;
-    } else {
-       node->high = h;
-       m = fls_fast32(l ^ next->low) + 1;   /* m = lower identical bit */
-       node->low = l & ~((1 << m) - 1); /* value of common bits */
-    }
-
-    if (node->high == h && node->low == l) { /* <h:l> is exactly on this node */
-       /* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
-       if (l) {
-           node->level = ffs_fast32(l);
-           if (next->low & (1 << (node->level - 1))) /* right branch */
-               node->right = next;
-           else
-               node->left = next;
-       }
-       else {
-           node->level = ffs_fast32(h) + 32;
-           if (next->high & (1 << (node->level - 33))) /* right branch */
-               node->right = next;
-           else
-               node->left = next;
-       }
-       return node;
-    }
-
-    /* the new leaf now */
-    node->level = m; /* set the level to the lowest common bit */
-    new = (struct ultree *)pool_alloc2(pool2_tree64);
-    UL2TREE_INIT(new);
-    new->high = h;
-    new->low = l;
-    if (l)
-       new->level = __ffs_fast32(l);
-    else
-       new->level = __ffs_fast32(h) + 32;
-
-    if (h > next->high || (h == next->high && l > next->low)) {
-       node->left  = next;
-       node->right = new;
-    }
-    else {
-       node->left  = new;
-       node->right = next;
-    }
-    new->up = node;
-    return new;
-}
-
-
-/*
- * finds a value in the tree <root>. If it cannot be found, NULL is returned.
- */
-inline static struct ultree *__ultree_find(struct ultree *root, unsigned long x) {
-    do {
-       if (x == root->low)
-           return root;
-
-       if ((x >> (root->level - 1)) & 1)
-           root = root->right;
-       else
-           root = root->left;
-
-       if (root == NULL)
-           return NULL;
-
-       /* we'll keep walking down as long as we have all bits in common */
-    } while ((x & ~((1 << root->level) - 1)) == root->low);
-
-    /* should be there, but nothing. */
-    return NULL;
-}
-
-/*
- * finds a value in the tree <root>. If it cannot be found, NULL is returned.
- */
-inline static struct ulltree *__ulltree_find(struct ulltree *root, unsigned long long x) {
-    do {
-       if (x == root->value)
-           return root;
-
-       if ((x >> (root->level - 1)) & 1)
-           root = root->right;
-       else
-           root = root->left;
-
-       if (root == NULL)
-           return NULL;
-
-       /* we'll keep walking down as long as we have all bits in common */
-    } while ((x & ~((1ULL << root->level) - 1)) == root->value);
-
-    /* should be there, but nothing. */
-    return NULL;
-}
-
-
-/*
- * walks down the tree <__root> and assigns each of its data to <__data>.
- * <__stack> is an int array of at least N entries where N is the maximum number
- * of levels of the tree. <__slen> is an integer variable used as a stack index.
- * The instruction following the foreach statement is executed for each data,
- * after the data has been unlinked from the tree.
- * The nodes are deleted automatically, so it is illegal to manually delete a
- * node within this loop.
- */
-#define tree64_foreach_destructive(__root, __data, __stack, __slen)    \
-    for (__slen = 0, __stack[0] = __root, __data = NULL; ({            \
-        __label__ __left, __right, __again, __end;                     \
-       typeof(__root) __ptr = __stack[__slen];                         \
-__again:                                                               \
-       __data = __ptr->data;                                           \
-       if (__data != NULL) {                                           \
-           __ptr->data = NULL;                                         \
-           goto __end;                                                 \
-       }                                                               \
-       else if (__ptr->left != NULL) {                                 \
-           __stack[++__slen] = __ptr = __ptr->left;                    \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__left:                                                                        \
-       if (__ptr->right != NULL) {                                     \
-           __stack[++__slen] = __ptr = __ptr->right;                   \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__right:                                                               \
-       if (!__slen--)                                                  \
-           goto __end; /* nothing left, don't delete the root node */  \
-       else {                                                          \
-           typeof (__root) __old;                                      \
-           pool_free2(pool2_tree64, __ptr);                            \
-           __old = __ptr;                                              \
-           __ptr = __stack[__slen];                                    \
-           if (__ptr->left == __old) {                                 \
-               /* unlink this node from its parent */                  \
-               __ptr->left = NULL;                                     \
-               goto __left;                                            \
-           }                                                           \
-           else {                                                      \
-               /* no need to unlink, the parent will also die */       \
-               goto __right;                                           \
-           }                                                           \
-       }                                                               \
-__end:                                                                 \
-        (__slen >= 0); /* nothing after loop */}); )
-
-
-/*
- * walks down the tree <__root> of type <__type> and assigns each of its data
- * to <__data>. <__stack> is an int array of at least N entries where N is the
- * maximum number of levels of the tree. <__slen> is an integer variable used
- * as a stack index. The instruction following the foreach statement is
- * executed for each data, after the data has been unlinked from the tree.
- */
-#define tree_foreach_destructive(__type, __root, __data, __stack, __slen)              \
-    for (__slen = 0, __stack[0] = __root, __data = NULL; ({            \
-        __label__ __left, __right, __again, __end;                     \
-       typeof(__root) __ptr = __stack[__slen];                         \
-__again:                                                               \
-       __data = __ptr->data;                                           \
-       if (__data != NULL) {                                           \
-           __ptr->data = NULL;                                         \
-           goto __end;                                                 \
-       }                                                               \
-       else if (__ptr->left != NULL) {                                 \
-           __stack[++__slen] = __ptr = __ptr->left;                    \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__left:                                                                        \
-       if (__ptr->right != NULL) {                                     \
-           __stack[++__slen] = __ptr = __ptr->right;                   \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__right:                                                               \
-       if (!__slen--)                                                  \
-           goto __end; /* nothing left, don't delete the root node */  \
-       else {                                                          \
-           typeof (__root) __old;                                      \
-           pool_free2(pool##__type, __ptr);                            \
-           __old = __ptr;                                              \
-           __ptr = __stack[__slen];                                    \
-           if (__ptr->left == __old) {                                 \
-               /* unlink this node from its parent */                  \
-               __ptr->left = NULL;                                     \
-               goto __left;                                            \
-           }                                                           \
-           else {                                                      \
-               /* no need to unlink, the parent will also die */       \
-               goto __right;                                           \
-           }                                                           \
-       }                                                               \
-__end:                                                                 \
-        (__slen >= 0); /* nothing after loop */}); )
-
-
-/*
- * walks down the tree <__root> and assigns <__data> a pointer to each of its
- * data pointers. <__stack> is an int array of at least N entries where N is the
- * maximum number of levels of the tree. <__slen> is an integer variable used as
- * a stack index. The instruction following the foreach statement is executed
- * for each data.
- * The tree will walk down only when the data field is empty (NULL), so it
- * allows inner breaks, and will restart without losing items. The nodes data
- * will be set to NULL after the inner code, or when the inner code does
- * '__stack[__slen]->data = NULL';
- * The nodes are deleted automatically, so it is illegal to manually delete a
- * node within this loop.
- */
-#define tree64_foreach(__root, __data, __stack, __slen)                        \
-    for (__slen = 0, __stack[0] = __root, __data = NULL; ({            \
-        __label__ __left, __right, __again, __end;                     \
-       typeof(__root) __ptr = __stack[__slen];                         \
-__again:                                                               \
-       if (__ptr->data != NULL) {                                      \
-           __data = __ptr->data;                                       \
-           goto __end;                                                 \
-       }                                                               \
-       else if (__ptr->left != NULL) {                                 \
-           __stack[++__slen] = __ptr = __ptr->left;                    \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__left:                                                                        \
-       if (__ptr->right != NULL) {                                     \
-           __stack[++__slen] = __ptr = __ptr->right;                   \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__right:                                                               \
-       if (!__slen--)                                                  \
-           goto __end; /* nothing left, don't delete the root node */  \
-       else {                                                          \
-           typeof (__root) __old;                                      \
-           pool_free2(pool2_tree64, __ptr);                            \
-           __old = __ptr;                                              \
-           __ptr = __stack[__slen];                                    \
-           if (__ptr->left == __old) {                                 \
-               /* unlink this node from its parent */                  \
-               __ptr->left = NULL;                                     \
-               goto __left;                                            \
-           }                                                           \
-           else {                                                      \
-               /* no need to unlink, the parent will also die */       \
-               goto __right;                                           \
-           }                                                           \
-       }                                                               \
-__end:                                                                 \
-        (__slen >= 0); }); ((typeof(__root))__stack[__slen])->data = NULL)
-
-
-
-/*
- * walks down the tree <__root> and assigns <__node> to each of its nodes.
- * <__stack> is an int array of at least N entries where N is the
- * maximum number of levels of the tree. <__slen> is an integer variable used as
- * a stack index. The instruction following the foreach statement is executed
- * for each node.
- * The tree will walk down only when the data field is empty (NULL), so it
- * allows inner breaks, and will restart without losing items. The nodes data
- * will be set to NULL after the inner code, or when the inner code does
- * '__node->data = NULL';
- * The nodes are deleted automatically, so it is illegal to manually delete a
- * node within this loop.
- */
-#define tree64_foreach_node(__root, __node, __stack, __slen)           \
-    for (__slen = 0, __stack[0] = __root; ({                           \
-        __label__ __left, __right, __again, __end;                     \
-       typeof(__root) __ptr = __stack[__slen];                         \
-__again:                                                               \
-       if (__ptr->data != NULL) {                                      \
-           __node = __ptr;                                             \
-           goto __end;                                                 \
-       }                                                               \
-       else if (__ptr->left != NULL) {                                 \
-           __stack[++__slen] = __ptr = __ptr->left;                    \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__left:                                                                        \
-       if (__ptr->right != NULL) {                                     \
-           __stack[++__slen] = __ptr = __ptr->right;                   \
-           goto __again;                                               \
-       }                                                               \
-       else                                                            \
-__right:                                                               \
-       if (!__slen--)                                                  \
-           goto __end; /* nothing left, don't delete the root node */  \
-       else {                                                          \
-           typeof (__root) __old;                                      \
-           pool_free2(pool2_tree64, __ptr);                            \
-           __old = __ptr;                                              \
-           __ptr = __stack[__slen];                                    \
-           if (__ptr->left == __old) {                                 \
-               /* unlink this node from its parent */                  \
-               __ptr->left = NULL;                                     \
-               goto __left;                                            \
-           }                                                           \
-           else {                                                      \
-               /* no need to unlink, the parent will also die */       \
-               goto __right;                                           \
-           }                                                           \
-       }                                                               \
-__end:                                                                 \
-        (__slen >= 0); }); ((typeof(__root))__stack[__slen])->data = NULL)
-
-
-/*
- * removes the current node if possible, and its parent if it doesn't handle
- * data. A pointer to the parent or grandparent is returned (the parent of the
- * last one deleted in fact). This function should be compatible with any
- * tree struct because of the void types.
- * WARNING : never call it from within a tree_foreach() because this last one
- * uses a stack which will not be updated.
- */
-
-inline static void *__tree_delete_only_one(void *firstnode) {
-    struct tree64 *down, **uplink;
-    struct tree64 *node = firstnode;
-
-    /* don't kill the root or a populated link */
-    if (node->data || node->up == NULL)
-       return node;
-    if (node->left && node->right)
-       return node;
-    /* since we know that at least left or right is null, we can do arithmetics on them */
-    down = (void *)((long)node->left | (long)node->right);
-    /* find where we are linked */
-    if (node == node->up->left)
-       uplink = &node->up->left;
-    else
-       uplink = &node->up->right;
-
-    *uplink = down; /* we relink the lower branch above us or simply cut it */
-    if (down) {
-       down->up = node->up;
-       /* we know that we cannot do more because we kept one branch */
-    }
-    else {
-       /* we'll redo this once for the node above us because there was no branch below us,
-        * so maybe it doesn't need to exist for only one branch
-        */
-       down = node;
-       node = node->up;
-       pool_free2(pool2_tree64, down);
-       if (node->data || node->up == NULL)
-           return node;
-       /* now we're sure we were sharing this empty node with another branch, let's find it */
-       down = (void *)((long)node->left | (long)node->right);
-       if (node == node->up->left)
-           uplink = &node->up->left;
-       else
-           uplink = &node->up->right;
-       *uplink = down; /* we relink the lower branch above */
-       down->up = node->up;
-    }
-    /* free the last node */
-    pool_free2(pool2_tree64, node);
-    return down->up;
-}
-
-/*
- * removes the current node if possible, and all of its parents which do not
- * carry data. A pointer to the parent of the last one deleted is returned.
- * This function should be compatible with any tree struct because of the void
- * types.
- * WARNING : never call it from within a tree_foreach() because this last one
- * uses a stack which will not be updated.
- */
-
-inline static void *__tree_delete(void *firstnode) {
-    struct tree64 *down, **uplink, *up;
-    struct tree64 *node = firstnode;
-
-    while (1) {
-       /* don't kill the root or a populated link */
-       if (node->data || (up = node->up) == NULL)
-           return node;
-       if (node->left && node->right)
-           return node;
-       /* since we know that at least left or right is null, we can do arithmetics on them */
-       down = (void *)((long)node->left | (long)node->right);
-       /* find where we are linked */
-       if (node == up->left)
-           uplink = &up->left;
-       else
-           uplink = &up->right;
-
-       *uplink = down; /* we relink the lower branch above us or simply cut it */
-       pool_free2(pool2_tree64, node);
-       node = up;
-       if (down)
-           down->up = node;
-    }
-}
-
-#endif /* __TREE_H__ */
index 49e3a94b6b35121fa78938f62dbf81c20f4e66fe..d27e1db54ea4c9c299e523e078028dc31c87d06c 100644 (file)
@@ -2,7 +2,7 @@
   include/proto/task.h
   Functions for task management.
 
-  Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
 extern void *run_queue;
 extern struct pool_head *pool2_task;
 
-/* perform minimal intializations, report 0 in case of error, 1 if OK. */
+/* perform minimal initializations, report 0 in case of error, 1 if OK. */
 int init_task();
 
-/* needed later */
-void *tree_delete(void *node);
-
 /* puts the task <t> in run queue <q>, and returns <t> */
 #define task_wakeup _task_wakeup
 struct task *_task_wakeup(struct task *t);
@@ -49,17 +46,12 @@ static inline struct task *__task_wakeup(struct task *t)
        if (t->state == TASK_RUNNING)
                return t;
 
-       if (t->qlist.p != NULL)
-               DLIST_DEL(&t->qlist);
+       if (likely(t->eb.node.leaf_p))
+               eb32_delete(&t->eb);
 
        DLIST_ADD(run_queue, &t->qlist);
        t->state = TASK_RUNNING;
 
-       if (likely(t->wq != NULL)) {
-               tree_delete(t->wq);
-               t->wq = NULL;
-       }
-
        return t;
 }
 
@@ -79,7 +71,7 @@ static inline struct task *task_sleep(struct task *t)
 /*
  * unlinks the task from wherever it is queued :
  *  - eternity_queue, run_queue
- *  - wait queue : wq not null => remove carrier node too
+ *  - wait queue
  * A pointer to the task itself is returned.
  */
 static inline struct task *task_delete(struct task *t)
@@ -89,10 +81,21 @@ static inline struct task *task_delete(struct task *t)
                t->qlist.p = NULL;
        }
 
-       if (t->wq) {
-               tree_delete(t->wq);
-               t->wq = NULL;
-       }
+       if (t->eb.node.leaf_p)
+               eb32_delete(&t->eb);
+
+       return t;
+}
+
+/*
+ * Initialize a new task. The bare minimum is performed (queue pointers and state).
+ * The task is returned.
+ */
+static inline struct task *task_init(struct task *t)
+{
+       t->qlist.p = NULL;
+       t->eb.node.leaf_p = NULL;
+       t->state = TASK_IDLE;
        return t;
 }
 
index e0bbd6dac80e99e3f0860a4d1ccd0958a2c0e493..6b56547644364b256b3cc7132db9ac48cb2dd96d 100644 (file)
@@ -2,7 +2,7 @@
   include/types/task.h
   Macros, variables and structures for task management.
 
-  Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -25,8 +25,8 @@
 #include <sys/time.h>
 
 #include <common/config.h>
+#include <common/eb32tree.h>
 #include <common/mini-clist.h>
-#include <import/tree.h>
 
 /* values for task->state */
 #define TASK_IDLE      0
@@ -35,7 +35,7 @@
 /* The base for all tasks */
 struct task {
        struct list qlist;              /* chaining in the same queue; bidirectionnal but not circular */
-       struct ultree *wq;              /* NULL if unqueued, or back ref to the carrier node in the WQ */
+       struct eb32_node eb;            /* ebtree node used to hold the task in the wait queue */
        int state;                      /* task state : IDLE or RUNNING */
        struct timeval expire;          /* next expiration time for this task, use only for fast sorting */
        void (*process)(struct task *t, struct timeval *next);  /* the function which processes the task */
index e1a01cc49a8ba8503e4b8dc05b2e47ad78adac3f..fcd4e02543e902c303152a272b0e2aae711be714 100644 (file)
@@ -91,9 +91,7 @@ int appsession_task_init(void)
                if ((appsess_refresh = pool_alloc2(pool2_task)) == NULL)
                        return -1;
 
-               appsess_refresh->wq = NULL;
-               appsess_refresh->qlist.p = NULL;
-               appsess_refresh->state = TASK_IDLE;
+               task_init(appsess_refresh);
                appsess_refresh->context = NULL;
                tv_ms_add(&appsess_refresh->expire, &now, TBLCHKINT);
                appsess_refresh->process = appsession_refresh;
index eff0df00aa4c3989c80ceaa02f8c3b554d559dc0..91db0268c82104f352ce57bb2ac8b8bc5d1e61a5 100644 (file)
@@ -850,9 +850,7 @@ int start_checks() {
 
                        s->check = t;
 
-                       t->wq = NULL;
-                       t->qlist.p = NULL;
-                       t->state = TASK_IDLE;
+                       task_init(t);
                        t->process = process_chk;
                        t->context = s;
 
index 06a8ce155ae0bd9e427caa78b04f2295fc1ca361..96c3a0ad572f1720fba5f0f47b953f47d823c242 100644 (file)
@@ -155,9 +155,7 @@ int event_accept(int fd) {
                if (p->options & PR_O_TCP_NOLING)
                        setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
 
-               t->wq = NULL;
-               t->qlist.p = NULL;
-               t->state = TASK_IDLE;
+               task_init(t);
                t->process = process_session;
                t->context = s;
 
@@ -410,8 +408,6 @@ int event_accept(int fd) {
                        tv_bound(&t->expire, &s->txn.exp);
                }
 
-               task_queue(t);
-
                if (p->mode != PR_MODE_HEALTH)
                        task_wakeup(t);
 
index 45e48522de3dd210b31b636b8ef09df07f915d25..330ef2a4d8be14831aae924f399d6fa04f286fa8 100644 (file)
@@ -864,7 +864,6 @@ void deinit(void)
        pool_destroy2(pool2_buffer);
        pool_destroy2(pool2_requri);
        pool_destroy2(pool2_task);
-       pool_destroy2(pool2_tree64);
        pool_destroy2(pool2_capture);
        pool_destroy2(pool2_appsess);
        pool_destroy2(pool2_pendconn);
index b708689c11e133372f9f77f727602e0839c95473..c4c3d379045932acb8ff9986b5b4d6cc41b890bb 100644 (file)
@@ -444,9 +444,7 @@ int uxst_event_accept(int fd) {
                        return 0;
                }
 
-               t->wq = NULL;
-               t->qlist.p = NULL;
-               t->state = TASK_IDLE;
+               task_init(t);
                t->process = l->handler;
                t->context = s;
 
@@ -527,7 +525,6 @@ int uxst_event_accept(int fd) {
                        t->expire = s->req->rex;
                }
 
-               task_queue(t);
                task_wakeup(t);
 
                l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
index c60961f3ac26fb28d1315d6720d86f121cfa239b..16eea645be9e3f8ac0a265cddecaaa9939760848 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Task management functions.
  *
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-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
@@ -11,6 +11,7 @@
  */
 
 #include <common/config.h>
+#include <common/eb32tree.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
 #include <proto/task.h>
 #include <types/task.h>
 
-// FIXME: check 8bitops.c for faster FLS
-#include <import/bitops.h>
-#include <import/tree.h>
+struct pool_head *pool2_task;
 
-static struct ultree *stack[LLONGBITS];
+void *run_queue = NULL;
 
-struct pool_head *pool2_task, *pool2_tree64;
+/* Principle of the wait queue : we have two trees ordered by time. On of them
+ * contains all timers for current time-frame, and the other one for next
+ * time-frame. Each time-frame is TIMER_KEY_BITS bits wide in number of
+ * milliseconds, which is 49 days for 32 bits. Values are stored into and
+ * retrieved from the tree using a key of TIMER_KEY_BITS bits. A pointer
+ * always designates the current tree, which is the one we read from, until
+ * it is exhausted and <now> has its high bit designate the new tree.
+ * An improvement would consist in holding too large timers in a side tree
+ * consulted only once a switch. It could also be a simple list BTW.
+ */
+#define TIMER_KEY_BITS        32
+#define TIMER_SUBSEC_BITS     10
+#define TIMER_SECOND_BITS     (TIMER_KEY_BITS - TIMER_SUBSEC_BITS)
+
+static struct {
+       struct eb_root *curr; /* current time frame (t[0],t[1]) */
+       struct eb_root t[2];  /* trees with MSB 0 and 1 */
+       struct timeval first; /* first value in the tree when known */
+} timers;
+
+/* returns an ordered key based on an expiration date. */
+static inline unsigned int timeval_to_key(const struct timeval *t)
+{
+       unsigned int key;
 
-UL2TREE_HEAD(timer_wq);
-void *eternity_queue = NULL;
-void *run_queue = NULL;
+       /* We choose sec << 10 + usec / 1000 below to keep the precision at the
+        * millisecond, but we might as well divide by 1024 and have a slightly
+        * lower precision of 1.024 ms.
+        */
+
+       key   = ((unsigned int)t->tv_sec << TIMER_SUBSEC_BITS) +
+               ((unsigned int)t->tv_usec / 1000);
+
+#if TIMER_KEY_BITS != 32
+       key  &= (1 << TIMER_KEY_BITS) - 1;
+#endif
+       return key;
+}       
+
+/* returns a tree number based on an expiration date. */
+static inline unsigned int timeval_to_tree(const struct timeval *t)
+{
+       return (t->tv_sec >> TIMER_SECOND_BITS) & 1;
+}       
 
 /* perform minimal intializations, report 0 in case of error, 1 if OK. */
 int init_task()
 {
-       pool2_task = create_pool("task", sizeof(struct task), MEM_F_SHARED);
-       pool2_tree64 = create_pool("tree64", sizeof(struct tree64), MEM_F_SHARED);
-       return pool2_task && pool2_tree64;
-}
+       memset(&timers, 0, sizeof(timers));
 
-struct ultree *ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l)
-{
-       return __ul2tree_insert(root, h, l);
-}
+       /* note: we never queue in the past, so we start with <now> */
+       timers.curr = &timers.t[timeval_to_tree(&now)];
 
-void *tree_delete(void *node) {
-    return __tree_delete(node);
+       pool2_task = create_pool("task", sizeof(struct task), MEM_F_SHARED);
+       return pool2_task != NULL;
 }
 
 struct task *_task_wakeup(struct task *t)
@@ -58,84 +91,100 @@ struct task *_task_wakeup(struct task *t)
  * task_queue()
  *
  * Inserts a task into the wait queue at the position given by its expiration
- * date.
- *
+ * date. Note that the task must *not* already be in the wait queue nor in the
+ * run queue, otherwise unpredictable results may happen. Tasks queued with an
+ * eternity expiration date are simply returned. Last, tasks must not be queued
+ * further than the end of the next tree, which is between now and
+ * now+1<<TIMER_KEY_BITS ms (now+49days in 32bit).
  */
 struct task *task_queue(struct task *task)
 {
-       if (unlikely(task->qlist.p != NULL)) {
-               DLIST_DEL(&task->qlist);
-               task->qlist.p = NULL;
-       }
-
-       if (unlikely(task->wq != NULL)) {
-               tree_delete(task->wq);
-               task->wq = NULL;
-       }
+       struct eb_root *tmp;
+       unsigned int key;
 
-       if (unlikely(tv_iseternity(&task->expire))) {
-               task->wq = NULL;
-               DLIST_ADD(eternity_queue, &task->qlist);
+       if (unlikely(tv_iseternity(&task->expire)))
                return task;
-       }
 
-       task->wq = ul2tree_insert(&timer_wq, task->expire.tv_sec, task->expire.tv_usec);
-       DLIST_ADD(task->wq->data, &task->qlist);
+       if (tv_islt(&task->expire, &timers.first))
+               timers.first = task->expire;
+
+       key = timeval_to_key(&task->expire);
+       tmp = &timers.t[timeval_to_tree(&task->expire)];
+       eb32_insert(tmp, &task->eb);
        return task;
 }
 
 
 /*
- * Extract all expired timers from the wait queue, and wakes up all
+ * Extract all expired timers from the timer queue, and wakes up all
  * associated tasks. Returns the date of next event (or eternity).
  *
  */
 void wake_expired_tasks(struct timeval *next)
 {
-       int slen;
        struct task *task;
-       void *data;
-
-#ifdef WAKE_HINT_CHECK_FIRST
-       /*
-        * Hint: tasks are *rarely* expired. So we can try to optimize
-        * by not scanning the tree at all in most cases. However, this
-        * code costs 160 more bytes which do not look much useful because
-        * the performance win is not obvious.
-        */
+       struct eb32_node *eb;
+       unsigned int now_key;
+       unsigned int now_tree;
 
-       if (likely(timer_wq.data != NULL)) {
-               task = LIST_ELEM(timer_wq.data, struct task *, qlist);
-               if (likely(tv_isgt(&task->expire, &now))) {
-                       *next = task->expire;
-                       return;
-               }
-       }
-       /* OK we lose. Let's scan the tree then. */
-#endif
 
-       tree64_foreach(&timer_wq, data, stack, slen) {
-               task = LIST_ELEM(data, struct task *, qlist);
+       now_tree = timeval_to_tree(&now);
 
-               if (tv_isgt(&task->expire, &now)) {
-                       *next = task->expire;
-                       return;
-               }
+       /* This is a speedup: we immediately check for an expirable task in the
+        * timer's index. Warning: if nothing is found, we still may have to
+        * switch the trees.
+        */
+       if (likely(tv_isgt(&timers.first, &now))) {
+               *next = timers.first;
+               if (timers.curr != &timers.t[now_tree])
+                       timers.curr = &timers.t[now_tree];
+               return;
+       }
 
-               /*
-                * OK, all tasks linked to this node will be unlinked, as well
-                * as the node itself, so we do not need to care about correct
-                * unlinking.
-                */
-               foreach_dlist_item(task, data, struct task *, qlist) {
-                       DLIST_DEL(&task->qlist);
-                       task->wq = NULL;
+       now_key = timeval_to_key(&now);
+       do {
+               eb = eb32_first(timers.curr);
+               while (eb) {
+                       struct eb32_node *next_eb;
+
+                       task = eb32_entry(eb, struct task, eb);
+                       if (eb->key > now_key) {
+                               *next = task->expire;
+                               timers.first = task->expire;
+                               return;
+                       }
+
+                       /* detach the task from the queue */
+                       next_eb = eb32_next(eb);
+                       eb32_delete(eb);
+                       eb = next_eb;
+
+                       /* and add the task to the run queue */
                        DLIST_ADD(run_queue, &task->qlist);
                        task->state = TASK_RUNNING;
                }
-       }
-       tv_eternity(next);
-       return;
+
+               /* OK we have reached the end of the <curr> tree. It might mean
+                * that we must now switch, which is indicated by the fact that
+                * the current tree pointer does not match <now> anymore.
+                */
+               if (timers.curr == &timers.t[now_tree]) {
+                       /* We cannot switch now, so we have to find the first
+                        * timer of the next tree.
+                        */
+                       eb = eb32_first(&timers.t[now_tree ^ 1]);
+                       if (eb) {
+                               task = eb32_entry(eb, struct task, eb);
+                               *next = task->expire;
+                               timers.first = task->expire;
+                       } else {
+                               tv_eternity(next);
+                               tv_eternity(&timers.first);
+                       }
+                       return;
+               }
+               timers.curr = &timers.t[now_tree];
+       } while (1);
 }
 
 /*