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

📄 rbt.c

📁 bind 9.3结合mysql数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
		} 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);					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;				}			}		}	}	ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));	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(DNS_RBTNODE_VALID(node));	if (DOWN(node) != NULL) {		if (recurse)			RUNTIME_CHECK(dns_rbt_deletetree(rbt, DOWN(node))				      == ISC_R_SUCCESS);		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);#if DNS_RBT_USEMAGIC	node->magic = 0;#endif	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(DNS_RBTNODE_VALID(node));	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(DNS_RBTNODE_VALID(node));	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(DNS_RBTNODE_VALID(node));	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) {	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);#if DNS_RBT_USEMAGIC	node->magic = DNS_RBTNODE_MAGIC;#endif	*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 voidrehash(dns_rbt_t *rbt) {	unsigned int oldsize;	dns_rbtnode_t **oldtable;	dns_rbtnode_t *node;	unsigned int hash;	unsigned int i;	oldsize = rbt->hashsize;	oldtable = rbt->hashtable;	rbt->hashsize *= 2 + 1;	rbt->hashtable = isc_mem_get(rbt->mctx,				     rbt->hashsize * sizeof(dns_rbtnode_t *));	if (rbt->hashtable == NULL) {		rbt->hashtable = oldtable;		rbt->hashsize = oldsize;		return;	}	for (i = 0; i < rbt->hashsize; i++)		rbt->hashtable[i] = NULL;	for (i = 0; i < oldsize; i++) {

⌨️ 快捷键说明

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