⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rbt.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
	dns_rbtnode_t *node;	isc_region_t region;	unsigned int labels;	REQUIRE(name->offsets != NULL);	dns_name_toregion(name, &region);	labels = dns_name_countlabels(name);	ENSURE(labels > 0);	/*	 * Allocate space for the node structure, the name, and the offsets.	 */	node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) +					    region.length + labels);	if (node == NULL)		return (ISC_R_NOMEMORY);	node->is_root = 0;	PARENT(node) = NULL;	RIGHT(node) = NULL;	LEFT(node) = NULL;	DOWN(node) = NULL;	DATA(node) = NULL;#ifdef DNS_RBT_USEHASH	HASHNEXT(node) = NULL;	HASHVAL(node) = 0;#endif	LOCKNUM(node) = 0;	REFS(node) = 0;	WILD(node) = 0;	DIRTY(node) = 0;	node->find_callback = 0;	MAKE_BLACK(node);	/*	 * The following is stored to make reconstructing a name from the	 * stored value in the node easy:  the length of the name, the number	 * of labels, whether the name is absolute or not, the name itself,	 * and the name's offsets table.	 *	 * XXX RTH	 *	The offsets table could be made smaller by eliminating the	 *	first offset, which is always 0.  This requires changes to	 * 	lib/dns/name.c.	 */	NAMELEN(node) = region.length;	PADBYTES(node) = 0;	OFFSETLEN(node) = labels;	ATTRS(node) = name->attributes;	memcpy(NAME(node), region.base, region.length);	memcpy(OFFSETS(node), name->offsets, labels);	*nodep = node;	return (ISC_R_SUCCESS);}#ifdef DNS_RBT_USEHASHstatic inline voidhash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {	unsigned int hash;	compute_node_hash(node);	hash = HASHVAL(node) % rbt->hashsize;	HASHNEXT(node) = rbt->hashtable[hash];	rbt->hashtable[hash] = node;}static isc_result_tinithash(dns_rbt_t *rbt) {	unsigned int bytes;	rbt->hashsize = RBT_HASH_SIZE;	bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);	rbt->hashtable = isc_mem_get(rbt->mctx, bytes);	if (rbt->hashtable == NULL)		return (ISC_R_NOMEMORY);	memset(rbt->hashtable, 0, bytes);	return (ISC_R_SUCCESS);}static isc_result_trehash(dns_rbt_t *rbt) {	unsigned int oldsize;	dns_rbtnode_t **oldtable;	dns_rbtnode_t *node;	unsigned int hash;	unsigned int i;	oldsize = rbt->hashsize;	rbt->hashsize *= 2;	oldtable = rbt->hashtable;	rbt->hashtable = isc_mem_get(rbt->mctx,				     rbt->hashsize * sizeof(dns_rbtnode_t *));	if (rbt->hashtable == NULL)		return (ISC_R_NOMEMORY);	for (i = 0; i < rbt->hashsize; i++)		rbt->hashtable[i] = NULL;	for (i = 0; i < oldsize; i++) {		node = oldtable[i];		while (node != NULL) {			hash = HASHVAL(node) % rbt->hashsize;			oldtable[i] = HASHNEXT(node);			HASHNEXT(node) = rbt->hashtable[hash];			rbt->hashtable[hash] = node;			node = oldtable[i];		}	}	isc_mem_put(rbt->mctx, oldtable,		    rbt->hashsize * sizeof(dns_rbtnode_t *) / 2);	return (ISC_R_SUCCESS);}static inline isc_result_thash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {	isc_result_t result = ISC_R_SUCCESS;	if (rbt->hashtable == NULL)		result = inithash(rbt);	else if (rbt->nodecount >= rbt->hashsize)		result = rehash(rbt);	if (result == ISC_R_SUCCESS)		hash_add_node(rbt, node);	return (result);}static inline voidunhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {	unsigned int bucket;	dns_rbtnode_t *bucket_node;	if (rbt->hashtable != NULL) {		bucket = HASHVAL(node) % rbt->hashsize;		bucket_node = rbt->hashtable[bucket];		if (bucket_node == node)			rbt->hashtable[bucket] = HASHNEXT(node);		else {			while (HASHNEXT(bucket_node) != node) {				INSIST(HASHNEXT(bucket_node) != NULL);				bucket_node = HASHNEXT(bucket_node);			}			HASHNEXT(bucket_node) = HASHNEXT(node);		}	}}#endif /* DNS_RBT_USEHASH */static inline voidrotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {	dns_rbtnode_t *child;	REQUIRE(node != NULL);	REQUIRE(rootp != NULL);	child = RIGHT(node);	INSIST(child != NULL);	RIGHT(node) = LEFT(child);	if (LEFT(child) != NULL)		PARENT(LEFT(child)) = node;	LEFT(child) = node;	if (child != NULL)		PARENT(child) = PARENT(node);	if (IS_ROOT(node)) {		*rootp = child;		child->is_root = 1;		node->is_root = 0;	} else {		if (LEFT(PARENT(node)) == node)			LEFT(PARENT(node)) = child;		else			RIGHT(PARENT(node)) = child;	}	PARENT(node) = child;}static inline voidrotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {	dns_rbtnode_t *child;	REQUIRE(node != NULL);	REQUIRE(rootp != NULL);	child = LEFT(node);	INSIST(child != NULL);	LEFT(node) = RIGHT(child);	if (RIGHT(child) != NULL)		PARENT(RIGHT(child)) = node;	RIGHT(child) = node;	if (child != NULL)		PARENT(child) = PARENT(node);	if (IS_ROOT(node)) {		*rootp = child;		child->is_root = 1;		node->is_root = 0;	} else {		if (LEFT(PARENT(node)) == node)			LEFT(PARENT(node)) = child;		else			RIGHT(PARENT(node)) = child;	}	PARENT(node) = child;}/* * This is the real workhorse of the insertion code, because it does the * true red/black tree on a single level. */static voiddns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, 		   dns_rbtnode_t **rootp){	dns_rbtnode_t *child, *root, *parent, *grandparent;	dns_name_t add_name, current_name;	dns_offsets_t add_offsets, current_offsets;	REQUIRE(rootp != NULL);	REQUIRE(node != NULL && LEFT(node) == NULL && RIGHT(node) == NULL);	REQUIRE(current != NULL);	root = *rootp;	if (root == NULL) {		/*		 * First node of a level.		 */		MAKE_BLACK(node);		node->is_root = 1;		PARENT(node) = current;		*rootp = node;		return;	}	child = root;	dns_name_init(&add_name, add_offsets);	NODENAME(node, &add_name);	dns_name_init(&current_name, current_offsets);	NODENAME(current, &current_name);	if (order < 0) {		INSIST(LEFT(current) == NULL);		LEFT(current) = node;	} else {		INSIST(RIGHT(current) == NULL);		RIGHT(current) = node;	}	INSIST(PARENT(node) == NULL);	PARENT(node) = current;	MAKE_RED(node);	while (node != root && IS_RED(PARENT(node))) {		/*		 * XXXDCL could do away with separate parent and grandparent		 * variables.  They are vestiges of the days before parent		 * pointers.  However, they make the code a little clearer.		 */		parent = PARENT(node);		grandparent = PARENT(parent);		if (parent == LEFT(grandparent)) {			child = RIGHT(grandparent);			if (child != NULL && IS_RED(child)) {				MAKE_BLACK(parent);				MAKE_BLACK(child);				MAKE_RED(grandparent);				node = grandparent;			} else {				if (node == RIGHT(parent)) {					rotate_left(parent, &root);					node = parent;					parent = PARENT(node);					grandparent = PARENT(parent);				}				MAKE_BLACK(parent);				MAKE_RED(grandparent);				rotate_right(grandparent, &root);			}		} else {			child = LEFT(grandparent);			if (child != NULL && IS_RED(child)) {				MAKE_BLACK(parent);				MAKE_BLACK(child);				MAKE_RED(grandparent);				node = grandparent;			} else {				if (node == LEFT(parent)) {					rotate_right(parent, &root);					node = parent;					parent = PARENT(node);					grandparent = PARENT(parent);				}				MAKE_BLACK(parent);				MAKE_RED(grandparent);				rotate_left(grandparent, &root);			}		}	}	MAKE_BLACK(root);	ENSURE(IS_ROOT(root));	*rootp = root;	return;}/* * This is the real workhorse of the deletion code, because it does the * true red/black tree on a single level. */static voiddns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {	dns_rbtnode_t *child, *sibling, *parent;	dns_rbtnode_t *successor;	REQUIRE(delete != NULL);	/*	 * Verify that the parent history is (apparently) correct.	 */	INSIST((IS_ROOT(delete) && *rootp == delete) ||	       (! IS_ROOT(delete) &&		(LEFT(PARENT(delete)) == delete ||		 RIGHT(PARENT(delete)) == delete)));	child = NULL;	if (LEFT(delete) == NULL) {		if (RIGHT(delete) == NULL) {			if (IS_ROOT(delete)) {				/*				 * This is the only item in the tree.				 */				*rootp = NULL;				return;			}		} else			/*			 * This node has one child, on the right.			 */			child = RIGHT(delete);	} else if (RIGHT(delete) == NULL)		/*		 * This node has one child, on the left.		 */		child = LEFT(delete);	else {		dns_rbtnode_t holder, *tmp = &holder;		/*		 * This node has two children, so it cannot be directly		 * deleted.  Find its immediate in-order successor and		 * move it to this location, then do the deletion at the		 * old site of the successor.		 */		successor = RIGHT(delete);		while (LEFT(successor) != NULL)			successor = LEFT(successor);		/*		 * The successor cannot possibly have a left child;		 * if there is any child, it is on the right.		 */		if (RIGHT(successor) != NULL)			child = RIGHT(successor);		/* Swap the two nodes; it would be simpler to just replace		 * the value being deleted with that of the successor,		 * but this rigamarole is done so the caller has complete		 * control over the pointers (and memory allocation) of		 * all of nodes.  If just the key value were removed from		 * the tree, the pointer to the node would be unchanged.		 */		/*		 * First, put the successor in the tree location of the		 * node to be deleted.  Save its existing tree pointer		 * information, which will be needed when linking up		 * delete to the successor's old location.		 */		memcpy(tmp, successor, sizeof(dns_rbtnode_t));		if (IS_ROOT(delete)) {			*rootp = successor;			successor->is_root = ISC_TRUE;			delete->is_root = ISC_FALSE;		} else			if (LEFT(PARENT(delete)) == delete)				LEFT(PARENT(delete)) = successor;			else				RIGHT(PARENT(delete)) = successor;		PARENT(successor) = PARENT(delete);		LEFT(successor)   = LEFT(delete);		RIGHT(successor)  = RIGHT(delete);		COLOR(successor)  = COLOR(delete);		if (LEFT(successor) != NULL)			PARENT(LEFT(successor)) = successor;		if (RIGHT(successor) != successor)			PARENT(RIGHT(successor)) = successor;		/*		 * Now relink the node to be deleted into the		 * successor's previous tree location.  PARENT(tmp)		 * is the successor's original parent.		 */		INSIST(! IS_ROOT(delete));		if (PARENT(tmp) == delete) {			/*			 * Node being deleted was successor's parent.			 */			RIGHT(successor) = delete;			PARENT(delete) = successor;		} else {			LEFT(PARENT(tmp)) = delete;			PARENT(delete) = PARENT(tmp);		}		/*		 * Original location of successor node has no left.		 */		LEFT(delete)   = NULL;		RIGHT(delete)  = RIGHT(tmp);		COLOR(delete)  = COLOR(tmp);	}	/*	 * Remove the node by removing the links from its parent.	 */	if (! IS_ROOT(delete)) {		if (LEFT(PARENT(delete)) == delete)			LEFT(PARENT(delete)) = child;		else			RIGHT(PARENT(delete)) = child;		if (child != NULL)			PARENT(child) = PARENT(delete);	} else {		/*		 * This is the root being deleted, and at this point		 * it is known to have just one child.		 */		*rootp = child;		child->is_root = 1;		PARENT(child) = PARENT(delete);	}	/*	 * Fix color violations.	 */	if (IS_BLACK(delete)) {		parent = PARENT(delete);		while (child != *rootp && IS_BLACK(child)) {			INSIST(child == NULL || ! IS_ROOT(child));			if (LEFT(parent) == child) {				sibling = RIGHT(parent);				if (IS_RED(sibling)) {					MAKE_BLACK(sibling);					MAKE_RED(parent);					rotate_left(parent, rootp);					sibling = RIGHT(parent);				}				if (IS_BLACK(LEFT(sibling)) &&				    IS_BLACK(RIGHT(sibling))) {					MAKE_RED(sibling);					child = parent;				} else {					if (IS_BLACK(RIGHT(sibling))) {						MAKE_BLACK(LEFT(sibling));						MAKE_RED(sibling);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -