From: Marko Kreen Date: Mon, 11 Jan 2010 05:47:58 +0000 (+0200) Subject: X-Git-Tag: pgbouncer_1_4_rc3~77 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3671655f66dd26284ed3a3c5e98a9cd7ff3fae86;p=pgbouncer --- diff --git a/Makefile b/Makefile index 2ff514a..07a2675 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ # sources SRCS = client.c loader.c objects.c pooler.c proto.c sbuf.c server.c util.c \ admin.c stats.c takeover.c md5.c janitor.c pktbuf.c system.c main.c \ - varcache.c aatree.c hash.c slab.c + varcache.c hash.c slab.c HDRS = client.h loader.h objects.h pooler.h proto.h sbuf.h server.h util.h \ admin.h stats.h takeover.h md5.h janitor.h pktbuf.h system.h bouncer.h \ - mbuf.h varcache.h aatree.h hash.h slab.h iobuf.h + mbuf.h varcache.h hash.h slab.h iobuf.h # data & dirs to include in tgz DOCS = doc/overview.txt doc/usage.txt doc/config.txt doc/todo.txt diff --git a/include/aatree.h b/include/aatree.h deleted file mode 100644 index c040554..0000000 --- a/include/aatree.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * PgBouncer - Lightweight connection pooler for PostgreSQL. - * - * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -typedef struct Node Node; -typedef struct Tree Tree; - -typedef int (*tree_cmp_f)(long, Node *node); -typedef void (*tree_walker_f)(Node *n, void *arg); - -/* - * Tree header, for storing helper functions. - */ -struct Tree { - Node *root; - int count; - tree_cmp_f node_cmp; - tree_walker_f release_cb; -}; - -/* - * Tree node. - */ -struct Node { - Node *left; /* smaller values */ - Node *right; /* larger values */ - int level; /* number of black nodes to leaf */ -}; - -/* - * walk order - */ -enum TreeWalkType { - WALK_IN_ORDER = 0, /* left->self->right */ - WALK_PRE_ORDER = 1, /* self->left->right */ - WALK_POST_ORDER = 2, /* left->right->self */ -}; - -void tree_init(Tree *tree, tree_cmp_f cmpfn, tree_walker_f release_cb); -Node *tree_search(Tree *tree, long value); -void tree_insert(Tree *tree, long value, Node *node); -void tree_remove(Tree *tree, long value); -void tree_walk(Tree *tree, enum TreeWalkType wtype, tree_walker_f walker, void *arg); -void tree_destroy(Tree *tree); - diff --git a/include/bouncer.h b/include/bouncer.h index 86686a9..f5becd4 100644 --- a/include/bouncer.h +++ b/include/bouncer.h @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -74,7 +75,6 @@ typedef struct PktHdr PktHdr; extern int cf_sbuf_len; -#include "aatree.h" #include "hash.h" #include "util.h" #include "mbuf.h" @@ -217,7 +217,7 @@ struct PgPool { struct PgUser { struct List head; /* used to attach user to list */ struct List pool_list; /* list of pools where pool->user == this user */ - Node tree_node; /* used to attach user to tree */ + struct AANode tree_node; /* used to attach user to tree */ char name[MAX_USERNAME]; char passwd[MAX_PASSWORD]; }; diff --git a/include/objects.h b/include/objects.h index e9d98a8..2d7ae80 100644 --- a/include/objects.h +++ b/include/objects.h @@ -17,7 +17,7 @@ */ extern struct StatList user_list; -extern Tree user_tree; +extern struct AATree user_tree; extern struct StatList pool_list; extern struct StatList database_list; extern struct StatList autodatabase_idle_list; diff --git a/src/aatree.c b/src/aatree.c deleted file mode 100644 index 051d38b..0000000 --- a/src/aatree.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * PgBouncer - Lightweight connection pooler for PostgreSQL. - * - * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * Self-balancing binary tree. - * - * Here is an implementation of AA-tree (Arne Andersson tree) - * which is simplification of Red-Black tree. - * - * Red-black tree has following properties that must be kept: - * 1. A node is either red or black. - * 2. The root is black. - * 3. All leaves (NIL nodes) are black. - * 4. Both childen of red node are black. - * 5. Every path from root to leaf contains same number of black nodes. - * - * AA-tree adds additional property: - * 6. Red node can exist only as a right node. - * - * Red-black tree properties quarantee that the longest path is max 2x longer - * than shortest path (B-R-B-R-B-R-B vs. B-B-B-B) thus the tree will be roughly - * balanced. Also it has good worst-case guarantees for insertion and deletion, - * which makes it good tool for real-time applications. - * - * AA-tree removes most special cases from RB-tree, thus making resulting - * code lot simpler. It requires slightly more rotations when inserting - * and deleting but also keeps the tree more balanced. - */ - -#include /* for NULL */ - -#include "aatree.h" - -/* - * NIL node - */ -#define NIL (&_nil) -static struct Node _nil = { &_nil, &_nil, 0 }; - -/* - * Rebalancing. AA-tree needs only 2 operations - * to keep the tree balanced. - */ - -/* - * Fix red on left. - * - * X Y - * / --> \ - * Y X - * \ / - * a a - */ -static inline Node * skew(Node *x) -{ - Node *y = x->left; - if (x->level == y->level && x != NIL) { - x->left = y->right; - y->right = x; - return y; - } - return x; -} - -/* - * Fix 2 reds on right. - * - * X Y - * \ / \ - * Y --> X Z - * / \ \ - * a Z a - */ -static inline Node * split(Node *x) -{ - Node *y = x->right; - if (x->level == y->right->level && x != NIL) { - x->right = y->left; - y->left = x; - y->level++; - return y; - } - return x; -} - -/* insert is easy */ -static Node *rebalance_on_insert(Node *current) -{ - return split(skew(current)); -} - -/* remove is bit more tricky */ -static Node *rebalance_on_remove(Node *current) -{ - /* - * Removal can create a gap in levels, - * fix it by lowering current->level. - */ - if (current->left->level < current->level - 1 - || current->right->level < current->level - 1) - { - current->level--; - - /* if ->right is red, change it's level too */ - if (current->right->level > current->level) - current->right->level = current->level; - - /* reshape, ask Arne about those */ - current = skew(current); - current->right = skew(current->right); - current->right->right = skew(current->right->right); - current = split(current); - current->right = split(current->right); - } - return current; -} - -/* - * Recursive insertion - */ - -static Node * insert_sub(Tree *tree, Node *current, long value, Node *node) -{ - int cmp; - - if (current == NIL) { - /* - * Init node as late as possible, to avoid corrupting - * the tree in case it is already added. - */ - node->left = node->right = NIL; - node->level = 1; - - tree->count++; - return node; - } - - /* recursive insert */ - cmp = tree->node_cmp(value, current); - if (cmp > 0) - current->right = insert_sub(tree, current->right, value, node); - else if (cmp < 0) - current->left = insert_sub(tree, current->left, value, node); - else - /* already exists? */ - return current; - - return rebalance_on_insert(current); -} - -void tree_insert(Tree *tree, long value, Node *node) -{ - tree->root = insert_sub(tree, tree->root, value, node); -} - -/* - * Recursive removal - */ - -/* remove_sub could be used for that, but want to avoid comparisions */ -static Node *steal_leftmost(Tree *tree, Node *current, Node **save_p) -{ - if (current->left == NIL) { - *save_p = current; - return current->right; - } - - current->left = steal_leftmost(tree, current->left, save_p); - return rebalance_on_remove(current); -} - -/* drop this node from tree */ -static Node *drop_this_node(Tree *tree, Node *old) -{ - Node *new = NIL; - - if (old->left == NIL) - new = old->right; - else if (old->right == NIL) - new = old->left; - else { - /* - * Picking nearest from right is better than from left, - * due to asymmetry of the AA-tree. It will result in - * less tree operations in the long run, - */ - old->right = steal_leftmost(tree, old->right, &new); - - /* take old node's place */ - *new = *old; - } - - /* cleanup for old node */ - tree->release_cb(old, tree); - tree->count--; - - return new; -} - -static Node *remove_sub(Tree *tree, Node *current, long value) -{ - int cmp; - - /* not found? */ - if (current == NIL) - return current; - - cmp = tree->node_cmp(value, current); - if (cmp > 0) - current->right = remove_sub(tree, current->right, value); - else if (cmp < 0) - current->left = remove_sub(tree, current->left, value); - else - current = drop_this_node(tree, current); - - return rebalance_on_remove(current); -} - -void tree_remove(Tree *tree, long value) -{ - tree->root = remove_sub(tree, tree->root, value); -} - -/* - * Walking all nodes - */ - -static void walk_sub(Node *current, enum TreeWalkType wtype, - tree_walker_f walker, void *arg) -{ - if (current == NIL) - return; - - switch (wtype) { - case WALK_IN_ORDER: - walk_sub(current->left, wtype, walker, arg); - walker(current, arg); - walk_sub(current->right, wtype, walker, arg); - break; - case WALK_POST_ORDER: - walk_sub(current->left, wtype, walker, arg); - walk_sub(current->right, wtype, walker, arg); - walker(current, arg); - break; - case WALK_PRE_ORDER: - walker(current, arg); - walk_sub(current->left, wtype, walker, arg); - walk_sub(current->right, wtype, walker, arg); - break; - } -} - -/* walk tree in correct order */ -void tree_walk(Tree *tree, enum TreeWalkType wtype, tree_walker_f walker, void *arg) -{ - walk_sub(tree->root, wtype, walker, arg); -} - -/* walk tree in bottom-up order, so that walker can destroy the nodes */ -void tree_destroy(Tree *tree) -{ - walk_sub(tree->root, WALK_POST_ORDER, tree->release_cb, tree); - - /* reset tree */ - tree->root = NIL; - tree->count = 0; -} - -/* prepare tree */ -void tree_init(Tree *tree, tree_cmp_f cmpfn, tree_walker_f release_cb) -{ - tree->root = NIL; - tree->count = 0; - tree->node_cmp = cmpfn; - tree->release_cb = release_cb; -} - -/* - * search function - */ -Node *tree_search(Tree *tree, long value) -{ - Node *current = tree->root; - while (current != NIL) { - int cmp = tree->node_cmp(value, current); - if (cmp > 0) - current = current->right; - else if (cmp < 0) - current = current->left; - else - return current; - } - return NULL; -} - diff --git a/src/objects.c b/src/objects.c index 41930ff..9eff2ed 100644 --- a/src/objects.c +++ b/src/objects.c @@ -27,7 +27,7 @@ STATLIST(user_list); STATLIST(database_list); STATLIST(pool_list); -Tree user_tree; +struct AATree user_tree; /* * client and server objects will be pre-allocated @@ -87,7 +87,7 @@ static void construct_server(void *obj) } /* compare string with PgUser->name, for usage with btree */ -static int user_node_cmp(long userptr, Node *node) +static int user_node_cmp(long userptr, struct AANode *node) { const char *name = (const char *)userptr; PgUser *user = container_of(node, PgUser, tree_node); @@ -97,7 +97,7 @@ static int user_node_cmp(long userptr, Node *node) /* initialization before config loading */ void init_objects(void) { - tree_init(&user_tree, user_node_cmp, NULL); + aatree_init(&user_tree, user_node_cmp, NULL); user_cache = objcache_create("user_cache", sizeof(PgUser), 0, NULL); db_cache = objcache_create("db_cache", sizeof(PgDatabase), 0, NULL); pool_cache = objcache_create("pool_cache", sizeof(PgPool), 0, NULL); @@ -354,7 +354,7 @@ PgUser *add_user(const char *name, const char *passwd) safe_strcpy(user->name, name, sizeof(user->name)); put_in_order(&user->head, &user_list, cmp_user); - tree_insert(&user_tree, (long)user->name, &user->tree_node); + aatree_insert(&user_tree, (long)user->name, &user->tree_node); } safe_strcpy(user->passwd, passwd, sizeof(user->passwd)); return user; @@ -404,9 +404,9 @@ PgDatabase *find_database(const char *name) PgUser *find_user(const char *name) { PgUser *user = NULL; - Node *node; + struct AANode *node; - node = tree_search(&user_tree, (long)name); + node = aatree_search(&user_tree, (long)name); user = node ? container_of(node, PgUser, tree_node) : NULL; return user; }