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

📄 rbt.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
				    FINDCALLBACK(current)) {					result = chain_name(chain,							    callback_name,							    ISC_FALSE);					if (result != ISC_R_SUCCESS) {						dns_rbtnodechain_reset(chain);						return (result);					}					result = (callback)(current,							    callback_name,							    callback_arg);					if (result != DNS_R_CONTINUE) {						saved_result = result;						/*						 * Treat this node as if it						 * had no down pointer.						 */						current = NULL;						break;					}				}				/*				 * Finally, head to the next tree level.				 */				current = DOWN(current);				current_root = current;			} else {				/*				 * Though there are labels in common, the				 * entire name at this node is not common				 * with the search name so the search				 * name does not exist in the tree.				 */				INSIST(compared == dns_namereln_commonancestor				       || compared == dns_namereln_contains);				current = NULL;			}		}	}	/*	 * If current is not NULL, NOEXACT is not disallowing exact matches,	 * and either the node has data or an empty node is ok, return	 * ISC_R_SUCCESS to indicate an exact match.	 */	if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&	    (DATA(current) != NULL ||	     (options & DNS_RBTFIND_EMPTYDATA) != 0)) {		/*		 * Found an exact match.		 */		chain->end = current;		chain->level_matches = chain->level_count;		if (foundname != NULL)			result = chain_name(chain, foundname, ISC_TRUE);		else			result = ISC_R_SUCCESS;		if (result == ISC_R_SUCCESS) {			*node = current;			result = saved_result;		} else			*node = NULL;	} else {		/*		 * Did not find an exact match (or did not want one).		 */		if (*node != NULL) {			/*			 * ... but found a partially matching superdomain.			 * Unwind the chain to the partial match node			 * to set level_matches to the level above the node,			 * and then to derive the name.			 *			 * chain->level_count is guaranteed to be at least 1			 * here because by definition of finding a superdomain,			 * the chain is pointed to at least the first subtree.			 */			chain->level_matches = chain->level_count - 1;			while (chain->levels[chain->level_matches] != *node) {				INSIST(chain->level_matches > 0);				chain->level_matches--;			}			if (foundname != NULL) {				unsigned int saved_count = chain->level_count;				chain->level_count = chain->level_matches + 1;				result = chain_name(chain, foundname,						    ISC_FALSE);				chain->level_count = saved_count;			} else				result = ISC_R_SUCCESS;			if (result == ISC_R_SUCCESS)				result = DNS_R_PARTIALMATCH;		} else			result = ISC_R_NOTFOUND;		if (current != NULL) {			/*			 * There was an exact match but either			 * DNS_RBTFIND_NOEXACT was set, or			 * DNS_RBTFIND_EMPTYDATA was set and the node had no			 * data.  A policy decision was made to set the			 * chain to the exact match, but this is subject			 * to change if it becomes apparent that something			 * else would be more useful.  It is important that			 * this case is handled here, because the predecessor			 * setting code below assumes the match was not exact.			 */			INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||			       ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&				DATA(current) == NULL));			chain->end = current;		} else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {			/*			 * Ensure the chain points nowhere.			 */			chain->end = NULL;		} else {			/*			 * Since there was no exact match, the chain argument			 * needs to be pointed at the DNSSEC predecessor of			 * the search name.			 */			if (compared == dns_namereln_subdomain) {				/*				 * Attempted to follow a down pointer that was				 * NULL, which means the searched for name was				 * a subdomain of a terminal name in the tree.				 * Since there are no existing subdomains to				 * order against, the terminal name is the				 * predecessor.				 */				INSIST(chain->level_count > 0);				INSIST(chain->level_matches <				       chain->level_count);				chain->end =					chain->levels[--chain->level_count];			} else {				isc_result_t result2;				/*				 * Point current to the node that stopped				 * the search.				 *				 * With the hashing modification that has been				 * added to the algorithm, the stop node of a				 * standard binary search is not known.  So it				 * has to be found.  There is probably a more				 * clever way of doing this.				 *				 * The assignment of current to NULL when				 * the relationship is *not* dns_namereln_none,				 * even though it later gets set to the same				 * last_compared anyway, is simply to not push				 * the while loop in one more level of				 * indentation.				 */				if (compared == dns_namereln_none)					current = last_compared;				else					current = NULL;				while (current != NULL) {					NODENAME(current, &current_name);					compared = dns_name_fullcompare(								search_name,								&current_name,								&order,								&common_labels,								&common_bits);					last_compared = current;					/*					 * Standard binary search movement.					 */					if (order < 0)						current = LEFT(current);					else						current = RIGHT(current);				}				current = last_compared;				/*				 * Reached a point within a level tree that				 * positively indicates the name is not				 * present, but the stop node could be either				 * less than the desired name (order > 0) or				 * greater than the desired name (order < 0).				 *				 * If the stop node is less, it is not				 * necessarily the predecessor.  If the stop				 * node has a down pointer, then the real				 * predecessor is at the end of a level below				 * (not necessarily the next level).				 * Move down levels until the rightmost node				 * does not have a down pointer.				 *				 * When the stop node is greater, it is				 * the successor.  All the logic for finding				 * the predecessor is handily encapsulated				 * in dns_rbtnodechain_prev.  In the event				 * that the search name is less than anything				 * else in the tree, the chain is reset.				 * XXX DCL What is the best way for the caller				 *         to know that the search name has				 *         no predecessor?				 */				if (order > 0) {					if (DOWN(current) != NULL) {						ADD_LEVEL(chain, current);						result2 =						      move_chain_to_last(chain,								DOWN(current));						if (result2 != ISC_R_SUCCESS)							result = result2;					} else						/*						 * Ah, the pure and simple						 * case.  The stop node is the						 * predecessor.						 */						chain->end = current;				} else {					INSIST(order < 0);					chain->end = current;					result2 = dns_rbtnodechain_prev(chain,									NULL,									NULL);					if (result2 == ISC_R_SUCCESS ||					    result2 == DNS_R_NEWORIGIN)						; 	/* Nothing. */					else if (result2 == ISC_R_NOMORE)						/*						 * There is no predecessor.						 */						dns_rbtnodechain_reset(chain);					else						result = result2;				}			}		}	}	return (result);}/* * Get the data pointer associated with 'name'. */isc_result_tdns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,		 dns_name_t *foundname, void **data) {	dns_rbtnode_t *node = NULL;	isc_result_t result;	REQUIRE(data != NULL && *data == NULL);	result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,				  options, NULL, NULL);	if (node != NULL &&	    (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))		*data = DATA(node);	else		result = ISC_R_NOTFOUND;	return (result);}/* * Delete a name from the tree of trees. */isc_result_tdns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {	dns_rbtnode_t *node = NULL;	isc_result_t result;	REQUIRE(VALID_RBT(rbt));	REQUIRE(dns_name_isabsolute(name));	/*	 * First, find the node.	 *	 * When searching, the name might not have an exact match:	 * consider a.b.a.com, b.b.a.com and c.b.a.com as the only	 * elements of a tree, which would make layer 1 a single	 * node tree of "b.a.com" and layer 2 a three node tree of	 * a, b, and c.  Deleting a.com would find only a partial depth	 * match in the first layer.  Should it be a requirement that	 * that the name to be deleted have data?  For now, it is.	 *	 * ->dirty, ->locknum and ->references are ignored; they are	 * solely the province of rbtdb.c.	 */	result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,				  DNS_RBTFIND_NOOPTIONS, NULL, NULL);	if (result == ISC_R_SUCCESS) {		if (DATA(node) != NULL)			result = dns_rbt_deletenode(rbt, node, recurse);		else			result = ISC_R_NOTFOUND;	} else if (result == DNS_R_PARTIALMATCH)		result = ISC_R_NOTFOUND;	return (result);}/* * Remove a node from the tree of trees. * * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing * a sequence of additions to be deletions will not generally get the * tree back to the state it started in.  For example, if the addition * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level, * then the subsequent deletion of "b.c" will not cause "a" to be pulled up, * restoring "a.b.c".  The RBT *used* to do this kind of rejoining, but it * turned out to be a bad idea because it could corrupt an active nodechain * that had "b.c" as one of its levels -- and the RBT has no idea what * nodechains are in use by callers, so it can't even *try* to helpfully * fix them up (which would probably be doomed to failure anyway). * * Similarly, it is possible to leave the tree in a state where a supposedly * deleted node still exists.  The first case of this is obvious; take * the tree which has "b.c" on one level, pointing to "a".  Now deleted "b.c". * It was just established in the previous paragraph why we can't pull "a" * back up to its parent level.  But what happens when "a" then gets deleted? * "b.c" is left hanging around without data or children.  This condition * is actually pretty easy to detect, but ... should it really be removed? * Is a chain pointing to it?  An iterator?  Who knows!  (Note that the * references structure member cannot be looked at because it is private to * rbtdb.)  This is ugly and makes me unhappy, but after hours of trying to * make it more aesthetically proper and getting nowhere, this is the way it * is going to stay until such time as it proves to be a *real* problem. * * Finally, for reference, note that the original routine that did node * joining was called join_nodes().  It has been excised, living now only * in the CVS history, but comments have been left behind that point to it just * in case someone wants to muck with this some more. * * The one positive aspect of all of this is that joining used to have a * case where it might fail.  Without trying to join, now this function always * succeeds. It still returns isc_result_t, though, so the API wouldn't change.  */isc_result_tdns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse){	dns_rbtnode_t *parent;	REQUIRE(VALID_RBT(rbt));	REQUIRE(node != NULL);	if (DOWN(node) != NULL) {		if (recurse)			dns_rbt_deletetree(rbt, DOWN(node));		else {			if (DATA(node) != NULL && rbt->data_deleter != NULL)				rbt->data_deleter(DATA(node),						  rbt->deleter_arg);			DATA(node) = NULL;			/*			 * Since there is at least one node below this one and			 * no recursion was requested, the deletion is			 * complete.  The down node from this node might be all			 * by itself on a single level, so join_nodes() could			 * be used to collapse the tree (with all the caveats			 * of the comment at the start of this function).			 */			return (ISC_R_SUCCESS);		}	}	/*	 * Note the node that points to the level of the node that is being	 * deleted.  If the deleted node is the top level, parent will be set	 * to NULL.	 */	parent = find_up(node);	/*	 * This node now has no down pointer (either because it didn't	 * have one to start, or because it was recursively removed).	 * So now the node needs to be removed from this level.	 */	dns_rbt_deletefromlevel(node, parent == NULL ? &rbt->root :						       &DOWN(parent));	if (DATA(node) != NULL && rbt->data_deleter != NULL)		rbt->data_deleter(DATA(node), rbt->deleter_arg);	unhash_node(rbt, node);	isc_mem_put(rbt->mctx, node, NODE_SIZE(node));	rbt->nodecount--;	/*	 * There are now two special cases that can exist that would	 * not have existed if the tree had been created using only	 * the names that now exist in it.  (This is all related to	 * join_nodes() as described in this function's introductory comment.)	 * Both cases exist when the deleted node's parent (the node	 * that pointed to the deleted node's level) is not null but	 * it has no data:  parent != NULL && DATA(parent) == NULL.	 *	 * The first case is that the deleted node was the last on its level:	 * DOWN(parent) == NULL.  This case can only exist if the parent was	 * previously deleted -- and so now, apparently, the parent should go	 * away.  That can't be done though because there might be external	 * references to it, such as through a nodechain.	 *	 * The other case also involves a parent with no data, but with the	 * deleted node being the next-to-last node instead of the last:	 * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.	 * Presumably now the remaining node on the level should be joined	 * with the parent, but it's already been described why that can't be	 * done.	 */	/*	 * This function never fails.	 */	return (ISC_R_SUCCESS);}voiddns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {	REQUIRE(node != NULL);	REQUIRE(name != NULL);	REQUIRE(name->offsets == NULL);	NODENAME(node, name);}isc_result_tdns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {	dns_name_t current;	isc_result_t result;	REQUIRE(node != NULL);	REQUIRE(name != NULL);	REQUIRE(name->buffer != NULL);	dns_name_init(&current, NULL);	dns_name_reset(name);	do {		INSIST(node != NULL);		NODENAME(node, &current);		result = dns_name_concatenate(name, &current, name, NULL);		if (result != ISC_R_SUCCESS)			break;				node = find_up(node);	} while (! dns_name_isabsolute(name));	return (result);}char *dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size){	dns_fixedname_t fixedname;	dns_name_t *name;	isc_result_t result;	REQUIRE(node != NULL);	REQUIRE(printname != NULL);	dns_fixedname_init(&fixedname);	name = dns_fixedname_name(&fixedname);	result = dns_rbt_fullnamefromnode(node, name);	if (result == ISC_R_SUCCESS)		dns_name_format(name, printname, size);	else		snprintf(printname, size, "<error building name: %s>",			 dns_result_totext(result));	return (printname);}static isc_result_tcreate_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {

⌨️ 快捷键说明

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