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

📄 rbtdb.c

📁 非常好的dns解析软件
💻 C
📖 第 1 页 / 共 5 页
字号:
	top->down = NULL;}static inline voidclean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {	rdatasetheader_t *current, *top_prev, *top_next;	isc_mem_t *mctx = rbtdb->common.mctx;	/*	 * Caller must be holding the node lock.	 */	top_prev = NULL;	for (current = node->data; current != NULL; current = top_next) {		top_next = current->next;		clean_stale_headers(mctx, current);		/*		 * If current is nonexistent or stale, we can clean it up.		 */		if ((current->attributes &		     (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {			if (top_prev != NULL)				top_prev->next = current->next;			else				node->data = current->next;			free_rdataset(mctx, current);		} else			top_prev = current;	}	node->dirty = 0;}static inline voidclean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,		rbtdb_serial_t least_serial){	rdatasetheader_t *current, *dcurrent, *down_next, *dparent;	rdatasetheader_t *top_prev, *top_next;	isc_mem_t *mctx = rbtdb->common.mctx;	isc_boolean_t still_dirty = ISC_FALSE;	/*	 * Caller must be holding the node lock.	 */	REQUIRE(least_serial != 0);	top_prev = NULL;	for (current = node->data; current != NULL; current = top_next) {		top_next = current->next;		/*		 * First, we clean up any instances of multiple rdatasets		 * with the same serial number, or that have the IGNORE		 * attribute.		 */		dparent = current;		for (dcurrent = current->down;		     dcurrent != NULL;		     dcurrent = down_next) {			down_next = dcurrent->down;			INSIST(dcurrent->serial <= dparent->serial);			if (dcurrent->serial == dparent->serial ||			    IGNORE(dcurrent)) {				if (down_next != NULL)					down_next->next = dparent;				dparent->down = down_next;				free_rdataset(mctx, dcurrent);			} else				dparent = dcurrent;		}		/*		 * We've now eliminated all IGNORE datasets with the possible		 * exception of current, which we now check.		 */		if (IGNORE(current)) {			down_next = current->down;			if (down_next == NULL) {				if (top_prev != NULL)					top_prev->next = current->next;				else					node->data = current->next;				free_rdataset(mctx, current);				/*				 * current no longer exists, so we can				 * just continue with the loop.				 */				continue;			} else {				/*				 * Pull up current->down, making it the new				 * current.				 */				if (top_prev != NULL)					top_prev->next = down_next;				else					node->data = down_next;				down_next->next = top_next;				free_rdataset(mctx, current);				current = down_next;			}		}		/*		 * We now try to find the first down node less than the		 * least serial.		 */		dparent = current;		for (dcurrent = current->down;		     dcurrent != NULL;		     dcurrent = down_next) {			down_next = dcurrent->down;			if (dcurrent->serial < least_serial)				break;			dparent = dcurrent;		}		/*		 * If there is a such an rdataset, delete it and any older		 * versions.		 */		if (dcurrent != NULL) {			do {				down_next = dcurrent->down;				INSIST(dcurrent->serial <= least_serial);				free_rdataset(mctx, dcurrent);				dcurrent = down_next;			} while (dcurrent != NULL);			dparent->down = NULL;		}		/*		 * Note.  The serial number of 'current' might be less than		 * least_serial too, but we cannot delete it because it is		 * the most recent version, unless it is a NONEXISTENT		 * rdataset.		 */		if (current->down != NULL) {			still_dirty = ISC_TRUE;			top_prev = current;		} else {			/*			 * If this is a NONEXISTENT rdataset, we can delete it.			 */			if (NONEXISTENT(current)) {				if (top_prev != NULL)					top_prev->next = current->next;				else					node->data = current->next;				free_rdataset(mctx, current);			} else				top_prev = current;		}	}	if (!still_dirty)		node->dirty = 0;}/* * Caller must be holding the node lock if its reference must be protected * by the lock. */static inline voidnew_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {	unsigned int lockrefs, noderefs;	isc_refcount_t *lockref;	dns_rbtnode_refincrement0(node, &noderefs);	if (noderefs == 1) {	/* this is the first reference to the node */		lockref = &rbtdb->node_locks[node->locknum].references;		isc_refcount_increment0(lockref, &lockrefs);		INSIST(lockrefs != 0);	}	INSIST(noderefs != 0);}/* * Caller must be holding the node lock; either the "strong", read or write * lock.  Note that the lock must be held even when node references are * atomically modified; in that case the decrement operation itself does not * have to be protected, but we must avoid a race condition where multiple * threads are decreasing the reference to zero simultaneously and at least * one of them is going to free the node. * This function returns ISC_TRUE if and only if the node reference decreases * to zero. */static isc_boolean_tdecrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,		    rbtdb_serial_t least_serial,		    isc_rwlocktype_t nlock, isc_rwlocktype_t tlock){	isc_result_t result;	isc_boolean_t write_locked;	rbtdb_nodelock_t *nodelock;	unsigned int refs, nrefs;	nodelock = &rbtdb->node_locks[node->locknum];	/* Handle easy and typical case first. */	if (!node->dirty && (node->data != NULL || node->down != NULL)) {		dns_rbtnode_refdecrement(node, &nrefs);		INSIST((int)nrefs >= 0);		if (nrefs == 0) {			isc_refcount_decrement(&nodelock->references, &refs);			INSIST((int)refs >= 0);		}		return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE);	}	/* Upgrade the lock? */	if (nlock == isc_rwlocktype_read) {		NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);		NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);	}	dns_rbtnode_refdecrement(node, &nrefs);	INSIST((int)nrefs >= 0);	if (nrefs > 0) {		/* Restore the lock? */		if (nlock == isc_rwlocktype_read)			NODE_WEAKDOWNGRADE(&nodelock->lock);		return (ISC_FALSE);	}	if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {		if (IS_CACHE(rbtdb))			clean_cache_node(rbtdb, node);		else {			if (least_serial == 0) {				/*				 * Caller doesn't know the least serial.				 * Get it.				 */				RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);				least_serial = rbtdb->least_serial;				RBTDB_UNLOCK(&rbtdb->lock,					     isc_rwlocktype_read);			}			clean_zone_node(rbtdb, node, least_serial);		}	}	isc_refcount_decrement(&nodelock->references, &refs);	INSIST((int)refs >= 0);	/*	 * XXXDCL should this only be done for cache zones?	 */	if (node->data != NULL || node->down != NULL) {		/* Restore the lock? */		if (nlock == isc_rwlocktype_read)			NODE_WEAKDOWNGRADE(&nodelock->lock);		return (ISC_TRUE);	}	/*	 * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.	 */	if (tlock != isc_rwlocktype_write) {		/*		 * Locking hierarchy notwithstanding, we don't need to free		 * the node lock before acquiring the tree write lock because		 * we only do a trylock.		 */		if (tlock == isc_rwlocktype_read)			result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);		else			result = isc_rwlock_trylock(&rbtdb->tree_lock,						    isc_rwlocktype_write);		RUNTIME_CHECK(result == ISC_R_SUCCESS ||			      result == ISC_R_LOCKBUSY); 		write_locked = ISC_TF(result == ISC_R_SUCCESS);	} else		write_locked = ISC_TRUE;	if (write_locked && dns_rbtnode_refcurrent(node) == 0) {		/*		 * We can now delete the node if the reference counter is		 * zero.  This should be typically the case, but a different		 * thread may still gain a (new) reference just before the		 * current thread locks the tree (e.g., in findnode()).		 */		if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {			char printname[DNS_NAME_FORMATSIZE];			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),				      "decrement_reference: "				      "delete from rbt: %p %s",				      node,				      dns_rbt_formatnodename(node, printname,							   sizeof(printname)));		}		result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);		if (result != ISC_R_SUCCESS)			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,				      "decrement_reference: "				      "dns_rbt_deletenode: %s",				      isc_result_totext(result));	}	/* Restore the lock? */	if (nlock == isc_rwlocktype_read)		NODE_WEAKDOWNGRADE(&nodelock->lock);	/*	 * Relock a read lock, or unlock the write lock if no lock was held.	 */	if (tlock == isc_rwlocktype_none)		if (write_locked)			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);	if (tlock == isc_rwlocktype_read)		if (write_locked)			isc_rwlock_downgrade(&rbtdb->tree_lock);	return (ISC_TRUE);}static inline voidmake_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,		   rbtdb_changedlist_t *cleanup_list){	/*	 * Caller must be holding the database lock.	 */	rbtdb->least_serial = version->serial;	*cleanup_list = version->changed_list;	ISC_LIST_INIT(version->changed_list);}static inline voidcleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {	rbtdb_changed_t *changed, *next_changed;	/*	 * If the changed record is dirty, then	 * an update created multiple versions of	 * a given rdataset.  We keep this list	 * until we're the least open version, at	 * which point it's safe to get rid of any	 * older versions.	 *	 * If the changed record isn't dirty, then	 * we don't need it anymore since we're	 * committing and not rolling back.	 *	 * The caller must be holding the database lock.	 */	for (changed = HEAD(version->changed_list);	     changed != NULL;	     changed = next_changed) {		next_changed = NEXT(changed, link);		if (!changed->dirty) {			UNLINK(version->changed_list,			       changed, link);			APPEND(*cleanup_list,			       changed, link);		}	}}static isc_boolean_tiszonesecure(dns_db_t *db, dns_dbnode_t *origin) {	dns_rdataset_t keyset;	dns_rdataset_t nsecset, signsecset;	isc_boolean_t haszonekey = ISC_FALSE;	isc_boolean_t hasnsec = ISC_FALSE;	isc_result_t result;	dns_rdataset_init(&keyset);	result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,				     0, &keyset, NULL);	if (result == ISC_R_SUCCESS) {		dns_rdata_t keyrdata = DNS_RDATA_INIT;		result = dns_rdataset_first(&keyset);		while (result == ISC_R_SUCCESS) {			dns_rdataset_current(&keyset, &keyrdata);			if (dns_zonekey_iszonekey(&keyrdata)) {				haszonekey = ISC_TRUE;				break;			}			result = dns_rdataset_next(&keyset);		}		dns_rdataset_disassociate(&keyset);	}	if (!haszonekey)		return (ISC_FALSE);	dns_rdataset_init(&nsecset);	dns_rdataset_init(&signsecset);	result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,				     0, &nsecset, &signsecset);	if (result == ISC_R_SUCCESS) {		if (dns_rdataset_isassociated(&signsecset)) {			hasnsec = ISC_TRUE;			dns_rdataset_disassociate(&signsecset);		}		dns_rdataset_disassociate(&nsecset);	}	return (hasnsec);}static voidcloseversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;	rbtdb_version_t *version, *cleanup_version, *least_greater;	isc_boolean_t rollback = ISC_FALSE;	rbtdb_changedlist_t cleanup_list;	rbtdb_changed_t *changed, *next_changed;	rbtdb_serial_t serial, least_serial;	dns_rbtnode_t *rbtnode;	unsigned int refs;	REQUIRE(VALID_RBTDB(rbtdb));	version = (rbtdb_version_t *)*versionp;	cleanup_version = NULL;	ISC_LIST_INIT(cleanup_list);	isc_refcount_decrement(&version->references, &refs);	if (refs > 0) {		/* typical and easy case first */		if (commit) {			RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);			INSIST(!version->writer);			RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);		}		goto end;	}	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);	serial = version->serial;	if (version->writer) {		if (commit) {			unsigned cur_ref;			rbtdb_version_t *cur_version;			INSIST(version->commit_ok);			INSIST(version == rbtdb->future_version);			/*			 * The current version is going to be replaced.			 * Release the (likely last) reference to it from the			 * DB itself and unlink it from the open list.			 */			cur_version = rbtdb->current_version;			isc_refcount_decrement(&cur_version->references,					       &cur_ref);			if (cur_ref == 0) {				if (cur_version->serial == rbtdb->least_serial)					INSIST(EMPTY(cur_version->changed_list));				UNLINK(rbtdb->open_versions,				       cur_version, link);			}			if (EMPTY(rbtdb->open_versions)) {				/*				 * We're going to become the least open				 * version.				 */				make_least_version(rbtdb, version,						   &cleanup_list);			} else {				/*				 * Some other open version is the				 * least version.  We can't cleanup				 * records that were changed in this				 * version because the older versions				 * may still be in use by an open				 * version.				 *				 * We can, however, discard the				 * changed records for things that				 * we've added that didn't exist in				 * prior versions.				 */

⌨️ 快捷键说明

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