[asterisk-commits] akshayb: branch akshayb/ao2_containers r266520 - /team/akshayb/ao2_containers...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun May 30 10:56:07 CDT 2010


Author: akshayb
Date: Sun May 30 10:56:04 2010
New Revision: 266520

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=266520
Log:
Adding the variable file for ao2_container in btree data structure

Added:
    team/akshayb/ao2_containers/main/astobj2_btree.c   (with props)
    team/akshayb/ao2_containers/main/btree.c   (with props)
Modified:
    team/akshayb/ao2_containers/main/astobj2.c
    team/akshayb/ao2_containers/main/astobj2_hash.c

Modified: team/akshayb/ao2_containers/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2.c?view=diff&rev=266520&r1=266519&r2=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2.c (original)
+++ team/akshayb/ao2_containers/main/astobj2.c Sun May 30 10:56:04 2010
@@ -378,8 +378,6 @@
 
 struct ao2_container_core {
 	ao2_callback_fn *cmp_fn;
-	ao2_link_fn *link_fn;
-	ao2_unlink_fn *unlink_fn;
 	/*! Number of elements in the container */
 	int elements;
 	/*! described above */
@@ -388,6 +386,9 @@
 
 struct ao2_container_var {
 	ao2_hash_fn *hash_fn;
+	ao2_link_fn *link_fn;
+	ao2_unlink_fn *unlink_fn;
+
 	int n_buckets;
 	/*! variable size */
 	struct bucket buckets[0];
@@ -441,11 +442,9 @@
 /* This too can be grouped in a alloc function. But that is un-necessary and would be done later */	
 	c->core.version = 1; /* 0 is a reserved value here */
 	c->core.cmp_fn = cmp_fn;
-	c->core.link_fn = link_fn;
-	c->core.unlink_fn = unlink_fn;
 /* This can be put in separate allocation function for varialbe an core part. We can just leave core part here and and constructor for variable part,in astobj2_hash.c */
 
-	internal_ao2_container_var_alloc(c, hash_fn, n_buckets);
+	internal_ao2_container_var_alloc(c, hash_fn,link_fn ,unlink_fn n_buckets);
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
@@ -507,61 +506,7 @@
 	struct astobj2 *astobj;		/* pointer to internal data */
 }; 
 
-/*
- * link an object to a container
- */
-
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
-{
-	int i;
-	/* create a new list entry */
-	struct bucket_entry *p;
-	struct astobj2 *obj = INTERNAL_OBJ(user_data);
-
-	if (obj == NULL)
-		return NULL;
-
-	if (INTERNAL_OBJ(c) == NULL)
-		return NULL;
-
-	p = ast_calloc(1, sizeof(*p));
-	if (!p)
-		return NULL;
-
-	i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
-
-	ao2_lock(c);
-	i %= c->n_buckets;
-	p->astobj = obj;
-	p->version = ast_atomic_fetchadd_int(&c->version, 1);
-	AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
-	ast_atomic_fetchadd_int(&c->elements, 1);
-
-	/* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
-	return p;
-}
-
-void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
-{
-	struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
-
-	if (p) {
-		__ao2_ref_debug(user_data, +1, tag, file, line, funcname);
-		ao2_unlock(c);
-	}
-	return p;
-}
-
-void *__ao2_link(struct ao2_container *c, void *user_data)
-{
-	struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
-
-	if (p) {
-		__ao2_ref(user_data, +1);
-		ao2_unlock(c);
-	}
-	return p;
-}
+
 
 /*!
  * \brief another convenience function is a callback that matches on address
@@ -734,7 +679,8 @@
 			 * link the object into the container that will hold the results.
 			 */
 			if (ret && (multi_container != NULL)) {
-				__ao2_link(multi_container, ret);
+				//__ao2_link(multi_container, ret);
+				multi_container.ao2_link(multi_container, ret);
 				ret = NULL;
 			}
 
@@ -773,7 +719,7 @@
 			break;
 		}
 
-		if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
+		if (i == c->var.n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
 			/* Move to the beginning to ensure we check every bucket */
 			i = -1;
 			last = start;
@@ -825,12 +771,12 @@
  */
 void *__ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
 {
-	return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
+	return __ao2_callback_debug(c, flags, c->core.cmp_fn, arg, tag, file, line, funcname);
 }
 
 void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
 {
-	return __ao2_callback(c, flags, c->cmp_fn, arg);
+	return __ao2_callback(c, flags, c->core.cmp_fn, arg);
 }
 
 /*!

Added: team/akshayb/ao2_containers/main/astobj2_btree.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2_btree.c?view=auto&rev=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2_btree.c (added)
+++ team/akshayb/ao2_containers/main/astobj2_btree.c Sun May 30 10:56:04 2010
@@ -1,0 +1,100 @@
+#include "asterisk/astobj2.h"
+#include "asterisk/astobj2_hash.h"
+
+void internal_ao2_container_var_alloc(ao2_hash_fn *hash_fn, const unsigned int n_buckets)
+{
+	c->var.hash_fn = hash_fn;
+	c->var.n_buckets = n_buckets;
+}
+
+//This funtion calculates the size of ao2_container. Just replace the code in case of other containers:
+
+size_t get_container_size (const unsigned int num_buckets)
+{
+	return (sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket));
+}
+
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+{
+	int i;
+	/* create a new list entry */
+	struct bucket_entry *p;
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+
+	if (obj == NULL)
+		return NULL;
+
+	if (INTERNAL_OBJ(c) == NULL)
+		return NULL;
+
+	p = ast_calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
+
+	ao2_lock(c);
+	i %= c->n_buckets;
+	p->astobj = obj;
+	p->version = ast_atomic_fetchadd_int(&c->version, 1);
+	AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
+	ast_atomic_fetchadd_int(&c->elements, 1);
+
+	/* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
+	return p;
+}
+
+void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
+	struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
+
+	if (p) {
+		__ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+		ao2_unlock(c);
+	}
+	return p;
+}
+
+void *__ao2_link(struct ao2_container *c, void *user_data)
+{
+	struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+	if (p) {
+		__ao2_ref(user_data, +1);
+		ao2_unlock(c);
+	}
+	return p;
+}
+
+/*!
+ *ao2_unlink
+ *Have to be tested for working, Till now it has been just copied and no testing done for the working of the thing
+*/
+
+/*
+ * Unlink an object from the container
+ * and destroy the associated * bucket_entry structure.
+ */
+
+// link an object to the container.
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+			 char *file, int line, const char *funcname)
+{
+	if (INTERNAL_OBJ(user_data) == NULL)	/* safety check on the argument */
+		return NULL;
+
+	__ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+
+	return NULL;
+}
+
+void *__ao2_unlink(struct ao2_container *c, void *user_data)
+{
+	if (INTERNAL_OBJ(user_data) == NULL)	/* safety check on the argument */
+		return NULL;
+
+	__ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+
+	return NULL;
+}
+

Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 30 10:56:04 2010
@@ -1,0 +1,1 @@
+Akshay Bhardwaj 30th May 2010, Contains the variable part of ao2_container based on btree data structure

Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
    svn:mime-type = text/c

Propchange: team/akshayb/ao2_containers/main/astobj2_btree.c
------------------------------------------------------------------------------
    svn:mimetype = text/c

Modified: team/akshayb/ao2_containers/main/astobj2_hash.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/astobj2_hash.c?view=diff&rev=266520&r1=266519&r2=266520
==============================================================================
--- team/akshayb/ao2_containers/main/astobj2_hash.c (original)
+++ team/akshayb/ao2_containers/main/astobj2_hash.c Sun May 30 10:56:04 2010
@@ -14,4 +14,87 @@
 	return (sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket));
 }
 
