xref: /onnv-gate/usr/src/cmd/filebench/common/fb_avl.c (revision 9513:5dc53d16bc1b)
18404SAndrew.W.Wilson@sun.com /*
28404SAndrew.W.Wilson@sun.com  * CDDL HEADER START
38404SAndrew.W.Wilson@sun.com  *
48404SAndrew.W.Wilson@sun.com  * The contents of this file are subject to the terms of the
58404SAndrew.W.Wilson@sun.com  * Common Development and Distribution License (the "License").
68404SAndrew.W.Wilson@sun.com  * You may not use this file except in compliance with the License.
78404SAndrew.W.Wilson@sun.com  *
88404SAndrew.W.Wilson@sun.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98404SAndrew.W.Wilson@sun.com  * or http://www.opensolaris.org/os/licensing.
108404SAndrew.W.Wilson@sun.com  * See the License for the specific language governing permissions
118404SAndrew.W.Wilson@sun.com  * and limitations under the License.
128404SAndrew.W.Wilson@sun.com  *
138404SAndrew.W.Wilson@sun.com  * When distributing Covered Code, include this CDDL HEADER in each
148404SAndrew.W.Wilson@sun.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158404SAndrew.W.Wilson@sun.com  * If applicable, add the following below this CDDL HEADER, with the
168404SAndrew.W.Wilson@sun.com  * fields enclosed by brackets "[]" replaced with your own identifying
178404SAndrew.W.Wilson@sun.com  * information: Portions Copyright [yyyy] [name of copyright owner]
188404SAndrew.W.Wilson@sun.com  *
198404SAndrew.W.Wilson@sun.com  * CDDL HEADER END
208404SAndrew.W.Wilson@sun.com  */
218404SAndrew.W.Wilson@sun.com /*
22*9513SAndrew.W.Wilson@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238404SAndrew.W.Wilson@sun.com  * Use is subject to license terms.
248404SAndrew.W.Wilson@sun.com  */
258404SAndrew.W.Wilson@sun.com 
268404SAndrew.W.Wilson@sun.com 
278404SAndrew.W.Wilson@sun.com /*
288404SAndrew.W.Wilson@sun.com  * AVL - generic AVL tree implementation for FileBench use.
298404SAndrew.W.Wilson@sun.com  * -Adapted from the avl.c open source code used in the Solaris Kernel-
308404SAndrew.W.Wilson@sun.com  *
318404SAndrew.W.Wilson@sun.com  * A complete description of AVL trees can be found in many CS textbooks.
328404SAndrew.W.Wilson@sun.com  *
338404SAndrew.W.Wilson@sun.com  * Here is a very brief overview. An AVL tree is a binary search tree that is
348404SAndrew.W.Wilson@sun.com  * almost perfectly balanced. By "almost" perfectly balanced, we mean that at
358404SAndrew.W.Wilson@sun.com  * any given node, the left and right subtrees are allowed to differ in height
368404SAndrew.W.Wilson@sun.com  * by at most 1 level.
378404SAndrew.W.Wilson@sun.com  *
388404SAndrew.W.Wilson@sun.com  * This relaxation from a perfectly balanced binary tree allows doing
398404SAndrew.W.Wilson@sun.com  * insertion and deletion relatively efficiently. Searching the tree is
408404SAndrew.W.Wilson@sun.com  * still a fast operation, roughly O(log(N)).
418404SAndrew.W.Wilson@sun.com  *
428404SAndrew.W.Wilson@sun.com  * The key to insertion and deletion is a set of tree maniuplations called
438404SAndrew.W.Wilson@sun.com  * rotations, which bring unbalanced subtrees back into the semi-balanced state.
448404SAndrew.W.Wilson@sun.com  *
458404SAndrew.W.Wilson@sun.com  * This implementation of AVL trees has the following peculiarities:
468404SAndrew.W.Wilson@sun.com  *
478404SAndrew.W.Wilson@sun.com  *	- The AVL specific data structures are physically embedded as fields
488404SAndrew.W.Wilson@sun.com  *	  in the "using" data structures.  To maintain generality the code
498404SAndrew.W.Wilson@sun.com  *	  must constantly translate between "avl_node_t *" and containing
508404SAndrew.W.Wilson@sun.com  *	  data structure "void *"s by adding/subracting the avl_offset.
518404SAndrew.W.Wilson@sun.com  *
528404SAndrew.W.Wilson@sun.com  *	- Since the AVL data is always embedded in other structures, there is
538404SAndrew.W.Wilson@sun.com  *	  no locking or memory allocation in the AVL routines. This must be
548404SAndrew.W.Wilson@sun.com  *	  provided for by the enclosing data structure's semantics. Typically,
558404SAndrew.W.Wilson@sun.com  *	  avl_insert()/_add()/_remove()/avl_insert_here() require some kind of
568404SAndrew.W.Wilson@sun.com  *	  exclusive write lock. Other operations require a read lock.
578404SAndrew.W.Wilson@sun.com  *
588404SAndrew.W.Wilson@sun.com  *      - The implementation uses iteration instead of explicit recursion,
598404SAndrew.W.Wilson@sun.com  *	  since it is intended to run on limited size kernel stacks. Since
608404SAndrew.W.Wilson@sun.com  *	  there is no recursion stack present to move "up" in the tree,
618404SAndrew.W.Wilson@sun.com  *	  there is an explicit "parent" link in the avl_node_t.
628404SAndrew.W.Wilson@sun.com  *
638404SAndrew.W.Wilson@sun.com  *      - The left/right children pointers of a node are in an array.
648404SAndrew.W.Wilson@sun.com  *	  In the code, variables (instead of constants) are used to represent
658404SAndrew.W.Wilson@sun.com  *	  left and right indices.  The implementation is written as if it only
668404SAndrew.W.Wilson@sun.com  *	  dealt with left handed manipulations.  By changing the value assigned
678404SAndrew.W.Wilson@sun.com  *	  to "left", the code also works for right handed trees.  The
688404SAndrew.W.Wilson@sun.com  *	  following variables/terms are frequently used:
698404SAndrew.W.Wilson@sun.com  *
708404SAndrew.W.Wilson@sun.com  *		int left;	// 0 when dealing with left children,
718404SAndrew.W.Wilson@sun.com  *				// 1 for dealing with right children
728404SAndrew.W.Wilson@sun.com  *
738404SAndrew.W.Wilson@sun.com  *		int left_heavy;	// -1 when left subtree is taller at some node,
748404SAndrew.W.Wilson@sun.com  *				// +1 when right subtree is taller
758404SAndrew.W.Wilson@sun.com  *
768404SAndrew.W.Wilson@sun.com  *		int right;	// will be the opposite of left (0 or 1)
778404SAndrew.W.Wilson@sun.com  *		int right_heavy;// will be the opposite of left_heavy (-1 or 1)
788404SAndrew.W.Wilson@sun.com  *
798404SAndrew.W.Wilson@sun.com  *		int direction;  // 0 for "<" (ie. left child); 1 for ">" (right)
808404SAndrew.W.Wilson@sun.com  *
818404SAndrew.W.Wilson@sun.com  *	  Though it is a little more confusing to read the code, the approach
828404SAndrew.W.Wilson@sun.com  *	  allows using half as much code (and hence cache footprint) for tree
838404SAndrew.W.Wilson@sun.com  *	  manipulations and eliminates many conditional branches.
848404SAndrew.W.Wilson@sun.com  *
858404SAndrew.W.Wilson@sun.com  *	- The avl_index_t is an opaque "cookie" used to find nodes at or
868404SAndrew.W.Wilson@sun.com  *	  adjacent to where a new value would be inserted in the tree. The value
878404SAndrew.W.Wilson@sun.com  *	  is a modified "avl_node_t *".  The bottom bit (normally 0 for a
888404SAndrew.W.Wilson@sun.com  *	  pointer) is set to indicate if that the new node has a value greater
898404SAndrew.W.Wilson@sun.com  *	  than the value of the indicated "avl_node_t *".
908404SAndrew.W.Wilson@sun.com  */
918404SAndrew.W.Wilson@sun.com 
928404SAndrew.W.Wilson@sun.com #include "filebench.h"
938404SAndrew.W.Wilson@sun.com #include "fb_avl.h"
948404SAndrew.W.Wilson@sun.com 
958404SAndrew.W.Wilson@sun.com /*
968404SAndrew.W.Wilson@sun.com  * Small arrays to translate between balance (or diff) values and child indeces.
978404SAndrew.W.Wilson@sun.com  *
988404SAndrew.W.Wilson@sun.com  * Code that deals with binary tree data structures will randomly use
998404SAndrew.W.Wilson@sun.com  * left and right children when examining a tree.  C "if()" statements
1008404SAndrew.W.Wilson@sun.com  * which evaluate randomly suffer from very poor hardware branch prediction.
1018404SAndrew.W.Wilson@sun.com  * In this code we avoid some of the branch mispredictions by using the
1028404SAndrew.W.Wilson@sun.com  * following translation arrays. They replace random branches with an
1038404SAndrew.W.Wilson@sun.com  * additional memory reference. Since the translation arrays are both very
1048404SAndrew.W.Wilson@sun.com  * small the data should remain efficiently in cache.
1058404SAndrew.W.Wilson@sun.com  */
1068404SAndrew.W.Wilson@sun.com static const int  avl_child2balance[2]	= {-1, 1};
1078404SAndrew.W.Wilson@sun.com static const int  avl_balance2child[]	= {0, 0, 1};
1088404SAndrew.W.Wilson@sun.com 
1098404SAndrew.W.Wilson@sun.com 
1108404SAndrew.W.Wilson@sun.com /*
1118404SAndrew.W.Wilson@sun.com  * Walk from one node to the previous valued node (ie. an infix walk
1128404SAndrew.W.Wilson@sun.com  * towards the left). At any given node we do one of 2 things:
1138404SAndrew.W.Wilson@sun.com  *
1148404SAndrew.W.Wilson@sun.com  * - If there is a left child, go to it, then to it's rightmost descendant.
1158404SAndrew.W.Wilson@sun.com  *
1168404SAndrew.W.Wilson@sun.com  * - otherwise we return thru parent nodes until we've come from a right child.
1178404SAndrew.W.Wilson@sun.com  *
1188404SAndrew.W.Wilson@sun.com  * Return Value:
1198404SAndrew.W.Wilson@sun.com  * NULL - if at the end of the nodes
1208404SAndrew.W.Wilson@sun.com  * otherwise next node
1218404SAndrew.W.Wilson@sun.com  */
1228404SAndrew.W.Wilson@sun.com void *
avl_walk(avl_tree_t * tree,void * oldnode,int left)1238404SAndrew.W.Wilson@sun.com avl_walk(avl_tree_t *tree, void	*oldnode, int left)
1248404SAndrew.W.Wilson@sun.com {
1258404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
1268404SAndrew.W.Wilson@sun.com 	avl_node_t *node = AVL_DATA2NODE(oldnode, off);
1278404SAndrew.W.Wilson@sun.com 	int right = 1 - left;
1288404SAndrew.W.Wilson@sun.com 	int was_child;
1298404SAndrew.W.Wilson@sun.com 
1308404SAndrew.W.Wilson@sun.com 
1318404SAndrew.W.Wilson@sun.com 	/*
1328404SAndrew.W.Wilson@sun.com 	 * nowhere to walk to if tree is empty
1338404SAndrew.W.Wilson@sun.com 	 */
1348404SAndrew.W.Wilson@sun.com 	if (node == NULL)
1358404SAndrew.W.Wilson@sun.com 		return (NULL);
1368404SAndrew.W.Wilson@sun.com 
1378404SAndrew.W.Wilson@sun.com 	/*
1388404SAndrew.W.Wilson@sun.com 	 * Visit the previous valued node. There are two possibilities:
1398404SAndrew.W.Wilson@sun.com 	 *
1408404SAndrew.W.Wilson@sun.com 	 * If this node has a left child, go down one left, then all
1418404SAndrew.W.Wilson@sun.com 	 * the way right.
1428404SAndrew.W.Wilson@sun.com 	 */
1438404SAndrew.W.Wilson@sun.com 	if (node->avl_child[left] != NULL) {
1448404SAndrew.W.Wilson@sun.com 		for (node = node->avl_child[left];
1458404SAndrew.W.Wilson@sun.com 		    node->avl_child[right] != NULL;
1468404SAndrew.W.Wilson@sun.com 		    node = node->avl_child[right])
1478404SAndrew.W.Wilson@sun.com 			;
1488404SAndrew.W.Wilson@sun.com 	/*
1498404SAndrew.W.Wilson@sun.com 	 * Otherwise, return thru left children as far as we can.
1508404SAndrew.W.Wilson@sun.com 	 */
1518404SAndrew.W.Wilson@sun.com 	} else {
1528404SAndrew.W.Wilson@sun.com 		for (;;) {
1538404SAndrew.W.Wilson@sun.com 			was_child = AVL_XCHILD(node);
1548404SAndrew.W.Wilson@sun.com 			node = AVL_XPARENT(node);
1558404SAndrew.W.Wilson@sun.com 			if (node == NULL)
1568404SAndrew.W.Wilson@sun.com 				return (NULL);
1578404SAndrew.W.Wilson@sun.com 			if (was_child == right)
1588404SAndrew.W.Wilson@sun.com 				break;
1598404SAndrew.W.Wilson@sun.com 		}
1608404SAndrew.W.Wilson@sun.com 	}
1618404SAndrew.W.Wilson@sun.com 
1628404SAndrew.W.Wilson@sun.com 	return (AVL_NODE2DATA(node, off));
1638404SAndrew.W.Wilson@sun.com }
1648404SAndrew.W.Wilson@sun.com 
1658404SAndrew.W.Wilson@sun.com /*
1668404SAndrew.W.Wilson@sun.com  * Return the lowest valued node in a tree or NULL.
1678404SAndrew.W.Wilson@sun.com  * (leftmost child from root of tree)
1688404SAndrew.W.Wilson@sun.com  */
1698404SAndrew.W.Wilson@sun.com void *
avl_first(avl_tree_t * tree)1708404SAndrew.W.Wilson@sun.com avl_first(avl_tree_t *tree)
1718404SAndrew.W.Wilson@sun.com {
1728404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
1738404SAndrew.W.Wilson@sun.com 	avl_node_t *prev = NULL;
1748404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
1758404SAndrew.W.Wilson@sun.com 
1768404SAndrew.W.Wilson@sun.com 	for (node = tree->avl_root; node != NULL; node = node->avl_child[0])
1778404SAndrew.W.Wilson@sun.com 		prev = node;
1788404SAndrew.W.Wilson@sun.com 
1798404SAndrew.W.Wilson@sun.com 	if (prev != NULL)
1808404SAndrew.W.Wilson@sun.com 		return (AVL_NODE2DATA(prev, off));
1818404SAndrew.W.Wilson@sun.com 	return (NULL);
1828404SAndrew.W.Wilson@sun.com }
1838404SAndrew.W.Wilson@sun.com 
1848404SAndrew.W.Wilson@sun.com /*
1858404SAndrew.W.Wilson@sun.com  * Return the highest valued node in a tree or NULL.
1868404SAndrew.W.Wilson@sun.com  * (rightmost child from root of tree)
1878404SAndrew.W.Wilson@sun.com  */
1888404SAndrew.W.Wilson@sun.com void *
avl_last(avl_tree_t * tree)1898404SAndrew.W.Wilson@sun.com avl_last(avl_tree_t *tree)
1908404SAndrew.W.Wilson@sun.com {
1918404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
1928404SAndrew.W.Wilson@sun.com 	avl_node_t *prev = NULL;
1938404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
1948404SAndrew.W.Wilson@sun.com 
1958404SAndrew.W.Wilson@sun.com 	for (node = tree->avl_root; node != NULL; node = node->avl_child[1])
1968404SAndrew.W.Wilson@sun.com 		prev = node;
1978404SAndrew.W.Wilson@sun.com 
1988404SAndrew.W.Wilson@sun.com 	if (prev != NULL)
1998404SAndrew.W.Wilson@sun.com 		return (AVL_NODE2DATA(prev, off));
2008404SAndrew.W.Wilson@sun.com 	return (NULL);
2018404SAndrew.W.Wilson@sun.com }
2028404SAndrew.W.Wilson@sun.com 
2038404SAndrew.W.Wilson@sun.com /*
2048404SAndrew.W.Wilson@sun.com  * Access the node immediately before or after an insertion point.
2058404SAndrew.W.Wilson@sun.com  *
2068404SAndrew.W.Wilson@sun.com  * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child
2078404SAndrew.W.Wilson@sun.com  *
2088404SAndrew.W.Wilson@sun.com  * Return value:
2098404SAndrew.W.Wilson@sun.com  *	NULL: no node in the given direction
2108404SAndrew.W.Wilson@sun.com  *	"void *"  of the found tree node
2118404SAndrew.W.Wilson@sun.com  */
2128404SAndrew.W.Wilson@sun.com void *
avl_nearest(avl_tree_t * tree,avl_index_t where,int direction)2138404SAndrew.W.Wilson@sun.com avl_nearest(avl_tree_t *tree, avl_index_t where, int direction)
2148404SAndrew.W.Wilson@sun.com {
2158404SAndrew.W.Wilson@sun.com 	int child = AVL_INDEX2CHILD(where);
2168404SAndrew.W.Wilson@sun.com 	avl_node_t *node = AVL_INDEX2NODE(where);
2178404SAndrew.W.Wilson@sun.com 	void *data;
2188404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
2198404SAndrew.W.Wilson@sun.com 
2208404SAndrew.W.Wilson@sun.com 	if (node == NULL) {
2218404SAndrew.W.Wilson@sun.com 		if (tree->avl_root != NULL)
2228404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_ERROR,
2238404SAndrew.W.Wilson@sun.com 			    "Null Node Pointer Supplied");
2248404SAndrew.W.Wilson@sun.com 		return (NULL);
2258404SAndrew.W.Wilson@sun.com 	}
2268404SAndrew.W.Wilson@sun.com 	data = AVL_NODE2DATA(node, off);
2278404SAndrew.W.Wilson@sun.com 	if (child != direction)
2288404SAndrew.W.Wilson@sun.com 		return (data);
2298404SAndrew.W.Wilson@sun.com 
2308404SAndrew.W.Wilson@sun.com 	return (avl_walk(tree, data, direction));
2318404SAndrew.W.Wilson@sun.com }
2328404SAndrew.W.Wilson@sun.com 
2338404SAndrew.W.Wilson@sun.com 
2348404SAndrew.W.Wilson@sun.com /*
2358404SAndrew.W.Wilson@sun.com  * Search for the node which contains "value".  The algorithm is a
2368404SAndrew.W.Wilson@sun.com  * simple binary tree search.
2378404SAndrew.W.Wilson@sun.com  *
2388404SAndrew.W.Wilson@sun.com  * return value:
2398404SAndrew.W.Wilson@sun.com  *	NULL: the value is not in the AVL tree
2408404SAndrew.W.Wilson@sun.com  *		*where (if not NULL)  is set to indicate the insertion point
2418404SAndrew.W.Wilson@sun.com  *	"void *"  of the found tree node
2428404SAndrew.W.Wilson@sun.com  */
2438404SAndrew.W.Wilson@sun.com void *
avl_find(avl_tree_t * tree,void * value,avl_index_t * where)2448404SAndrew.W.Wilson@sun.com avl_find(avl_tree_t *tree, void *value, avl_index_t *where)
2458404SAndrew.W.Wilson@sun.com {
2468404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
2478404SAndrew.W.Wilson@sun.com 	avl_node_t *prev = NULL;
2488404SAndrew.W.Wilson@sun.com 	int child = 0;
2498404SAndrew.W.Wilson@sun.com 	int diff;
2508404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
2518404SAndrew.W.Wilson@sun.com 
2528404SAndrew.W.Wilson@sun.com 	for (node = tree->avl_root; node != NULL;
2538404SAndrew.W.Wilson@sun.com 	    node = node->avl_child[child]) {
2548404SAndrew.W.Wilson@sun.com 
2558404SAndrew.W.Wilson@sun.com 		prev = node;
2568404SAndrew.W.Wilson@sun.com 
2578404SAndrew.W.Wilson@sun.com 		diff = tree->avl_compar(value, AVL_NODE2DATA(node, off));
2588404SAndrew.W.Wilson@sun.com 		if (!((-1 <= diff) && (diff <= 1))) {
2598404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_ERROR, "avl compare error");
2608404SAndrew.W.Wilson@sun.com 			return (NULL);
2618404SAndrew.W.Wilson@sun.com 		}
2628404SAndrew.W.Wilson@sun.com 		if (diff == 0) {
2638404SAndrew.W.Wilson@sun.com 			if (where != NULL)
2648404SAndrew.W.Wilson@sun.com 				*where = 0;
2658404SAndrew.W.Wilson@sun.com 
2668404SAndrew.W.Wilson@sun.com 			return (AVL_NODE2DATA(node, off));
2678404SAndrew.W.Wilson@sun.com 		}
2688404SAndrew.W.Wilson@sun.com 		child = avl_balance2child[1 + diff];
2698404SAndrew.W.Wilson@sun.com 
2708404SAndrew.W.Wilson@sun.com 	}
2718404SAndrew.W.Wilson@sun.com 
2728404SAndrew.W.Wilson@sun.com 	if (where != NULL)
2738404SAndrew.W.Wilson@sun.com 		*where = AVL_MKINDEX(prev, child);
2748404SAndrew.W.Wilson@sun.com 
2758404SAndrew.W.Wilson@sun.com 	return (NULL);
2768404SAndrew.W.Wilson@sun.com }
2778404SAndrew.W.Wilson@sun.com 
2788404SAndrew.W.Wilson@sun.com 
2798404SAndrew.W.Wilson@sun.com /*
2808404SAndrew.W.Wilson@sun.com  * Perform a rotation to restore balance at the subtree given by depth.
2818404SAndrew.W.Wilson@sun.com  *
2828404SAndrew.W.Wilson@sun.com  * This routine is used by both insertion and deletion. The return value
2838404SAndrew.W.Wilson@sun.com  * indicates:
2848404SAndrew.W.Wilson@sun.com  *	 0 : subtree did not change height
2858404SAndrew.W.Wilson@sun.com  *	!0 : subtree was reduced in height
2868404SAndrew.W.Wilson@sun.com  *
2878404SAndrew.W.Wilson@sun.com  * The code is written as if handling left rotations, right rotations are
2888404SAndrew.W.Wilson@sun.com  * symmetric and handled by swapping values of variables right/left[_heavy]
2898404SAndrew.W.Wilson@sun.com  *
2908404SAndrew.W.Wilson@sun.com  * On input balance is the "new" balance at "node". This value is either
2918404SAndrew.W.Wilson@sun.com  * -2 or +2.
2928404SAndrew.W.Wilson@sun.com  */
2938404SAndrew.W.Wilson@sun.com static int
avl_rotation(avl_tree_t * tree,avl_node_t * node,int balance)2948404SAndrew.W.Wilson@sun.com avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance)
2958404SAndrew.W.Wilson@sun.com {
2968404SAndrew.W.Wilson@sun.com 	int left = !(balance < 0);	/* when balance = -2, left will be 0 */
2978404SAndrew.W.Wilson@sun.com 	int right = 1 - left;
2988404SAndrew.W.Wilson@sun.com 	int left_heavy = balance >> 1;
2998404SAndrew.W.Wilson@sun.com 	int right_heavy = -left_heavy;
3008404SAndrew.W.Wilson@sun.com 	avl_node_t *parent = AVL_XPARENT(node);
3018404SAndrew.W.Wilson@sun.com 	avl_node_t *child = node->avl_child[left];
3028404SAndrew.W.Wilson@sun.com 	avl_node_t *cright;
3038404SAndrew.W.Wilson@sun.com 	avl_node_t *gchild;
3048404SAndrew.W.Wilson@sun.com 	avl_node_t *gright;
3058404SAndrew.W.Wilson@sun.com 	avl_node_t *gleft;
3068404SAndrew.W.Wilson@sun.com 	int which_child = AVL_XCHILD(node);
3078404SAndrew.W.Wilson@sun.com 	int child_bal = AVL_XBALANCE(child);
3088404SAndrew.W.Wilson@sun.com 
3098404SAndrew.W.Wilson@sun.com 	/* BEGIN CSTYLED */
3108404SAndrew.W.Wilson@sun.com 	/*
3118404SAndrew.W.Wilson@sun.com 	 * case 1 : node is overly left heavy, the left child is balanced or
3128404SAndrew.W.Wilson@sun.com 	 * also left heavy. This requires the following rotation.
3138404SAndrew.W.Wilson@sun.com 	 *
3148404SAndrew.W.Wilson@sun.com 	 *                   (node bal:-2)
3158404SAndrew.W.Wilson@sun.com 	 *                    /           \
3168404SAndrew.W.Wilson@sun.com 	 *                   /             \
3178404SAndrew.W.Wilson@sun.com 	 *              (child bal:0 or -1)
3188404SAndrew.W.Wilson@sun.com 	 *              /    \
3198404SAndrew.W.Wilson@sun.com 	 *             /      \
3208404SAndrew.W.Wilson@sun.com 	 *                     cright
3218404SAndrew.W.Wilson@sun.com 	 *
3228404SAndrew.W.Wilson@sun.com 	 * becomes:
3238404SAndrew.W.Wilson@sun.com 	 *
3248404SAndrew.W.Wilson@sun.com 	 *              (child bal:1 or 0)
3258404SAndrew.W.Wilson@sun.com 	 *              /        \
3268404SAndrew.W.Wilson@sun.com 	 *             /          \
3278404SAndrew.W.Wilson@sun.com 	 *                        (node bal:-1 or 0)
3288404SAndrew.W.Wilson@sun.com 	 *                         /     \
3298404SAndrew.W.Wilson@sun.com 	 *                        /       \
3308404SAndrew.W.Wilson@sun.com 	 *                     cright
3318404SAndrew.W.Wilson@sun.com 	 *
3328404SAndrew.W.Wilson@sun.com 	 * we detect this situation by noting that child's balance is not
3338404SAndrew.W.Wilson@sun.com 	 * right_heavy.
3348404SAndrew.W.Wilson@sun.com 	 */
3358404SAndrew.W.Wilson@sun.com 	/* END CSTYLED */
3368404SAndrew.W.Wilson@sun.com 	if (child_bal != right_heavy) {
3378404SAndrew.W.Wilson@sun.com 
3388404SAndrew.W.Wilson@sun.com 		/*
3398404SAndrew.W.Wilson@sun.com 		 * compute new balance of nodes
3408404SAndrew.W.Wilson@sun.com 		 *
3418404SAndrew.W.Wilson@sun.com 		 * If child used to be left heavy (now balanced) we reduced
3428404SAndrew.W.Wilson@sun.com 		 * the height of this sub-tree -- used in "return...;" below
3438404SAndrew.W.Wilson@sun.com 		 */
3448404SAndrew.W.Wilson@sun.com 		child_bal += right_heavy; /* adjust towards right */
3458404SAndrew.W.Wilson@sun.com 
3468404SAndrew.W.Wilson@sun.com 		/*
3478404SAndrew.W.Wilson@sun.com 		 * move "cright" to be node's left child
3488404SAndrew.W.Wilson@sun.com 		 */
3498404SAndrew.W.Wilson@sun.com 		cright = child->avl_child[right];
3508404SAndrew.W.Wilson@sun.com 		node->avl_child[left] = cright;
3518404SAndrew.W.Wilson@sun.com 		if (cright != NULL) {
3528404SAndrew.W.Wilson@sun.com 			AVL_SETPARENT(cright, node);
3538404SAndrew.W.Wilson@sun.com 			AVL_SETCHILD(cright, left);
3548404SAndrew.W.Wilson@sun.com 		}
3558404SAndrew.W.Wilson@sun.com 
3568404SAndrew.W.Wilson@sun.com 		/*
3578404SAndrew.W.Wilson@sun.com 		 * move node to be child's right child
3588404SAndrew.W.Wilson@sun.com 		 */
3598404SAndrew.W.Wilson@sun.com 		child->avl_child[right] = node;
3608404SAndrew.W.Wilson@sun.com 		AVL_SETBALANCE(node, -child_bal);
3618404SAndrew.W.Wilson@sun.com 		AVL_SETCHILD(node, right);
3628404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(node, child);
3638404SAndrew.W.Wilson@sun.com 
3648404SAndrew.W.Wilson@sun.com 		/*
3658404SAndrew.W.Wilson@sun.com 		 * update the pointer into this subtree
3668404SAndrew.W.Wilson@sun.com 		 */
3678404SAndrew.W.Wilson@sun.com 		AVL_SETBALANCE(child, child_bal);
3688404SAndrew.W.Wilson@sun.com 		AVL_SETCHILD(child, which_child);
3698404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(child, parent);
3708404SAndrew.W.Wilson@sun.com 		if (parent != NULL)
3718404SAndrew.W.Wilson@sun.com 			parent->avl_child[which_child] = child;
3728404SAndrew.W.Wilson@sun.com 		else
3738404SAndrew.W.Wilson@sun.com 			tree->avl_root = child;
3748404SAndrew.W.Wilson@sun.com 
3758404SAndrew.W.Wilson@sun.com 		return (child_bal == 0);
3768404SAndrew.W.Wilson@sun.com 	}
3778404SAndrew.W.Wilson@sun.com 
3788404SAndrew.W.Wilson@sun.com 	/* BEGIN CSTYLED */
3798404SAndrew.W.Wilson@sun.com 	/*
3808404SAndrew.W.Wilson@sun.com 	 * case 2 : When node is left heavy, but child is right heavy we use
3818404SAndrew.W.Wilson@sun.com 	 * a different rotation.
3828404SAndrew.W.Wilson@sun.com 	 *
3838404SAndrew.W.Wilson@sun.com 	 *                   (node b:-2)
3848404SAndrew.W.Wilson@sun.com 	 *                    /   \
3858404SAndrew.W.Wilson@sun.com 	 *                   /     \
3868404SAndrew.W.Wilson@sun.com 	 *                  /       \
3878404SAndrew.W.Wilson@sun.com 	 *             (child b:+1)
3888404SAndrew.W.Wilson@sun.com 	 *              /     \
3898404SAndrew.W.Wilson@sun.com 	 *             /       \
3908404SAndrew.W.Wilson@sun.com 	 *                   (gchild b: != 0)
3918404SAndrew.W.Wilson@sun.com 	 *                     /  \
3928404SAndrew.W.Wilson@sun.com 	 *                    /    \
3938404SAndrew.W.Wilson@sun.com 	 *                 gleft   gright
3948404SAndrew.W.Wilson@sun.com 	 *
3958404SAndrew.W.Wilson@sun.com 	 * becomes:
3968404SAndrew.W.Wilson@sun.com 	 *
3978404SAndrew.W.Wilson@sun.com 	 *              (gchild b:0)
3988404SAndrew.W.Wilson@sun.com 	 *              /       \
3998404SAndrew.W.Wilson@sun.com 	 *             /         \
4008404SAndrew.W.Wilson@sun.com 	 *            /           \
4018404SAndrew.W.Wilson@sun.com 	 *        (child b:?)   (node b:?)
4028404SAndrew.W.Wilson@sun.com 	 *         /  \          /   \
4038404SAndrew.W.Wilson@sun.com 	 *        /    \        /     \
4048404SAndrew.W.Wilson@sun.com 	 *            gleft   gright
4058404SAndrew.W.Wilson@sun.com 	 *
4068404SAndrew.W.Wilson@sun.com 	 * computing the new balances is more complicated. As an example:
4078404SAndrew.W.Wilson@sun.com 	 *	 if gchild was right_heavy, then child is now left heavy
4088404SAndrew.W.Wilson@sun.com 	 *		else it is balanced
4098404SAndrew.W.Wilson@sun.com 	 */
4108404SAndrew.W.Wilson@sun.com 	/* END CSTYLED */
4118404SAndrew.W.Wilson@sun.com 	gchild = child->avl_child[right];
4128404SAndrew.W.Wilson@sun.com 	gleft = gchild->avl_child[left];
4138404SAndrew.W.Wilson@sun.com 	gright = gchild->avl_child[right];
4148404SAndrew.W.Wilson@sun.com 
4158404SAndrew.W.Wilson@sun.com 	/*
4168404SAndrew.W.Wilson@sun.com 	 * move gright to left child of node and
4178404SAndrew.W.Wilson@sun.com 	 *
4188404SAndrew.W.Wilson@sun.com 	 * move gleft to right child of node
4198404SAndrew.W.Wilson@sun.com 	 */
4208404SAndrew.W.Wilson@sun.com 	node->avl_child[left] = gright;
4218404SAndrew.W.Wilson@sun.com 	if (gright != NULL) {
4228404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(gright, node);
4238404SAndrew.W.Wilson@sun.com 		AVL_SETCHILD(gright, left);
4248404SAndrew.W.Wilson@sun.com 	}
4258404SAndrew.W.Wilson@sun.com 
4268404SAndrew.W.Wilson@sun.com 	child->avl_child[right] = gleft;
4278404SAndrew.W.Wilson@sun.com 	if (gleft != NULL) {
4288404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(gleft, child);
4298404SAndrew.W.Wilson@sun.com 		AVL_SETCHILD(gleft, right);
4308404SAndrew.W.Wilson@sun.com 	}
4318404SAndrew.W.Wilson@sun.com 
4328404SAndrew.W.Wilson@sun.com 	/*
4338404SAndrew.W.Wilson@sun.com 	 * move child to left child of gchild and
4348404SAndrew.W.Wilson@sun.com 	 *
4358404SAndrew.W.Wilson@sun.com 	 * move node to right child of gchild and
4368404SAndrew.W.Wilson@sun.com 	 *
4378404SAndrew.W.Wilson@sun.com 	 * fixup parent of all this to point to gchild
4388404SAndrew.W.Wilson@sun.com 	 */
4398404SAndrew.W.Wilson@sun.com 	balance = AVL_XBALANCE(gchild);
4408404SAndrew.W.Wilson@sun.com 	gchild->avl_child[left] = child;
4418404SAndrew.W.Wilson@sun.com 	AVL_SETBALANCE(child, (balance == right_heavy ? left_heavy : 0));
4428404SAndrew.W.Wilson@sun.com 	AVL_SETPARENT(child, gchild);
4438404SAndrew.W.Wilson@sun.com 	AVL_SETCHILD(child, left);
4448404SAndrew.W.Wilson@sun.com 
4458404SAndrew.W.Wilson@sun.com 	gchild->avl_child[right] = node;
4468404SAndrew.W.Wilson@sun.com 	AVL_SETBALANCE(node, (balance == left_heavy ? right_heavy : 0));
4478404SAndrew.W.Wilson@sun.com 	AVL_SETPARENT(node, gchild);
4488404SAndrew.W.Wilson@sun.com 	AVL_SETCHILD(node, right);
4498404SAndrew.W.Wilson@sun.com 
4508404SAndrew.W.Wilson@sun.com 	AVL_SETBALANCE(gchild, 0);
4518404SAndrew.W.Wilson@sun.com 	AVL_SETPARENT(gchild, parent);
4528404SAndrew.W.Wilson@sun.com 	AVL_SETCHILD(gchild, which_child);
4538404SAndrew.W.Wilson@sun.com 	if (parent != NULL)
4548404SAndrew.W.Wilson@sun.com 		parent->avl_child[which_child] = gchild;
4558404SAndrew.W.Wilson@sun.com 	else
4568404SAndrew.W.Wilson@sun.com 		tree->avl_root = gchild;
4578404SAndrew.W.Wilson@sun.com 
4588404SAndrew.W.Wilson@sun.com 	return (1);	/* the new tree is always shorter */
4598404SAndrew.W.Wilson@sun.com }
4608404SAndrew.W.Wilson@sun.com 
4618404SAndrew.W.Wilson@sun.com 
4628404SAndrew.W.Wilson@sun.com /*
4638404SAndrew.W.Wilson@sun.com  * Insert a new node into an AVL tree at the specified (from avl_find()) place.
4648404SAndrew.W.Wilson@sun.com  *
4658404SAndrew.W.Wilson@sun.com  * Newly inserted nodes are always leaf nodes in the tree, since avl_find()
4668404SAndrew.W.Wilson@sun.com  * searches out to the leaf positions.  The avl_index_t indicates the node
4678404SAndrew.W.Wilson@sun.com  * which will be the parent of the new node.
4688404SAndrew.W.Wilson@sun.com  *
4698404SAndrew.W.Wilson@sun.com  * After the node is inserted, a single rotation further up the tree may
4708404SAndrew.W.Wilson@sun.com  * be necessary to maintain an acceptable AVL balance.
4718404SAndrew.W.Wilson@sun.com  */
4728404SAndrew.W.Wilson@sun.com void
avl_insert(avl_tree_t * tree,void * new_data,avl_index_t where)4738404SAndrew.W.Wilson@sun.com avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where)
4748404SAndrew.W.Wilson@sun.com {
4758404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
4768404SAndrew.W.Wilson@sun.com 	avl_node_t *parent = AVL_INDEX2NODE(where);
4778404SAndrew.W.Wilson@sun.com 	int old_balance;
4788404SAndrew.W.Wilson@sun.com 	int new_balance;
4798404SAndrew.W.Wilson@sun.com 	int which_child = AVL_INDEX2CHILD(where);
4808404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
4818404SAndrew.W.Wilson@sun.com 
4828404SAndrew.W.Wilson@sun.com 	if (tree == NULL) {
4838404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "No Tree Supplied");
4848404SAndrew.W.Wilson@sun.com 		return;
4858404SAndrew.W.Wilson@sun.com 	}
4868404SAndrew.W.Wilson@sun.com #ifdef _LP64
4878404SAndrew.W.Wilson@sun.com 	if (((uintptr_t)new_data & 0x7) != 0) {
4888404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "Missaligned pointer to new data");
4898404SAndrew.W.Wilson@sun.com 		return;
4908404SAndrew.W.Wilson@sun.com 	}
4918404SAndrew.W.Wilson@sun.com #endif
4928404SAndrew.W.Wilson@sun.com 
4938404SAndrew.W.Wilson@sun.com 	node = AVL_DATA2NODE(new_data, off);
4948404SAndrew.W.Wilson@sun.com 
4958404SAndrew.W.Wilson@sun.com 	/*
4968404SAndrew.W.Wilson@sun.com 	 * First, add the node to the tree at the indicated position.
4978404SAndrew.W.Wilson@sun.com 	 */
4988404SAndrew.W.Wilson@sun.com 	++tree->avl_numnodes;
4998404SAndrew.W.Wilson@sun.com 
5008404SAndrew.W.Wilson@sun.com 	node->avl_child[0] = NULL;
5018404SAndrew.W.Wilson@sun.com 	node->avl_child[1] = NULL;
5028404SAndrew.W.Wilson@sun.com 
5038404SAndrew.W.Wilson@sun.com 	AVL_SETCHILD(node, which_child);
5048404SAndrew.W.Wilson@sun.com 	AVL_SETBALANCE(node, 0);
5058404SAndrew.W.Wilson@sun.com 	AVL_SETPARENT(node, parent);
5068404SAndrew.W.Wilson@sun.com 	if (parent != NULL) {
5078404SAndrew.W.Wilson@sun.com 		if (parent->avl_child[which_child] != NULL)
5088404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
5098404SAndrew.W.Wilson@sun.com 			    "Overwriting existing pointer");
5108404SAndrew.W.Wilson@sun.com 
5118404SAndrew.W.Wilson@sun.com 		parent->avl_child[which_child] = node;
5128404SAndrew.W.Wilson@sun.com 	} else {
5138404SAndrew.W.Wilson@sun.com 		if (tree->avl_root != NULL)
5148404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
5158404SAndrew.W.Wilson@sun.com 			    "Overwriting existing pointer");
5168404SAndrew.W.Wilson@sun.com 
5178404SAndrew.W.Wilson@sun.com 		tree->avl_root = node;
5188404SAndrew.W.Wilson@sun.com 	}
5198404SAndrew.W.Wilson@sun.com 	/*
5208404SAndrew.W.Wilson@sun.com 	 * Now, back up the tree modifying the balance of all nodes above the
5218404SAndrew.W.Wilson@sun.com 	 * insertion point. If we get to a highly unbalanced ancestor, we
5228404SAndrew.W.Wilson@sun.com 	 * need to do a rotation.  If we back out of the tree we are done.
5238404SAndrew.W.Wilson@sun.com 	 * If we brought any subtree into perfect balance (0), we are also done.
5248404SAndrew.W.Wilson@sun.com 	 */
5258404SAndrew.W.Wilson@sun.com 	for (;;) {
5268404SAndrew.W.Wilson@sun.com 		node = parent;
5278404SAndrew.W.Wilson@sun.com 		if (node == NULL)
5288404SAndrew.W.Wilson@sun.com 			return;
5298404SAndrew.W.Wilson@sun.com 
5308404SAndrew.W.Wilson@sun.com 		/*
5318404SAndrew.W.Wilson@sun.com 		 * Compute the new balance
5328404SAndrew.W.Wilson@sun.com 		 */
5338404SAndrew.W.Wilson@sun.com 		old_balance = AVL_XBALANCE(node);
5348404SAndrew.W.Wilson@sun.com 		new_balance = old_balance + avl_child2balance[which_child];
5358404SAndrew.W.Wilson@sun.com 
5368404SAndrew.W.Wilson@sun.com 		/*
5378404SAndrew.W.Wilson@sun.com 		 * If we introduced equal balance, then we are done immediately
5388404SAndrew.W.Wilson@sun.com 		 */
5398404SAndrew.W.Wilson@sun.com 		if (new_balance == 0) {
5408404SAndrew.W.Wilson@sun.com 			AVL_SETBALANCE(node, 0);
5418404SAndrew.W.Wilson@sun.com 			return;
5428404SAndrew.W.Wilson@sun.com 		}
5438404SAndrew.W.Wilson@sun.com 
5448404SAndrew.W.Wilson@sun.com 		/*
5458404SAndrew.W.Wilson@sun.com 		 * If both old and new are not zero we went
5468404SAndrew.W.Wilson@sun.com 		 * from -1 to -2 balance, do a rotation.
5478404SAndrew.W.Wilson@sun.com 		 */
5488404SAndrew.W.Wilson@sun.com 		if (old_balance != 0)
5498404SAndrew.W.Wilson@sun.com 			break;
5508404SAndrew.W.Wilson@sun.com 
5518404SAndrew.W.Wilson@sun.com 		AVL_SETBALANCE(node, new_balance);
5528404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(node);
5538404SAndrew.W.Wilson@sun.com 		which_child = AVL_XCHILD(node);
5548404SAndrew.W.Wilson@sun.com 	}
5558404SAndrew.W.Wilson@sun.com 
5568404SAndrew.W.Wilson@sun.com 	/*
5578404SAndrew.W.Wilson@sun.com 	 * perform a rotation to fix the tree and return
5588404SAndrew.W.Wilson@sun.com 	 */
5598404SAndrew.W.Wilson@sun.com 	(void) avl_rotation(tree, node, new_balance);
5608404SAndrew.W.Wilson@sun.com }
5618404SAndrew.W.Wilson@sun.com 
5628404SAndrew.W.Wilson@sun.com /*
5638404SAndrew.W.Wilson@sun.com  * Insert "new_data" in "tree" in the given "direction" either after or
5648404SAndrew.W.Wilson@sun.com  * before (AVL_AFTER, AVL_BEFORE) the data "here".
5658404SAndrew.W.Wilson@sun.com  *
5668404SAndrew.W.Wilson@sun.com  * Insertions can only be done at empty leaf points in the tree, therefore
5678404SAndrew.W.Wilson@sun.com  * if the given child of the node is already present we move to either
5688404SAndrew.W.Wilson@sun.com  * the AVL_PREV or AVL_NEXT and reverse the insertion direction. Since
5698404SAndrew.W.Wilson@sun.com  * every other node in the tree is a leaf, this always works.
5708404SAndrew.W.Wilson@sun.com  *
5718404SAndrew.W.Wilson@sun.com  * To help developers using this interface, we assert that the new node
5728404SAndrew.W.Wilson@sun.com  * is correctly ordered at every step of the way in DEBUG kernels.
5738404SAndrew.W.Wilson@sun.com  */
5748404SAndrew.W.Wilson@sun.com void
avl_insert_here(avl_tree_t * tree,void * new_data,void * here,int direction)5758404SAndrew.W.Wilson@sun.com avl_insert_here(
5768404SAndrew.W.Wilson@sun.com 	avl_tree_t *tree,
5778404SAndrew.W.Wilson@sun.com 	void *new_data,
5788404SAndrew.W.Wilson@sun.com 	void *here,
5798404SAndrew.W.Wilson@sun.com 	int direction)
5808404SAndrew.W.Wilson@sun.com {
5818404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
5828404SAndrew.W.Wilson@sun.com 	int child = direction;	/* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */
5838404SAndrew.W.Wilson@sun.com 
5848404SAndrew.W.Wilson@sun.com 	if ((tree == NULL) || (new_data == NULL) || (here == NULL) ||
5858404SAndrew.W.Wilson@sun.com 	    !((direction == AVL_BEFORE) || (direction == AVL_AFTER))) {
5868404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
5878404SAndrew.W.Wilson@sun.com 		    "avl_insert_here: Bad Parameters Passed");
5888404SAndrew.W.Wilson@sun.com 		return;
5898404SAndrew.W.Wilson@sun.com 	}
5908404SAndrew.W.Wilson@sun.com 
5918404SAndrew.W.Wilson@sun.com 	/*
5928404SAndrew.W.Wilson@sun.com 	 * If corresponding child of node is not NULL, go to the neighboring
5938404SAndrew.W.Wilson@sun.com 	 * node and reverse the insertion direction.
5948404SAndrew.W.Wilson@sun.com 	 */
5958404SAndrew.W.Wilson@sun.com 	node = AVL_DATA2NODE(here, tree->avl_offset);
5968404SAndrew.W.Wilson@sun.com 
5978404SAndrew.W.Wilson@sun.com 	if (node->avl_child[child] != NULL) {
5988404SAndrew.W.Wilson@sun.com 		node = node->avl_child[child];
5998404SAndrew.W.Wilson@sun.com 		child = 1 - child;
6008404SAndrew.W.Wilson@sun.com 		while (node->avl_child[child] != NULL)
6018404SAndrew.W.Wilson@sun.com 			node = node->avl_child[child];
6028404SAndrew.W.Wilson@sun.com 
6038404SAndrew.W.Wilson@sun.com 	}
6048404SAndrew.W.Wilson@sun.com 	if (node->avl_child[child] != NULL)
6058404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_DEBUG_IMPL, "Overwriting existing pointer");
6068404SAndrew.W.Wilson@sun.com 
6078404SAndrew.W.Wilson@sun.com 	avl_insert(tree, new_data, AVL_MKINDEX(node, child));
6088404SAndrew.W.Wilson@sun.com }
6098404SAndrew.W.Wilson@sun.com 
6108404SAndrew.W.Wilson@sun.com /*
6118404SAndrew.W.Wilson@sun.com  * Add a new node to an AVL tree.
6128404SAndrew.W.Wilson@sun.com  */
6138404SAndrew.W.Wilson@sun.com void
avl_add(avl_tree_t * tree,void * new_node)6148404SAndrew.W.Wilson@sun.com avl_add(avl_tree_t *tree, void *new_node)
6158404SAndrew.W.Wilson@sun.com {
6168404SAndrew.W.Wilson@sun.com 	avl_index_t where;
6178404SAndrew.W.Wilson@sun.com 
6188404SAndrew.W.Wilson@sun.com 	/*
6198404SAndrew.W.Wilson@sun.com 	 * This is unfortunate. Give up.
6208404SAndrew.W.Wilson@sun.com 	 */
6218404SAndrew.W.Wilson@sun.com 	if (avl_find(tree, new_node, &where) != NULL) {
6228404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
6238404SAndrew.W.Wilson@sun.com 		    "Attempting to insert already inserted node");
6248404SAndrew.W.Wilson@sun.com 		return;
6258404SAndrew.W.Wilson@sun.com 	}
6268404SAndrew.W.Wilson@sun.com 	avl_insert(tree, new_node, where);
6278404SAndrew.W.Wilson@sun.com }
6288404SAndrew.W.Wilson@sun.com 
6298404SAndrew.W.Wilson@sun.com /*
6308404SAndrew.W.Wilson@sun.com  * Delete a node from the AVL tree.  Deletion is similar to insertion, but
6318404SAndrew.W.Wilson@sun.com  * with 2 complications.
6328404SAndrew.W.Wilson@sun.com  *
6338404SAndrew.W.Wilson@sun.com  * First, we may be deleting an interior node. Consider the following subtree:
6348404SAndrew.W.Wilson@sun.com  *
6358404SAndrew.W.Wilson@sun.com  *     d           c            c
6368404SAndrew.W.Wilson@sun.com  *    / \         / \          / \
6378404SAndrew.W.Wilson@sun.com  *   b   e       b   e        b   e
6388404SAndrew.W.Wilson@sun.com  *  / \	        / \          /
6398404SAndrew.W.Wilson@sun.com  * a   c       a            a
6408404SAndrew.W.Wilson@sun.com  *
6418404SAndrew.W.Wilson@sun.com  * When we are deleting node (d), we find and bring up an adjacent valued leaf
6428404SAndrew.W.Wilson@sun.com  * node, say (c), to take the interior node's place. In the code this is
6438404SAndrew.W.Wilson@sun.com  * handled by temporarily swapping (d) and (c) in the tree and then using
6448404SAndrew.W.Wilson@sun.com  * common code to delete (d) from the leaf position.
6458404SAndrew.W.Wilson@sun.com  *
6468404SAndrew.W.Wilson@sun.com  * Secondly, an interior deletion from a deep tree may require more than one
6478404SAndrew.W.Wilson@sun.com  * rotation to fix the balance. This is handled by moving up the tree through
6488404SAndrew.W.Wilson@sun.com  * parents and applying rotations as needed. The return value from
6498404SAndrew.W.Wilson@sun.com  * avl_rotation() is used to detect when a subtree did not change overall
6508404SAndrew.W.Wilson@sun.com  * height due to a rotation.
6518404SAndrew.W.Wilson@sun.com  */
6528404SAndrew.W.Wilson@sun.com void
avl_remove(avl_tree_t * tree,void * data)6538404SAndrew.W.Wilson@sun.com avl_remove(avl_tree_t *tree, void *data)
6548404SAndrew.W.Wilson@sun.com {
6558404SAndrew.W.Wilson@sun.com 	avl_node_t *delete;
6568404SAndrew.W.Wilson@sun.com 	avl_node_t *parent;
6578404SAndrew.W.Wilson@sun.com 	avl_node_t *node;
6588404SAndrew.W.Wilson@sun.com 	avl_node_t tmp;
6598404SAndrew.W.Wilson@sun.com 	int old_balance;
6608404SAndrew.W.Wilson@sun.com 	int new_balance;
6618404SAndrew.W.Wilson@sun.com 	int left;
6628404SAndrew.W.Wilson@sun.com 	int right;
6638404SAndrew.W.Wilson@sun.com 	int which_child;
6648404SAndrew.W.Wilson@sun.com 	size_t off = tree->avl_offset;
6658404SAndrew.W.Wilson@sun.com 
6668404SAndrew.W.Wilson@sun.com 	if (tree == NULL) {
6678404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "No Tree Supplied");
6688404SAndrew.W.Wilson@sun.com 		return;
6698404SAndrew.W.Wilson@sun.com 	}
6708404SAndrew.W.Wilson@sun.com 
6718404SAndrew.W.Wilson@sun.com 	delete = AVL_DATA2NODE(data, off);
6728404SAndrew.W.Wilson@sun.com 
6738404SAndrew.W.Wilson@sun.com 	/*
6748404SAndrew.W.Wilson@sun.com 	 * Deletion is easiest with a node that has at most 1 child.
6758404SAndrew.W.Wilson@sun.com 	 * We swap a node with 2 children with a sequentially valued
6768404SAndrew.W.Wilson@sun.com 	 * neighbor node. That node will have at most 1 child. Note this
6778404SAndrew.W.Wilson@sun.com 	 * has no effect on the ordering of the remaining nodes.
6788404SAndrew.W.Wilson@sun.com 	 *
6798404SAndrew.W.Wilson@sun.com 	 * As an optimization, we choose the greater neighbor if the tree
6808404SAndrew.W.Wilson@sun.com 	 * is right heavy, otherwise the left neighbor. This reduces the
6818404SAndrew.W.Wilson@sun.com 	 * number of rotations needed.
6828404SAndrew.W.Wilson@sun.com 	 */
6838404SAndrew.W.Wilson@sun.com 	if (delete->avl_child[0] != NULL && delete->avl_child[1] != NULL) {
6848404SAndrew.W.Wilson@sun.com 
6858404SAndrew.W.Wilson@sun.com 		/*
6868404SAndrew.W.Wilson@sun.com 		 * choose node to swap from whichever side is taller
6878404SAndrew.W.Wilson@sun.com 		 */
6888404SAndrew.W.Wilson@sun.com 		old_balance = AVL_XBALANCE(delete);
6898404SAndrew.W.Wilson@sun.com 		left = avl_balance2child[old_balance + 1];
6908404SAndrew.W.Wilson@sun.com 		right = 1 - left;
6918404SAndrew.W.Wilson@sun.com 
6928404SAndrew.W.Wilson@sun.com 		/*
6938404SAndrew.W.Wilson@sun.com 		 * get to the previous value'd node
6948404SAndrew.W.Wilson@sun.com 		 * (down 1 left, as far as possible right)
6958404SAndrew.W.Wilson@sun.com 		 */
6968404SAndrew.W.Wilson@sun.com 		for (node = delete->avl_child[left];
6978404SAndrew.W.Wilson@sun.com 		    node->avl_child[right] != NULL;
6988404SAndrew.W.Wilson@sun.com 		    node = node->avl_child[right])
6998404SAndrew.W.Wilson@sun.com 			;
7008404SAndrew.W.Wilson@sun.com 
7018404SAndrew.W.Wilson@sun.com 		/*
7028404SAndrew.W.Wilson@sun.com 		 * create a temp placeholder for 'node'
7038404SAndrew.W.Wilson@sun.com 		 * move 'node' to delete's spot in the tree
7048404SAndrew.W.Wilson@sun.com 		 */
7058404SAndrew.W.Wilson@sun.com 		tmp = *node;
7068404SAndrew.W.Wilson@sun.com 
7078404SAndrew.W.Wilson@sun.com 		*node = *delete;
7088404SAndrew.W.Wilson@sun.com 		if (node->avl_child[left] == node)
7098404SAndrew.W.Wilson@sun.com 			node->avl_child[left] = &tmp;
7108404SAndrew.W.Wilson@sun.com 
7118404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(node);
7128404SAndrew.W.Wilson@sun.com 		if (parent != NULL)
7138404SAndrew.W.Wilson@sun.com 			parent->avl_child[AVL_XCHILD(node)] = node;
7148404SAndrew.W.Wilson@sun.com 		else
7158404SAndrew.W.Wilson@sun.com 			tree->avl_root = node;
7168404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(node->avl_child[left], node);
7178404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(node->avl_child[right], node);
7188404SAndrew.W.Wilson@sun.com 
7198404SAndrew.W.Wilson@sun.com 		/*
7208404SAndrew.W.Wilson@sun.com 		 * Put tmp where node used to be (just temporary).
7218404SAndrew.W.Wilson@sun.com 		 * It always has a parent and at most 1 child.
7228404SAndrew.W.Wilson@sun.com 		 */
7238404SAndrew.W.Wilson@sun.com 		delete = &tmp;
7248404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(delete);
7258404SAndrew.W.Wilson@sun.com 		parent->avl_child[AVL_XCHILD(delete)] = delete;
7268404SAndrew.W.Wilson@sun.com 		which_child = (delete->avl_child[1] != 0);
7278404SAndrew.W.Wilson@sun.com 		if (delete->avl_child[which_child] != NULL)
7288404SAndrew.W.Wilson@sun.com 			AVL_SETPARENT(delete->avl_child[which_child], delete);
7298404SAndrew.W.Wilson@sun.com 	}
7308404SAndrew.W.Wilson@sun.com 
7318404SAndrew.W.Wilson@sun.com 
7328404SAndrew.W.Wilson@sun.com 	/*
7338404SAndrew.W.Wilson@sun.com 	 * Here we know "delete" is at least partially a leaf node. It can
7348404SAndrew.W.Wilson@sun.com 	 * be easily removed from the tree.
7358404SAndrew.W.Wilson@sun.com 	 */
7368404SAndrew.W.Wilson@sun.com 	if (tree->avl_numnodes == 0) {
7378404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
7388404SAndrew.W.Wilson@sun.com 		    "Deleting Node from already empty tree");
7398404SAndrew.W.Wilson@sun.com 		return;
7408404SAndrew.W.Wilson@sun.com 	}
7418404SAndrew.W.Wilson@sun.com 
7428404SAndrew.W.Wilson@sun.com 	--tree->avl_numnodes;
7438404SAndrew.W.Wilson@sun.com 	parent = AVL_XPARENT(delete);
7448404SAndrew.W.Wilson@sun.com 	which_child = AVL_XCHILD(delete);
7458404SAndrew.W.Wilson@sun.com 	if (delete->avl_child[0] != NULL)
7468404SAndrew.W.Wilson@sun.com 		node = delete->avl_child[0];
7478404SAndrew.W.Wilson@sun.com 	else
7488404SAndrew.W.Wilson@sun.com 		node = delete->avl_child[1];
7498404SAndrew.W.Wilson@sun.com 
7508404SAndrew.W.Wilson@sun.com 	/*
7518404SAndrew.W.Wilson@sun.com 	 * Connect parent directly to node (leaving out delete).
7528404SAndrew.W.Wilson@sun.com 	 */
7538404SAndrew.W.Wilson@sun.com 	if (node != NULL) {
7548404SAndrew.W.Wilson@sun.com 		AVL_SETPARENT(node, parent);
7558404SAndrew.W.Wilson@sun.com 		AVL_SETCHILD(node, which_child);
7568404SAndrew.W.Wilson@sun.com 	}
7578404SAndrew.W.Wilson@sun.com 	if (parent == NULL) {
7588404SAndrew.W.Wilson@sun.com 		tree->avl_root = node;
7598404SAndrew.W.Wilson@sun.com 		return;
7608404SAndrew.W.Wilson@sun.com 	}
7618404SAndrew.W.Wilson@sun.com 	parent->avl_child[which_child] = node;
7628404SAndrew.W.Wilson@sun.com 
7638404SAndrew.W.Wilson@sun.com 
7648404SAndrew.W.Wilson@sun.com 	/*
7658404SAndrew.W.Wilson@sun.com 	 * Since the subtree is now shorter, begin adjusting parent balances
7668404SAndrew.W.Wilson@sun.com 	 * and performing any needed rotations.
7678404SAndrew.W.Wilson@sun.com 	 */
7688404SAndrew.W.Wilson@sun.com 	do {
7698404SAndrew.W.Wilson@sun.com 
7708404SAndrew.W.Wilson@sun.com 		/*
7718404SAndrew.W.Wilson@sun.com 		 * Move up the tree and adjust the balance
7728404SAndrew.W.Wilson@sun.com 		 *
7738404SAndrew.W.Wilson@sun.com 		 * Capture the parent and which_child values for the next
7748404SAndrew.W.Wilson@sun.com 		 * iteration before any rotations occur.
7758404SAndrew.W.Wilson@sun.com 		 */
7768404SAndrew.W.Wilson@sun.com 		node = parent;
7778404SAndrew.W.Wilson@sun.com 		old_balance = AVL_XBALANCE(node);
7788404SAndrew.W.Wilson@sun.com 		new_balance = old_balance - avl_child2balance[which_child];
7798404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(node);
7808404SAndrew.W.Wilson@sun.com 		which_child = AVL_XCHILD(node);
7818404SAndrew.W.Wilson@sun.com 
7828404SAndrew.W.Wilson@sun.com 		/*
7838404SAndrew.W.Wilson@sun.com 		 * If a node was in perfect balance but isn't anymore then
7848404SAndrew.W.Wilson@sun.com 		 * we can stop, since the height didn't change above this point
7858404SAndrew.W.Wilson@sun.com 		 * due to a deletion.
7868404SAndrew.W.Wilson@sun.com 		 */
7878404SAndrew.W.Wilson@sun.com 		if (old_balance == 0) {
7888404SAndrew.W.Wilson@sun.com 			AVL_SETBALANCE(node, new_balance);
7898404SAndrew.W.Wilson@sun.com 			break;
7908404SAndrew.W.Wilson@sun.com 		}
7918404SAndrew.W.Wilson@sun.com 
7928404SAndrew.W.Wilson@sun.com 		/*
7938404SAndrew.W.Wilson@sun.com 		 * If the new balance is zero, we don't need to rotate
7948404SAndrew.W.Wilson@sun.com 		 * else
7958404SAndrew.W.Wilson@sun.com 		 * need a rotation to fix the balance.
7968404SAndrew.W.Wilson@sun.com 		 * If the rotation doesn't change the height
7978404SAndrew.W.Wilson@sun.com 		 * of the sub-tree we have finished adjusting.
7988404SAndrew.W.Wilson@sun.com 		 */
7998404SAndrew.W.Wilson@sun.com 		if (new_balance == 0)
8008404SAndrew.W.Wilson@sun.com 			AVL_SETBALANCE(node, new_balance);
8018404SAndrew.W.Wilson@sun.com 		else if (!avl_rotation(tree, node, new_balance))
8028404SAndrew.W.Wilson@sun.com 			break;
8038404SAndrew.W.Wilson@sun.com 	} while (parent != NULL);
8048404SAndrew.W.Wilson@sun.com }
8058404SAndrew.W.Wilson@sun.com 
8068404SAndrew.W.Wilson@sun.com #define	AVL_REINSERT(tree, obj)		\
8078404SAndrew.W.Wilson@sun.com 	avl_remove((tree), (obj));	\
8088404SAndrew.W.Wilson@sun.com 	avl_add((tree), (obj))
8098404SAndrew.W.Wilson@sun.com 
8108404SAndrew.W.Wilson@sun.com boolean_t
avl_update_lt(avl_tree_t * t,void * obj)8118404SAndrew.W.Wilson@sun.com avl_update_lt(avl_tree_t *t, void *obj)
8128404SAndrew.W.Wilson@sun.com {
8138404SAndrew.W.Wilson@sun.com 	void *neighbor;
8148404SAndrew.W.Wilson@sun.com 
8158404SAndrew.W.Wilson@sun.com 	if (!(((neighbor = AVL_NEXT(t, obj)) == NULL) ||
8168404SAndrew.W.Wilson@sun.com 	    (t->avl_compar(obj, neighbor) <= 0))) {
8178404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
8188404SAndrew.W.Wilson@sun.com 		    "avl_update_lt: Neighbor miss compare");
8198404SAndrew.W.Wilson@sun.com 		return (B_FALSE);
8208404SAndrew.W.Wilson@sun.com 	}
8218404SAndrew.W.Wilson@sun.com 
8228404SAndrew.W.Wilson@sun.com 	neighbor = AVL_PREV(t, obj);
8238404SAndrew.W.Wilson@sun.com 	if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) {
8248404SAndrew.W.Wilson@sun.com 		AVL_REINSERT(t, obj);
8258404SAndrew.W.Wilson@sun.com 		return (B_TRUE);
8268404SAndrew.W.Wilson@sun.com 	}
8278404SAndrew.W.Wilson@sun.com 
8288404SAndrew.W.Wilson@sun.com 	return (B_FALSE);
8298404SAndrew.W.Wilson@sun.com }
8308404SAndrew.W.Wilson@sun.com 
8318404SAndrew.W.Wilson@sun.com boolean_t
avl_update_gt(avl_tree_t * t,void * obj)8328404SAndrew.W.Wilson@sun.com avl_update_gt(avl_tree_t *t, void *obj)
8338404SAndrew.W.Wilson@sun.com {
8348404SAndrew.W.Wilson@sun.com 	void *neighbor;
8358404SAndrew.W.Wilson@sun.com 
8368404SAndrew.W.Wilson@sun.com 	if (!(((neighbor = AVL_PREV(t, obj)) == NULL) ||
8378404SAndrew.W.Wilson@sun.com 	    (t->avl_compar(obj, neighbor) >= 0))) {
8388404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
8398404SAndrew.W.Wilson@sun.com 		    "avl_update_gt: Neighbor miss compare");
8408404SAndrew.W.Wilson@sun.com 		return (B_FALSE);
8418404SAndrew.W.Wilson@sun.com 	}
8428404SAndrew.W.Wilson@sun.com 
8438404SAndrew.W.Wilson@sun.com 	neighbor = AVL_NEXT(t, obj);
8448404SAndrew.W.Wilson@sun.com 	if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) {
8458404SAndrew.W.Wilson@sun.com 		AVL_REINSERT(t, obj);
8468404SAndrew.W.Wilson@sun.com 		return (B_TRUE);
8478404SAndrew.W.Wilson@sun.com 	}
8488404SAndrew.W.Wilson@sun.com 
8498404SAndrew.W.Wilson@sun.com 	return (B_FALSE);
8508404SAndrew.W.Wilson@sun.com }
8518404SAndrew.W.Wilson@sun.com 
8528404SAndrew.W.Wilson@sun.com boolean_t
avl_update(avl_tree_t * t,void * obj)8538404SAndrew.W.Wilson@sun.com avl_update(avl_tree_t *t, void *obj)
8548404SAndrew.W.Wilson@sun.com {
8558404SAndrew.W.Wilson@sun.com 	void *neighbor;
8568404SAndrew.W.Wilson@sun.com 
8578404SAndrew.W.Wilson@sun.com 	neighbor = AVL_PREV(t, obj);
8588404SAndrew.W.Wilson@sun.com 	if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) {
8598404SAndrew.W.Wilson@sun.com 		AVL_REINSERT(t, obj);
8608404SAndrew.W.Wilson@sun.com 		return (B_TRUE);
8618404SAndrew.W.Wilson@sun.com 	}
8628404SAndrew.W.Wilson@sun.com 
8638404SAndrew.W.Wilson@sun.com 	neighbor = AVL_NEXT(t, obj);
8648404SAndrew.W.Wilson@sun.com 	if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) {
8658404SAndrew.W.Wilson@sun.com 		AVL_REINSERT(t, obj);
8668404SAndrew.W.Wilson@sun.com 		return (B_TRUE);
8678404SAndrew.W.Wilson@sun.com 	}
8688404SAndrew.W.Wilson@sun.com 
8698404SAndrew.W.Wilson@sun.com 	return (B_FALSE);
8708404SAndrew.W.Wilson@sun.com }
8718404SAndrew.W.Wilson@sun.com 
8728404SAndrew.W.Wilson@sun.com /*
8738404SAndrew.W.Wilson@sun.com  * initialize a new AVL tree
8748404SAndrew.W.Wilson@sun.com  */
8758404SAndrew.W.Wilson@sun.com void
avl_create(avl_tree_t * tree,int (* compar)(const void *,const void *),size_t size,size_t offset)8768404SAndrew.W.Wilson@sun.com avl_create(avl_tree_t *tree, int (*compar) (const void *, const void *),
8778404SAndrew.W.Wilson@sun.com     size_t size, size_t offset)
8788404SAndrew.W.Wilson@sun.com {
8798404SAndrew.W.Wilson@sun.com 	if ((tree == NULL) || (compar == NULL) || (size == 0) ||
8808404SAndrew.W.Wilson@sun.com 	    (size < (offset + sizeof (avl_node_t)))) {
8818404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR,
8828404SAndrew.W.Wilson@sun.com 		    "avl_create: Bad Parameters Passed");
8838404SAndrew.W.Wilson@sun.com 		return;
8848404SAndrew.W.Wilson@sun.com 	}
8858404SAndrew.W.Wilson@sun.com ;
8868404SAndrew.W.Wilson@sun.com #ifdef _LP64
8878404SAndrew.W.Wilson@sun.com 	if ((offset & 0x7) != 0) {
8888404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "Missaligned pointer to new data");
8898404SAndrew.W.Wilson@sun.com 		return;
8908404SAndrew.W.Wilson@sun.com 	}
8918404SAndrew.W.Wilson@sun.com #endif
8928404SAndrew.W.Wilson@sun.com 
8938404SAndrew.W.Wilson@sun.com 	tree->avl_compar = compar;
8948404SAndrew.W.Wilson@sun.com 	tree->avl_root = NULL;
8958404SAndrew.W.Wilson@sun.com 	tree->avl_numnodes = 0;
8968404SAndrew.W.Wilson@sun.com 	tree->avl_size = size;
8978404SAndrew.W.Wilson@sun.com 	tree->avl_offset = offset;
8988404SAndrew.W.Wilson@sun.com }
8998404SAndrew.W.Wilson@sun.com 
9008404SAndrew.W.Wilson@sun.com /*
9018404SAndrew.W.Wilson@sun.com  * Delete a tree.
9028404SAndrew.W.Wilson@sun.com  */
9038404SAndrew.W.Wilson@sun.com /* ARGSUSED */
9048404SAndrew.W.Wilson@sun.com void
avl_destroy(avl_tree_t * tree)9058404SAndrew.W.Wilson@sun.com avl_destroy(avl_tree_t *tree)
9068404SAndrew.W.Wilson@sun.com {
9078404SAndrew.W.Wilson@sun.com 	if ((tree == NULL) || (tree->avl_numnodes != 0) ||
9088404SAndrew.W.Wilson@sun.com 	    (tree->avl_root != NULL))
9098404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_DEBUG_IMPL, "avl_tree: Tree not destroyed");
9108404SAndrew.W.Wilson@sun.com }
9118404SAndrew.W.Wilson@sun.com 
9128404SAndrew.W.Wilson@sun.com 
9138404SAndrew.W.Wilson@sun.com /*
9148404SAndrew.W.Wilson@sun.com  * Return the number of nodes in an AVL tree.
9158404SAndrew.W.Wilson@sun.com  */
916*9513SAndrew.W.Wilson@sun.com unsigned long
avl_numnodes(avl_tree_t * tree)9178404SAndrew.W.Wilson@sun.com avl_numnodes(avl_tree_t *tree)
9188404SAndrew.W.Wilson@sun.com {
9198404SAndrew.W.Wilson@sun.com 	if (tree == NULL) {
9208404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "avl_numnodes: Null tree pointer");
9218404SAndrew.W.Wilson@sun.com 		return (0);
9228404SAndrew.W.Wilson@sun.com 	}
9238404SAndrew.W.Wilson@sun.com 	return (tree->avl_numnodes);
9248404SAndrew.W.Wilson@sun.com }
9258404SAndrew.W.Wilson@sun.com 
9268404SAndrew.W.Wilson@sun.com boolean_t
avl_is_empty(avl_tree_t * tree)9278404SAndrew.W.Wilson@sun.com avl_is_empty(avl_tree_t *tree)
9288404SAndrew.W.Wilson@sun.com {
9298404SAndrew.W.Wilson@sun.com 	if (tree == NULL) {
9308404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_ERROR, "avl_is_empty: Null tree pointer");
9318404SAndrew.W.Wilson@sun.com 		return (0);
9328404SAndrew.W.Wilson@sun.com 	}
9338404SAndrew.W.Wilson@sun.com 	return (tree->avl_numnodes == 0);
9348404SAndrew.W.Wilson@sun.com }
9358404SAndrew.W.Wilson@sun.com 
9368404SAndrew.W.Wilson@sun.com #define	CHILDBIT	(1L)
9378404SAndrew.W.Wilson@sun.com 
9388404SAndrew.W.Wilson@sun.com /*
9398404SAndrew.W.Wilson@sun.com  * Post-order tree walk used to visit all tree nodes and destroy the tree
9408404SAndrew.W.Wilson@sun.com  * in post order. This is used for destroying a tree w/o paying any cost
9418404SAndrew.W.Wilson@sun.com  * for rebalancing it.
9428404SAndrew.W.Wilson@sun.com  *
9438404SAndrew.W.Wilson@sun.com  * example:
9448404SAndrew.W.Wilson@sun.com  *
9458404SAndrew.W.Wilson@sun.com  *	void *cookie = NULL;
9468404SAndrew.W.Wilson@sun.com  *	my_data_t *node;
9478404SAndrew.W.Wilson@sun.com  *
9488404SAndrew.W.Wilson@sun.com  *	while ((node = avl_destroy_nodes(tree, &cookie)) != NULL)
9498404SAndrew.W.Wilson@sun.com  *		free(node);
9508404SAndrew.W.Wilson@sun.com  *	avl_destroy(tree);
9518404SAndrew.W.Wilson@sun.com  *
9528404SAndrew.W.Wilson@sun.com  * The cookie is really an avl_node_t to the current node's parent and
9538404SAndrew.W.Wilson@sun.com  * an indication of which child you looked at last.
9548404SAndrew.W.Wilson@sun.com  *
9558404SAndrew.W.Wilson@sun.com  * On input, a cookie value of CHILDBIT indicates the tree is done.
9568404SAndrew.W.Wilson@sun.com  */
9578404SAndrew.W.Wilson@sun.com void *
avl_destroy_nodes(avl_tree_t * tree,void ** cookie)9588404SAndrew.W.Wilson@sun.com avl_destroy_nodes(avl_tree_t *tree, void **cookie)
9598404SAndrew.W.Wilson@sun.com {
9608404SAndrew.W.Wilson@sun.com 	avl_node_t	*node;
9618404SAndrew.W.Wilson@sun.com 	avl_node_t	*parent;
9628404SAndrew.W.Wilson@sun.com 	int		child;
9638404SAndrew.W.Wilson@sun.com 	void		*first;
9648404SAndrew.W.Wilson@sun.com 	size_t		off = tree->avl_offset;
9658404SAndrew.W.Wilson@sun.com 
9668404SAndrew.W.Wilson@sun.com 	/*
9678404SAndrew.W.Wilson@sun.com 	 * Initial calls go to the first node or it's right descendant.
9688404SAndrew.W.Wilson@sun.com 	 */
9698404SAndrew.W.Wilson@sun.com 	if (*cookie == NULL) {
9708404SAndrew.W.Wilson@sun.com 		first = avl_first(tree);
9718404SAndrew.W.Wilson@sun.com 
9728404SAndrew.W.Wilson@sun.com 		/*
9738404SAndrew.W.Wilson@sun.com 		 * deal with an empty tree
9748404SAndrew.W.Wilson@sun.com 		 */
9758404SAndrew.W.Wilson@sun.com 		if (first == NULL) {
9768404SAndrew.W.Wilson@sun.com 			*cookie = (void *)CHILDBIT;
9778404SAndrew.W.Wilson@sun.com 			return (NULL);
9788404SAndrew.W.Wilson@sun.com 		}
9798404SAndrew.W.Wilson@sun.com 
9808404SAndrew.W.Wilson@sun.com 		node = AVL_DATA2NODE(first, off);
9818404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(node);
9828404SAndrew.W.Wilson@sun.com 		goto check_right_side;
9838404SAndrew.W.Wilson@sun.com 	}
9848404SAndrew.W.Wilson@sun.com 
9858404SAndrew.W.Wilson@sun.com 	/*
9868404SAndrew.W.Wilson@sun.com 	 * If there is no parent to return to we are done.
9878404SAndrew.W.Wilson@sun.com 	 */
9888404SAndrew.W.Wilson@sun.com 	parent = (avl_node_t *)((uintptr_t)(*cookie) & ~CHILDBIT);
9898404SAndrew.W.Wilson@sun.com 	if (parent == NULL) {
9908404SAndrew.W.Wilson@sun.com 		if (tree->avl_root != NULL) {
9918404SAndrew.W.Wilson@sun.com 			if (tree->avl_numnodes != 1) {
9928404SAndrew.W.Wilson@sun.com 				filebench_log(LOG_DEBUG_IMPL,
9938404SAndrew.W.Wilson@sun.com 				    "avl_destroy_nodes:"
9948404SAndrew.W.Wilson@sun.com 				    " number of nodes wrong");
9958404SAndrew.W.Wilson@sun.com 			}
9968404SAndrew.W.Wilson@sun.com 			tree->avl_root = NULL;
9978404SAndrew.W.Wilson@sun.com 			tree->avl_numnodes = 0;
9988404SAndrew.W.Wilson@sun.com 		}
9998404SAndrew.W.Wilson@sun.com 		return (NULL);
10008404SAndrew.W.Wilson@sun.com 	}
10018404SAndrew.W.Wilson@sun.com 
10028404SAndrew.W.Wilson@sun.com 	/*
10038404SAndrew.W.Wilson@sun.com 	 * Remove the child pointer we just visited from the parent and tree.
10048404SAndrew.W.Wilson@sun.com 	 */
10058404SAndrew.W.Wilson@sun.com 	child = (uintptr_t)(*cookie) & CHILDBIT;
10068404SAndrew.W.Wilson@sun.com 	parent->avl_child[child] = NULL;
10078404SAndrew.W.Wilson@sun.com 	if (tree->avl_numnodes <= 1)
10088404SAndrew.W.Wilson@sun.com 		filebench_log(LOG_DEBUG_IMPL,
10098404SAndrew.W.Wilson@sun.com 		    "avl_destroy_nodes: number of nodes wrong");
10108404SAndrew.W.Wilson@sun.com 
10118404SAndrew.W.Wilson@sun.com 	--tree->avl_numnodes;
10128404SAndrew.W.Wilson@sun.com 
10138404SAndrew.W.Wilson@sun.com 	/*
10148404SAndrew.W.Wilson@sun.com 	 * If we just did a right child or there isn't one, go up to parent.
10158404SAndrew.W.Wilson@sun.com 	 */
10168404SAndrew.W.Wilson@sun.com 	if (child == 1 || parent->avl_child[1] == NULL) {
10178404SAndrew.W.Wilson@sun.com 		node = parent;
10188404SAndrew.W.Wilson@sun.com 		parent = AVL_XPARENT(parent);
10198404SAndrew.W.Wilson@sun.com 		goto done;
10208404SAndrew.W.Wilson@sun.com 	}
10218404SAndrew.W.Wilson@sun.com 
10228404SAndrew.W.Wilson@sun.com 	/*
10238404SAndrew.W.Wilson@sun.com 	 * Do parent's right child, then leftmost descendent.
10248404SAndrew.W.Wilson@sun.com 	 */
10258404SAndrew.W.Wilson@sun.com 	node = parent->avl_child[1];
10268404SAndrew.W.Wilson@sun.com 	while (node->avl_child[0] != NULL) {
10278404SAndrew.W.Wilson@sun.com 		parent = node;
10288404SAndrew.W.Wilson@sun.com 		node = node->avl_child[0];
10298404SAndrew.W.Wilson@sun.com 	}
10308404SAndrew.W.Wilson@sun.com 
10318404SAndrew.W.Wilson@sun.com 	/*
10328404SAndrew.W.Wilson@sun.com 	 * If here, we moved to a left child. It may have one
10338404SAndrew.W.Wilson@sun.com 	 * child on the right (when balance == +1).
10348404SAndrew.W.Wilson@sun.com 	 */
10358404SAndrew.W.Wilson@sun.com check_right_side:
10368404SAndrew.W.Wilson@sun.com 	if (node->avl_child[1] != NULL) {
10378404SAndrew.W.Wilson@sun.com 		if (AVL_XBALANCE(node) != 1)
10388404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
10398404SAndrew.W.Wilson@sun.com 			    "avl_destroy_nodes: Tree inconsistency");
10408404SAndrew.W.Wilson@sun.com 		parent = node;
10418404SAndrew.W.Wilson@sun.com 		node = node->avl_child[1];
10428404SAndrew.W.Wilson@sun.com 		if (node->avl_child[0] != NULL ||
10438404SAndrew.W.Wilson@sun.com 		    node->avl_child[1] != NULL)
10448404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
10458404SAndrew.W.Wilson@sun.com 			    "avl_destroy_nodes: Destroying non leaf node");
10468404SAndrew.W.Wilson@sun.com 	} else {
10478404SAndrew.W.Wilson@sun.com 
10488404SAndrew.W.Wilson@sun.com 		if (AVL_XBALANCE(node) > 0)
10498404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
10508404SAndrew.W.Wilson@sun.com 			    "avl_destroy_nodes: Tree inconsistency");
10518404SAndrew.W.Wilson@sun.com 	}
10528404SAndrew.W.Wilson@sun.com 
10538404SAndrew.W.Wilson@sun.com done:
10548404SAndrew.W.Wilson@sun.com 	if (parent == NULL) {
10558404SAndrew.W.Wilson@sun.com 		*cookie = (void *)CHILDBIT;
10568404SAndrew.W.Wilson@sun.com 		if (node != tree->avl_root)
10578404SAndrew.W.Wilson@sun.com 			filebench_log(LOG_DEBUG_IMPL,
10588404SAndrew.W.Wilson@sun.com 			    "avl_destroy_nodes: Dangling last node");
10598404SAndrew.W.Wilson@sun.com 	} else {
10608404SAndrew.W.Wilson@sun.com 		*cookie = (void *)((uintptr_t)parent | AVL_XCHILD(node));
10618404SAndrew.W.Wilson@sun.com 	}
10628404SAndrew.W.Wilson@sun.com 
10638404SAndrew.W.Wilson@sun.com 	return (AVL_NODE2DATA(node, off));
10648404SAndrew.W.Wilson@sun.com }
1065