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

📄 rbtdb.c

📁 非常好的dns解析软件
💻 C
📖 第 1 页 / 共 5 页
字号:
	isc_boolean_t			paused;	isc_boolean_t			new_origin;	isc_rwlocktype_t		tree_locked;	isc_result_t			result;	dns_fixedname_t			name;	dns_fixedname_t			origin;	dns_rbtnodechain_t		chain;	dns_rbtnode_t			*node;	dns_rbtnode_t			*deletions[DELETION_BATCH_MAX];	int				delete;} rbtdb_dbiterator_t;#define IS_STUB(rbtdb)  (((rbtdb)->common.attributes & DNS_DBATTR_STUB)  != 0)#define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,		       isc_event_t *event);/* * Locking * * If a routine is going to lock more than one lock in this module, then * the locking must be done in the following order: * *	Tree Lock * *	Node Lock	(Only one from the set may be locked at one time by *			 any caller) * *	Database Lock * * Failure to follow this hierarchy can result in deadlock. *//* * Deleting Nodes * * Currently there is no deletion of nodes from the database, except when * the database is being destroyed. * * If node deletion is added in the future, then for zone databases the node * for the origin of the zone MUST NOT be deleted. *//* * DB Routines */static voidattach(dns_db_t *source, dns_db_t **targetp) {	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;	REQUIRE(VALID_RBTDB(rbtdb));	isc_refcount_increment(&rbtdb->references, NULL);	*targetp = source;}static voidfree_rbtdb_callback(isc_task_t *task, isc_event_t *event) {	dns_rbtdb_t *rbtdb = event->ev_arg;	UNUSED(task);	free_rbtdb(rbtdb, ISC_TRUE, event);}/*% * Work out how many nodes can be deleted in the time between two * requests to the nameserver.  Smooth the resulting number and use it * as a estimate for the number of nodes to be deleted in the next * iteration. */static unsigned intadjust_quantum(unsigned int old, isc_time_t *start) {	unsigned int pps = dns_pps;	/* packets per second */	unsigned int interval;	isc_uint64_t usecs;	isc_time_t end;	unsigned int new;	if (pps < 100)		pps = 100;	isc_time_now(&end);	interval = 1000000 / pps;	/* interval in usec */	if (interval == 0)		interval = 1;	usecs = isc_time_microdiff(&end, start);	if (usecs == 0) {		/*		 * We were unable to measure the amount of time taken.		 * Double the nodes deleted next time.		 */		old *= 2;		if (old > 1000)			old = 1000;		return (old);	}	new = old * interval;	new /= (unsigned int)usecs;	if (new == 0)		new = 1;	else if (new > 1000)		new = 1000;	/* Smooth */	new = (new + old * 3) / 4;		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,		      ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);	return (new);}		static voidfree_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {	unsigned int i;	isc_ondestroy_t ondest;	isc_result_t result;	char buf[DNS_NAME_FORMATSIZE];	isc_time_t start;	REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));	REQUIRE(rbtdb->future_version == NULL);	if (rbtdb->current_version != NULL) {		unsigned int refs;		isc_refcount_decrement(&rbtdb->current_version->references,				       &refs);		INSIST(refs == 0);		UNLINK(rbtdb->open_versions, rbtdb->current_version, link);		isc_refcount_destroy(&rbtdb->current_version->references);		isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,			    sizeof(rbtdb_version_t));	}	if (event == NULL)		rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; again:	if (rbtdb->tree != NULL) {		isc_time_now(&start);		result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum);		if (result == ISC_R_QUOTA) {			INSIST(rbtdb->task != NULL);			if (rbtdb->quantum != 0)				rbtdb->quantum = adjust_quantum(rbtdb->quantum,								&start);			if (event == NULL)				event = isc_event_allocate(rbtdb->common.mctx,							   NULL,						         DNS_EVENT_FREESTORAGE,							   free_rbtdb_callback,							   rbtdb,							   sizeof(isc_event_t));			if (event == NULL)				goto again;			isc_task_send(rbtdb->task, &event);			return;		}		INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);	}	if (event != NULL)		isc_event_free(&event);	if (log) {		if (dns_name_dynamic(&rbtdb->common.origin))			dns_name_format(&rbtdb->common.origin, buf,					sizeof(buf));		else			strcpy(buf, "<UNKNOWN>");		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),			      "done free_rbtdb(%s)", buf);	}	if (dns_name_dynamic(&rbtdb->common.origin))		dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);	for (i = 0; i < rbtdb->node_lock_count; i++) {		isc_refcount_destroy(&rbtdb->node_locks[i].references);		NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);	}	isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,		    rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));	isc_rwlock_destroy(&rbtdb->tree_lock);	isc_refcount_destroy(&rbtdb->references);	if (rbtdb->task != NULL)		isc_task_detach(&rbtdb->task);	RBTDB_DESTROYLOCK(&rbtdb->lock);	rbtdb->common.magic = 0;	rbtdb->common.impmagic = 0;	ondest = rbtdb->common.ondest;	isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));	isc_ondestroy_notify(&ondest, rbtdb);}static inline voidmaybe_free_rbtdb(dns_rbtdb_t *rbtdb) {	isc_boolean_t want_free = ISC_FALSE;	unsigned int i;	unsigned int inactive = 0;	/* XXX check for open versions here */	if (rbtdb->soanode != NULL)		dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);	if (rbtdb->nsnode != NULL)		dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);	/*	 * Even though there are no external direct references, there still	 * may be nodes in use.	 */	for (i = 0; i < rbtdb->node_lock_count; i++) {		NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);		rbtdb->node_locks[i].exiting = ISC_TRUE;		NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);		if (isc_refcount_current(&rbtdb->node_locks[i].references)		    == 0) {			inactive++;		}	}	if (inactive != 0) {		RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);		rbtdb->active -= inactive;		if (rbtdb->active == 0)			want_free = ISC_TRUE;		RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);		if (want_free) {			char buf[DNS_NAME_FORMATSIZE];			if (dns_name_dynamic(&rbtdb->common.origin))				dns_name_format(&rbtdb->common.origin, buf,						sizeof(buf));			else				strcpy(buf, "<UNKNOWN>");			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,				      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),				      "calling free_rbtdb(%s)", buf);			free_rbtdb(rbtdb, ISC_TRUE, NULL);		}	}}static voiddetach(dns_db_t **dbp) {	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);	unsigned int refs;	REQUIRE(VALID_RBTDB(rbtdb));	isc_refcount_decrement(&rbtdb->references, &refs);	if (refs == 0)		maybe_free_rbtdb(rbtdb);	*dbp = NULL;}static voidcurrentversion(dns_db_t *db, dns_dbversion_t **versionp) {	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;	rbtdb_version_t *version;	unsigned int refs;	REQUIRE(VALID_RBTDB(rbtdb));	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);	version = rbtdb->current_version;	isc_refcount_increment(&version->references, &refs);	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);	*versionp = (dns_dbversion_t *)version;}static inline rbtdb_version_t *allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,		 unsigned int references, isc_boolean_t writer){	isc_result_t result;	rbtdb_version_t *version;	version = isc_mem_get(mctx, sizeof(*version));	if (version == NULL)		return (NULL);	version->serial = serial;	result = isc_refcount_init(&version->references, references);	if (result != ISC_R_SUCCESS) {		isc_mem_put(mctx, version, sizeof(*version));		return (NULL);	}	version->writer = writer;	version->commit_ok = ISC_FALSE;	ISC_LIST_INIT(version->changed_list);	ISC_LINK_INIT(version, link);	return (version);}static isc_result_tnewversion(dns_db_t *db, dns_dbversion_t **versionp) {	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;	rbtdb_version_t *version;	REQUIRE(VALID_RBTDB(rbtdb));	REQUIRE(versionp != NULL && *versionp == NULL);	REQUIRE(rbtdb->future_version == NULL);	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);	RUNTIME_CHECK(rbtdb->next_serial != 0);		/* XXX Error? */	version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,				   ISC_TRUE);	if (version != NULL) {		version->commit_ok = ISC_TRUE;		rbtdb->next_serial++;		rbtdb->future_version = version;	}	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);	if (version == NULL)		return (ISC_R_NOMEMORY);	*versionp = version;	return (ISC_R_SUCCESS);}static voidattachversion(dns_db_t *db, dns_dbversion_t *source,	      dns_dbversion_t **targetp){	dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;	rbtdb_version_t *rbtversion = source;	unsigned int refs;	REQUIRE(VALID_RBTDB(rbtdb));	isc_refcount_increment(&rbtversion->references, &refs);	INSIST(refs > 1);	*targetp = rbtversion;}static rbtdb_changed_t *add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,	    dns_rbtnode_t *node){	rbtdb_changed_t *changed;	unsigned int refs;	/*	 * Caller must be holding the node lock if its reference must be	 * protected by the lock.	 */	changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);	REQUIRE(version->writer);	if (changed != NULL) {		dns_rbtnode_refincrement(node, &refs);		INSIST(refs != 0);		changed->node = node;		changed->dirty = ISC_FALSE;		ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);	} else		version->commit_ok = ISC_FALSE;	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);	return (changed);}static voidfree_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,		 acachectl_t *array){	unsigned int count;	unsigned int i;	unsigned char *raw;	/* RDATASLAB */	/*	 * The caller must be holding the corresponding node lock.	 */	if (array == NULL)		return;	raw = (unsigned char *)header + sizeof(*header);	count = raw[0] * 256 + raw[1];	/*	 * Sanity check: since an additional cache entry has a reference to	 * the original DB node (in the callback arg), there should be no	 * acache entries when the node can be freed. 	 */	for (i = 0; i < count; i++)		INSIST(array[i].entry == NULL && array[i].cbarg == NULL);	isc_mem_put(mctx, array, count * sizeof(acachectl_t));}static inline voidfree_noqname(isc_mem_t *mctx, struct noqname **noqname) {	if (dns_name_dynamic(&(*noqname)->name))		dns_name_free(&(*noqname)->name, mctx);	if ((*noqname)->nsec != NULL)		isc_mem_put(mctx, (*noqname)->nsec,			    dns_rdataslab_size((*noqname)->nsec, 0));	if ((*noqname)->nsec != NULL)		isc_mem_put(mctx, (*noqname)->nsecsig,			    dns_rdataslab_size((*noqname)->nsecsig, 0));	isc_mem_put(mctx, *noqname, sizeof(**noqname));	*noqname = NULL;}static inline voidfree_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {	unsigned int size;	if (rdataset->noqname != NULL)		free_noqname(mctx, &rdataset->noqname);	free_acachearray(mctx, rdataset, rdataset->additional_auth);	free_acachearray(mctx, rdataset, rdataset->additional_glue);	if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)		size = sizeof(*rdataset);	else		size = dns_rdataslab_size((unsigned char *)rdataset,					  sizeof(*rdataset));	isc_mem_put(mctx, rdataset, size);}static inline voidrollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {	rdatasetheader_t *header, *dcurrent;	isc_boolean_t make_dirty = ISC_FALSE;	/*	 * Caller must hold the node lock.	 */	/*	 * We set the IGNORE attribute on rdatasets with serial number	 * 'serial'.  When the reference count goes to zero, these rdatasets	 * will be cleaned up; until that time, they will be ignored.	 */	for (header = node->data; header != NULL; header = header->next) {		if (header->serial == serial) {			header->attributes |= RDATASET_ATTR_IGNORE;			make_dirty = ISC_TRUE;		}		for (dcurrent = header->down;		     dcurrent != NULL;		     dcurrent = dcurrent->down) {			if (dcurrent->serial == serial) {				dcurrent->attributes |= RDATASET_ATTR_IGNORE;				make_dirty = ISC_TRUE;			}		}	}	if (make_dirty)		node->dirty = 1;}static inline voidclean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) {	rdatasetheader_t *d, *down_next;	for (d = top->down; d != NULL; d = down_next) {		down_next = d->down;		free_rdataset(mctx, d);	}

⌨️ 快捷键说明

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