+static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
+{
+	int i;
+	/* create a new list entry */
+	struct bucket_entry *p;
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
 
+	if (obj == NULL)
+		return NULL;
+
+	if (INTERNAL_OBJ(c) == NULL)
+		return NULL;
+
+	p = ast_calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	i = abs(c->var.hash_fn(user_data, OBJ_POINTER));
+
+	ao2_lock(c);
+	i %= c->n_buckets;
+	p->astobj = obj;
+	p->version = ast_atomic_fetchadd_int(&c->version, 1);
+	AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
+	ast_atomic_fetchadd_int(&c->elements, 1);
+
+	/* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
+	return p;
+}
+
+void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
+	struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
+
+	if (p) {
+		__ao2_ref_debug(user_data, +1, tag, file, line, funcname);
+		ao2_unlock(c);
+	}
+	return p;
+}
+
+void *__ao2_link(struct ao2_container *c, void *user_data)
+{
+	struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+	if (p) {
+		__ao2_ref(user_data, +1);
+		ao2_unlock(c);
+	}
+	return p;
+}
+
+/*!
+ *ao2_unlink
+ *Have to be tested for working, Till now it has been just copied and no testing done for the working of the thing
+*/
+
+/*
+ * Unlink an object from the container
+ * and destroy the associated * bucket_entry structure.
+ */
+
+// link an object to the container.
+void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
+			 char *file, int line, const char *funcname)
+{
+	if (INTERNAL_OBJ(user_data) == NULL)	/* safety check on the argument */
+		return NULL;
+
+	__ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
+
+	return NULL;
+}
+
+void *__ao2_unlink(struct ao2_container *c, void *user_data)
+{
+	if (INTERNAL_OBJ(user_data) == NULL)	/* safety check on the argument */
+		return NULL;
+
+	__ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
+
+	return NULL;
+}
+

