+++ /dev/null
-/*
- * 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);
-
+++ /dev/null
-/*
- * 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 <stddef.h> /* 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;
-}
-
STATLIST(database_list);
STATLIST(pool_list);
-Tree user_tree;
+struct AATree user_tree;
/*
* client and server objects will be pre-allocated
}
/* 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);
/* 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);
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;
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;
}