Added: team/akshayb/ao2_containers/main/btree.c
URL: http://svnview.digium.com/svn/asterisk/team/akshayb/ao2_containers/main/btree.c?view=auto&rev=266520
==============================================================================
--- team/akshayb/ao2_containers/main/btree.c (added)
+++ team/akshayb/ao2_containers/main/btree.c Sun May 30 10:56:04 2010
@@ -1,0 +1,857 @@
+#include "btree.h"
+
+typedef enum {left = -1,right = 1} position_t;
+
+typedef struct {
+	bt_node * node;
+	unsigned int index;
+}node_pos;
+
+static void print_single_node(btree *btree, bt_node * node);
+static bt_node * allocate_btree_node (unsigned int order);
+static int free_btree_node (bt_node * node);
+
+static node_pos get_btree_node(btree * btree,void * key);
+
+static int delete_key_from_node(btree * btree, node_pos * node_pos);
+static bt_node * merge_nodes(btree * btree, bt_node * n1, bt_key_val * kv ,bt_node * n2);
+static void move_key(btree * btree, bt_node * node, unsigned int index, position_t pos);
+static node_pos get_max_key_pos(btree * btree, bt_node * subtree);
+static node_pos get_min_key_pos(btree * btree, bt_node * subtree);
+static bt_node * merge_siblings(btree * btree, bt_node * parent,unsigned int index,
+					position_t pos);
+static void copy_key_val(btree * btree,bt_key_val * src, bt_key_val * dst);
+
+/**
+*	Used to create a btree with just the root node
+*	@param order The order of the B-tree
+*	@return The an empty B-tree
+*/
+btree * btree_create(unsigned int order) {
+	btree * btree;
+	btree = mem_alloc(sizeof(*btree));
+	btree->order = order;
+	btree->root = allocate_btree_node(order);
+	btree->root->leaf = true;
+	btree->root->nr_active = 0;
+	btree->root->next = NULL;
+	btree->root->level = 0;
+	return btree;
+}
+
+/**
+*       Function used to allocate memory for the btree node
+*       @param order Order of the B-Tree
+*	@param leaf boolean set true for a leaf node
+*       @return The allocated B-tree node
+*/
+static bt_node * allocate_btree_node (unsigned int order) {
+        bt_node * node;
+
+        // Allocate memory for the node
+        node = (bt_node *)mem_alloc(sizeof(bt_node));
+       
+        // Initialize the number of active nodes
+        node->nr_active = 0;
+
+        // Initialize the keys
+        node->key_vals = (bt_key_val **)mem_alloc(2*order*sizeof(bt_key_val*) - 1);
+        
+        // Initialize the child pointers
+        node->children = (bt_node **)mem_alloc(2*order*sizeof(bt_node*));
+
+	// Use to determine whether it is a leaf
+	node->leaf = true;
+
+	// Use to determine the level in the tree
+	node->level = 0;
+
+	//Initialize the linked list pointer to NULL
+	node->next = NULL;
+
+        return node;
+}
+
+/**
+*       Function used to free the memory allocated to the b-tree 
+*       @param node The node to be freed
+*       @param order Order of the B-Tree
+*       @return The allocated B-tree node
+*/
+static int free_btree_node (bt_node * node) {
+
+        mem_free(node->children);
+        mem_free(node->key_vals);
+        mem_free(node);
+
+        return 0;
+}
+
+/**
+*	Used to split the child node and adjust the parent so that
+*	it has two children
+*	@param parent Parent Node
+*	@param index Index of the child node
+*	@param child  Full child node
+*	
+*/
+static void btree_split_child(btree * btree, bt_node * parent, 
+				unsigned int index,
+				bt_node * child) {
+	int i = 0;	
+	unsigned int order = btree->order;
+
+	bt_node * new_child = allocate_btree_node(btree->order); 
+	new_child->leaf = child->leaf;
+	new_child->level = child->level;
+	new_child->nr_active = btree->order - 1;
+
+	// Copy the higher order keys to the new child	
+	for(i=0;i<order - 1;i++) {
+		new_child->key_vals[i] = child->key_vals[i + order];
+		if(!child->leaf) {
+			new_child->children[i] = 
+				child->children[i + order];
+		} 
+	}
+	
+	// Copy the last child pointer
+	if(!child->leaf) {
+		new_child->children[i] = 
+		child->children[i + order];
+	}
+
+	child->nr_active = order - 1;
+	
+	for(i = parent->nr_active + 1;i > index + 1;i--) {
+		parent->children[i] = parent->children[i - 1];
+	}
+	parent->children[index + 1] = new_child;
+
+	for(i = parent->nr_active;i > index;i--) {
+		parent->key_vals[i] = parent->key_vals[i - 1];
+	}
+
+	parent->key_vals[index] = child->key_vals[order - 1];	
+	parent->nr_active++;
+}
+
+/**
+*	Used to insert a key in the non-full node
+*	@param btree The btree
+*	@param node The node to which the key will be added
+*	@param the key value pair
+*	@return void
+*/
+
+static void btree_insert_nonfull (btree * btree, bt_node * parent_node,
+				bt_key_val * key_val) {
+	
+	unsigned int key = btree->value(key_val->key);
+	int i ;
+	bt_node * child;	
+	bt_node * node = parent_node;
+
+insert:	i = node->nr_active - 1;
+	if(node->leaf) {
+		while(i >= 0 && key < btree->value(node->key_vals[i]->key)) {
+			node->key_vals[i + 1] = node->key_vals[i];
+			i--;
+		}
+		node->key_vals[i + 1] = key_val;
+		node->nr_active++; 
+	} else {
+		while (i >= 0 && key < btree->value(node->key_vals[i]->key)) {
+			i--;
+		}
+		i++;
+		child = node->children[i]; 
+		
+		if(child->nr_active == 2*btree->order - 1) {
+			btree_split_child(btree,node,i,child);	
+			if(btree->value(key_val->key) > 
+				btree->value(node->key_vals[i]->key)) {
+				i++;	
+			}	
+		}
+		node = node->children[i];
+		goto insert;	
+	} 
+}
+
+
+/**
+*       Function used to insert node into a B-Tree
+*       @param root Root of the B-Tree
+*       @param node The node to be inserted
+*       @param compare Function used to compare the two nodes of the tree
+*       @return success or failure
+*/
+int btree_insert_key(btree * btree, bt_key_val * key_val) {
+	bt_node * rnode;
+
+	rnode = btree->root;
+	if(rnode->nr_active == (2*btree->order - 1)) {
+		bt_node * new_root;
+		new_root = allocate_btree_node(btree->order);
+		new_root->level = btree->root->level + 1;
+		btree->root = new_root;	
+		new_root->leaf = false;
+		new_root->nr_active = 0;
+		new_root->children[0]  = rnode;
+		btree_split_child(btree,new_root,0,rnode);
+		btree_insert_nonfull(btree,new_root,key_val);	
+	} else
+		btree_insert_nonfull(btree,rnode,key_val);		
+
+        return 0;
+}
+
+/**
+*	Used to get the position of the MAX key within the subtree
+*	@param btree The btree
+*	@param subtree The subtree to be searched
+*	@return The node containing the key and position of the key
+*/
+static node_pos get_max_key_pos(btree * btree, bt_node * subtree) {
+	node_pos node_pos;
+	bt_node * node = subtree; 
+
+	while(true) {
+		if(node == NULL) {
+			break;
+		}
+
+		if(node->leaf) {
+			node_pos.node 	= node;
+			node_pos.index 	= node->nr_active - 1;
+			return node_pos;	
+		} else {
+			node_pos.node 	= node;
+			node_pos.index 	= node->nr_active - 1;
+			node = node->children[node->nr_active];	
+		}
+	}
+	return node_pos;
+}
+
+/**
+*	Used to get the position of the MAX key within the subtree
+*	@param btree The btree
+*	@param subtree The subtree to be searched
+*	@return The node containing the key and position of the key
+*/
+static node_pos get_min_key_pos(btree * btree, bt_node * subtree) {
+	node_pos node_pos;
+	bt_node * node = subtree; 
+
+	while(true) {
+		if(node == NULL) {
+			break;
+		}
+
+		if(node->leaf) {
+			node_pos.node 	= node;
+			node_pos.index 	= 0;
+			return node_pos;	
+		} else {
+			node_pos.node 	= node;
+			node_pos.index 	= 0;
+			node = node->children[0];	
+		}
+	}
+	return node_pos;
+}
+
+/**
+*	Merge nodes n1 and n2 (case 3b from Cormen)
+*	@param btree The btree 
+*	@param node The parent node 
+*	@param index of the child
+*	@param pos left or right
+*	@return none 
+*/
+static bt_node * merge_siblings(btree * btree, bt_node * parent, unsigned int index , 
+					position_t pos) {
+	unsigned int i,j;
+	bt_node * new_node;
+	bt_node * n1, * n2;
+        
+        if (index == (parent->nr_active)) {   
+               index--;
+	       n1 = parent->children[parent->nr_active - 1];
+	       n2 = parent->children[parent->nr_active];
+        } else {
+               n1 = parent->children[index];
+	       n2 = parent->children[index + 1];
+        }
+
+	//Merge the current node with the left node
+	new_node = allocate_btree_node(btree->order);
+	new_node->level = n1->level;
+	new_node->leaf = n1->leaf;
+
+	for(j=0;j<btree->order - 1; j++) {
+		new_node->key_vals[j] =	n1->key_vals[j];
+		new_node->children[j] =	n1->children[j];
+	}
+	
+	new_node->key_vals[btree->order - 1] =	parent->key_vals[index];
+	new_node->children[btree->order - 1] =	n1->children[btree->order - 1];
+
+	for(j=0;j<btree->order - 1; j++) {
+		new_node->key_vals[j + btree->order] = 	n2->key_vals[j];
+		new_node->children[j + btree->order] = 	n2->children[j];
+	}
+	new_node->children[2*btree->order - 1] = n2->children[btree->order - 1];
+
+	parent->children[index] = new_node;
+
+	for(j = index;j<parent->nr_active;j++) {
+		parent->key_vals[j] = parent->key_vals[j + 1];
+		parent->children[j + 1] = parent->children[j + 2];
+	}
+
+	new_node->nr_active = n1->nr_active + n2->nr_active + 1;
+	parent->nr_active--;
+
+	for(i=parent->nr_active;i < 2*btree->order - 1; i++) {
+		parent->key_vals[i] = NULL; 
+	}
+
+	free_btree_node(n1);
+	free_btree_node(n2);
+
+	if (parent->nr_active == 0 && btree->root == parent) {
+		free_btree_node(parent);
+		btree->root = new_node;
+		if(new_node->level)
+			new_node->leaf = false;
+		else
+			new_node->leaf = true; 
+	}
+
+	return new_node;
+}
+
+/**
+*	Move the key from node to another	
+*	@param btree The B-Tree
+*	@param node The parent node
+*	@param index of the key to be moved done 
+*	@param pos the position of the child to receive the key 
+*	@return none
+*/
+static void move_key(btree * btree, bt_node * node, unsigned int index, position_t pos) {
+	bt_node * lchild;
+	bt_node * rchild;
+	unsigned int i;
+
+	if(pos == right) {
+		index--;
+	}
+	lchild = node->children[index];
+	rchild = node->children[index + 1];
+	
+	// Move the key from the parent to the left child
+	if(pos == left) {
+		lchild->key_vals[lchild->nr_active] = node->key_vals[index];
+		lchild->children[lchild->nr_active + 1] = rchild->children[0];
+		rchild->children[0] = NULL;
+		lchild->nr_active++;
+
+		node->key_vals[index] = rchild->key_vals[0];
+		rchild->key_vals[0] = NULL;
+
+		for(i=0;i<rchild->nr_active - 1;i++) {
+			rchild->key_vals[i] = rchild->key_vals[i + 1];
+			rchild->children[i] = rchild->children[i + 1];
+		}
+		rchild->children[rchild->nr_active - 1] = 
+				rchild->children[rchild->nr_active];
+		rchild->nr_active--;
+	} else {
+		// Move the key from the parent to the right child
+		for(i=rchild->nr_active;i > 0 ; i--) {
+			rchild->key_vals[i] = rchild->key_vals[i - 1];
+			rchild->children[i + 1] = rchild->children[i];		
+		}
+		rchild->children[1] = rchild->children[0];		
+		rchild->children[0] = NULL;
+
+		rchild->key_vals[0] = node->key_vals[index];
+
+		rchild->children[0] = lchild->children[lchild->nr_active];	
+		lchild->children[lchild->nr_active] = NULL;
+
+		node->key_vals[index] = lchild->key_vals[lchild->nr_active - 1];
+		lchild->key_vals[lchild->nr_active - 1] = NULL;
+			
+		lchild->nr_active--;
+		rchild->nr_active++;		
+	}				
+}
+
+/**
+*	Merge nodes n1 and n2
+*	@param n1 First node
+*	@param n2 Second node
+*	@return combined node
+*/
+static bt_node * merge_nodes(btree * btree, bt_node * n1, bt_key_val * kv,
+                                                bt_node * n2) {
+	bt_node * new_node;
+	unsigned int i;	
+
+	new_node = allocate_btree_node(btree->order);
+	new_node->leaf = true;
+	
+	for(i=0;i<n1->nr_active;i++) {
+		new_node->key_vals[i]   = n1->key_vals[i];	
+                new_node->children[i]   = n1->children[i];
+	}
+        new_node->children[n1->nr_active] = n1->children[n1->nr_active];
+        new_node->key_vals[n1->nr_active] = kv;
+
+	for(i=0;i<n2->nr_active;i++) {
+		new_node->key_vals[i + n1->nr_active + 1] = n2->key_vals[i];
+                new_node->children[i + n1->nr_active + 1] = n2->children[i];
+	}
+        new_node->children[2*btree->order - 1] = n2->children[n2->nr_active];
+	
+        new_node->nr_active = n1->nr_active + n2->nr_active + 1;
+        new_node->leaf = n1->leaf;
+        new_node->level = n1->level;
+
+	free_btree_node(n1);
+	free_btree_node(n2);
+
+	return new_node;
+}
+
+/**
+*	Used to delete a key from the B-tree node
+*	@param btree The btree
+*	@param node The node from which the key is to be deleted 	
+*	@param key The key to be deleted
+*	@return 0 on success -1 on error 
+*/
+
+int delete_key_from_node(btree * btree, node_pos * node_pos) {
+	unsigned int keys_max = 2*btree->order - 1;
+	unsigned int i;
+	bt_key_val * key_val;
+	bt_node * node = node_pos->node;
+
+	if(node->leaf == false) {
+		return -1;
+	}	
+	
+	key_val = node->key_vals[node_pos->index];
+
+	for(i=node_pos->index;i< keys_max - 1;i++) {
+		node->key_vals[i] = node->key_vals[i + 1];	
+	}
+	
+	if(key_val->key) {
+		mem_free(key_val->key);
+                key_val->key = NULL;
+	}
+
+	if(key_val->val) {
+		mem_free(key_val->val);
+                key_val->val = NULL;
+	}
+	
+	node->nr_active--;
+
+	if(node->nr_active == 0 ) {
+		free_btree_node(node);
+	}
+	return 0;
+}
+
+/**
+*       Function used to delete a node from a  B-Tree
+*       @param btree The B-Tree
+*       @param key Key of the node to be deleted
+*       @param value function to map the key to an unique integer value        
+*       @param compare Function used to compare the two nodes of the tree
+*       @return success or failure
+*/
+
+int btree_delete_key(btree * btree,bt_node * subtree,void * key) {
+	unsigned int i,index;
+	bt_node * node = NULL, * rsibling, *lsibling;
+	bt_node * comb_node, * parent;
+	node_pos sub_node_pos;
+	node_pos node_pos;
+	bt_key_val * key_val, * new_key_val;
+	unsigned int kv = btree->value(key);	
+
+	node = subtree;
+	parent = NULL;	
+
+del_loop:for (i = 0;;i = 0) {
+             
+            //If there are no keys simply return
+            if(!node->nr_active)
+                return -1;
+
+	    // Fix the index of the key greater than or equal
+	    // to the key that we would like to search
+		
+	    while (i < node->nr_active && kv > 
+			    btree->value(node->key_vals[i]->key) ) {
+		    i++;
+	    }
+	    index = i;
+
+	    // If we find such key break		    
+	    if(i < node->nr_active && 
+			kv == btree->value(node->key_vals[i]->key)) {
+			break;
+	    }
+            if(node->leaf)
+                return -1;
+                
+    	    //Store the parent node
+	    parent = node;
+
+	    // To get a child node 
+	    node = node->children[i];
+
+            //If NULL not found
+            if (node == NULL)
+                return -1;
+
+            if (index == (parent->nr_active)) {   
+                lsibling =  parent->children[parent->nr_active - 1];
+	    	rsibling = NULL; 
+            } else if (index == 0) {
+                lsibling = NULL;
+                rsibling = parent->children[1];
+            } else {
+        	lsibling = parent->children[i - 1];
+	    	rsibling = parent->children[i + 1];
+            }
+
+	    if (node->nr_active == btree->order - 1 && parent) {
+		// The current node has (t - 1) keys but the right sibling has > (t - 1)
+		// keys
+		if (rsibling && (rsibling->nr_active > btree->order - 1)) {
+			move_key(btree,parent,i,left);
+		} else
+		// The current node has (t - 1) keys but the left sibling has (t - 1)
+		// keys
+		if (lsibling && (lsibling->nr_active > btree->order - 1)) {
+			move_key(btree,parent,i,right);
+		} else
+		// Left sibling has (t - 1) keys
+	        if(lsibling && (lsibling->nr_active == btree->order - 1)) {
+		        node = merge_siblings(btree,parent,i,left);
+		} else
+                // Right sibling has (t - 1) keys
+	        if(rsibling && (rsibling->nr_active == btree->order - 1)) {
+		        node = merge_siblings(btree,parent,i,right);
+		}
+	    }
+        }            
+	
+	//Case 1 : The node containing the key is found and is the leaf node.
+	//Also the leaf node has keys greater than the minimum required.
+	//Simply remove the key
+	if(node->leaf && (node->nr_active > btree->order - 1)) {
+		node_pos.node = node;
+		node_pos.index = index;
+		delete_key_from_node(btree,&node_pos);
+		return 0;
+	}
+
+	//If the leaf node is the root permit deletion even if the number of keys is
+	//less than (t - 1)
+	if(node->leaf && (node == btree->root)) {
+		node_pos.node = node;
+		node_pos.index = index;
+		delete_key_from_node(btree,&node_pos);
+		return 0;
+	}
+
+
+	//Case 2: The node containing the key is found and is an internal node
+	if(node->leaf == false) {
+		if(node->children[index]->nr_active > btree->order - 1 ) {
+			sub_node_pos = get_max_key_pos(btree,node->children[index]);
+                        key_val = sub_node_pos.node->key_vals[sub_node_pos.index];
+
+                        new_key_val = (bt_key_val *)mem_alloc(sizeof(bt_key_val));
+                        copy_key_val(btree,key_val,new_key_val);
+        		node->key_vals[index] = new_key_val;	
+               
+                        btree_delete_key(btree,node->children[index],key_val->key);
+			if(sub_node_pos.node->leaf == false) {
+                                print("Not leaf\n");
+                        }
+		} else if ((node->children[index + 1]->nr_active > btree->order - 1) ) {
+			sub_node_pos = 
+                                get_min_key_pos(btree,node->children[index + 1]);
+                        key_val = sub_node_pos.node->key_vals[sub_node_pos.index];
+
+                        new_key_val = (bt_key_val *)mem_alloc(sizeof(bt_key_val));
+                        copy_key_val(btree,key_val,new_key_val);
+        		node->key_vals[index] = new_key_val;	
+               
+                        btree_delete_key(btree,node->children[index + 1],key_val->key);
+			if(sub_node_pos.node->leaf == false) {
+                                print("Not leaf\n");
+                        }
+
+		} else if ( 
+			node->children[index]->nr_active == btree->order - 1 &&
+			node->children[index + 1]->nr_active == btree->order - 1) {
+
+			comb_node = merge_nodes(btree,node->children[index],
+                                node->key_vals[index],
+				node->children[index + 1]);
+			node->children[index] = comb_node;
+			
+			for(i=index + 1;i<node->nr_active;i++) {
+				node->children[i] = node->children[i + 1];
+				node->key_vals[i - 1] = node->key_vals[i];
+			}
+			node->nr_active--;
+                        if (node->nr_active == 0 && btree->root == node) {
+                                free_btree_node(node);
+                                btree->root = comb_node;        
+                        } 
+                        node = comb_node;
+                        goto del_loop;
+		}		
+          }
+	
+	// Case 3:
+	// In this case start from the top of the tree and continue
+	// moving to the leaf node making sure that each node that
+	// we encounter on the way has atleast 't' (order of the tree)
+	// keys 
+	if(node->leaf && (node->nr_active > btree->order - 1)) {
+	      node_pos.node = node;
+	      node_pos.index = index;
+	      delete_key_from_node(btree,&node_pos);
+	}
+
+        return 0;
+}
+
+/**
+*	Function used to get the node containing the given key
+*	@param btree The btree to be searched
+*	@param key The the key to be searched
+*	@return The node and position of the key within the node 
+*/
+node_pos  get_btree_node(btree * btree,void * key) {
+	node_pos kp;
+	unsigned int key_val = btree->value(key);	
+	bt_node * node;
+	unsigned int i = 0;
+
+	node = btree->root;
+
+		
+	for (;;i = 0) {	
+
+	    // Fix the index of the key greater than or equal
+	    // to the key that we would like to search
+		
+	    while (i < node->nr_active && key_val > 
+			    btree->value(node->key_vals[i]->key) ) {
+		    i++;
+	    }
+
+	    // If we find such key return the key-value pair		    
+	    if(i < node->nr_active && 
+			key_val == btree->value(node->key_vals[i]->key)) {
+		    kp.node = node;
+		    kp.index = i;	
+		    return kp;
+	    }
+	
+	    // If the node is leaf and if we did not find the key 
+	    // return NULL
+	    if(node->leaf) {
+		    return kp;
+	    }
+
+	    // To got a child node 
+	    node = node->children[i];
+	}
+      	return kp;
+
+}
+
+/**
+*       Used to destory btree
+*       @param btree The B-tree
+*       @return none
+*/
+void btree_destroy(btree * btree) {
+       int i = 0;
+       unsigned int current_level;
+
+       bt_node * head, * tail, * node;
+       bt_node * child, * del_node;
+
+       node = btree->root;
+       current_level = node->level;
+       head = node;
+       tail = node;
+
+       while(true) {
+               if(head == NULL) {
+                       break;
+               }
+               if (head->level < current_level) {
+                       current_level = head->level;
+               }
+
+               if(head->leaf == false) {
+                       for(i = 0 ; i < head->nr_active + 1; i++) {
+                               child = head->children[i];
+                               tail->next = child;
+                               tail = child;
+                               child->next = NULL;
+                       }
+               }
+               del_node = head;
+               head = head->next;
+               free_btree_node(del_node);
+       }
+
+}
+
+/**
+*       Function used to search a node in a B-Tree
+*       @param btree The B-tree to be searched
+*       @param key Key of the node to be search
+*       @return The key-value pair
+*/
+bt_key_val * btree_search(btree * btree,void * key) {
+
+	bt_key_val * key_val = NULL;
+	node_pos kp = get_btree_node(btree,key);
+
+	if(kp.node) {
+		key_val = kp.node->key_vals[kp.index];
+	}
+	return key_val; 
+}
+
+/**
+*       Used to copy key value from source to destination
+*       @param src The source key value
+*       @param dst The dest key value
+*       @return none
+*/
+static void copy_key_val(btree * btree, bt_key_val * src, bt_key_val * dst) {
+        unsigned int keysize;
+        unsigned int datasize;
+
+        keysize    = btree->key_size(src->key);
+        dst->key        = (void *)mem_alloc(keysize);
+        bcopy(src->key,dst->key,keysize);
+        
+        if(src->val) {
+                datasize   = btree->data_size(src->val);
+                dst->val       = (void *)mem_alloc(datasize);
+                bcopy(src->val,dst->val,datasize);
+        }                
+        
+}
+
+/**
+*	Get the max key in the btree
+*	@param btree The btree
+*	@return The max key 
+*/
+void * btree_get_max_key(btree * btree) {
+	node_pos node_pos;
+	node_pos = get_max_key_pos(btree,btree->root);
+	return node_pos.node->key_vals[node_pos.index]->key;
+}
+
+/**
+*	Get the min key in the btree
+*	@param btree The btree
+*	@return The max key 
+*/
+void * btree_get_min_key(btree * btree) {
+	node_pos node_pos;
+	node_pos = get_min_key_pos(btree,btree->root);
+	return node_pos.node->key_vals[node_pos.index]->key;
+}
+
+#ifdef DEBUG
+
+/**
+*	Used to print the keys of the bt_node
+*	@param node The node whose keys are to be printed
+*	@return none
+*/
+
+static void print_single_node(btree *btree, bt_node * node) {
+	
+	int i = 0;
+	
+	print(" { ");	
+	while(i < node->nr_active) {
+		print("0x%x(%d) ", btree->value(node->key_vals[i]->key),
+			node->level);
+		i++;
+	}
+	print("} (0x%x,%d) ", node,node->leaf);	
+}
+
+/**
+*       Function used to print the B-tree
+*       @param root Root of the B-Tree
+*       @param print_key Function used to print the key value
+*       @return none
+*/
+
+void print_subtree(btree *btree,bt_node * node) {
+	
+	int i = 0;
+	unsigned int current_level;
+
+	bt_node * head, * tail;
+	bt_node * child;
+
+	current_level = node->level;
+	head = node;
+	tail = node;
+
+	while(true) {
+		if(head == NULL) {
+			break;
+		}
+		if (head->level < current_level) {
+			current_level = head->level;
+			print("\n");
+		}
+		print_single_node(btree,head);
+
+		if(head->leaf == false) {	
+			for(i = 0 ; i < head->nr_active + 1; i++) {
+				child = head->children[i];
+				tail->next = child;
+				tail = child;
+				child->next = NULL;
+			}
+		}
+		head = head->next;	
+	}
+	print("\n");
+}
+
+
+#endif

Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
    svn:eol-stlye = native

Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Sun May 30 10:56:04 2010
@@ -1,0 +1,1 @@
+Akshay Bhardwaj 30 May 2010, Contains code for btree implementation

Propchange: team/akshayb/ao2_containers/main/btree.c
------------------------------------------------------------------------------
    svn:mime-type = text/c




More information about the asterisk-commits mailing list