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

📄 rbtdb.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
static rbtdb_changed_t *add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,	    dns_rbtnode_t *node){	rbtdb_changed_t *changed;	/*	 * Caller must be holding the node lock.	 */	changed = isc_mem_get(rbtdb->common.mctx, sizeof *changed);	LOCK(&rbtdb->lock);	REQUIRE(version->writer);	if (changed != NULL) {		INSIST(node->references > 0);		node->references++;		INSIST(node->references != 0);		changed->node = node;		changed->dirty = ISC_FALSE;		ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);	} else		version->commit_ok = ISC_FALSE;	UNLOCK(&rbtdb->lock);	return (changed);}static inline voidfree_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {	unsigned int size;	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_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {	rdatasetheader_t *current, *dcurrent, *top_prev, *top_next, *down_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;		dcurrent = current->down;		if (dcurrent != NULL) {			do {				down_next = dcurrent->down;				free_rdataset(mctx, dcurrent);				dcurrent = down_next;			} while (dcurrent != NULL);			current->down = NULL;		}		/*		 * 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 ((current->attributes & RDATASET_ATTR_NONEXISTENT)			    != 0) {				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;}static inline voidnew_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {	if (node->references == 0) {		rbtdb->node_locks[node->locknum].references++;		INSIST(rbtdb->node_locks[node->locknum].references != 0);	}	node->references++;	INSIST(node->references != 0);}static voidno_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,	      rbtdb_serial_t least_serial, isc_rwlocktype_t lock){	isc_result_t result;	isc_boolean_t write_locked;	unsigned int locknum;	/*	 * Caller must be holding the node lock.	 */	REQUIRE(node->references == 0);	if (node->dirty) {		if (IS_CACHE(rbtdb))			clean_cache_node(rbtdb, node);		else {			if (least_serial == 0) {				/*				 * Caller doesn't know the least serial.				 * Get it.				 */				LOCK(&rbtdb->lock);				least_serial = rbtdb->least_serial;				UNLOCK(&rbtdb->lock);			}			clean_zone_node(rbtdb, node, least_serial);		}	}	locknum = node->locknum;	INSIST(rbtdb->node_locks[locknum].references > 0);	rbtdb->node_locks[locknum].references--;	/*	 * XXXDCL should this only be done for cache zones?	 */	if (node->data != NULL || node->down != NULL)		return;	/*	 * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.	 */	if (lock != 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 (lock == 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) {		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),				      "no_references: 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,				      "no_references: dns_rbt_deletenode: %s",				      isc_result_totext(result));	}	/*	 * Relock a read lock, or unlock the write lock if no lock was held.	 */	if (lock == isc_rwlocktype_none)		if (write_locked)			RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);	if (lock == isc_rwlocktype_read)		if (write_locked)			isc_rwlock_downgrade(&rbtdb->tree_lock);}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 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;	isc_mutex_t *lock;	REQUIRE(VALID_RBTDB(rbtdb));	version = (rbtdb_version_t *)*versionp;	cleanup_version = NULL;	ISC_LIST_INIT(cleanup_list);	LOCK(&rbtdb->lock);	INSIST(version->references > 0);	INSIST(!version->writer || !(commit && version->references > 1));	version->references--;	serial = version->serial;	if (version->references == 0) {		if (version->writer) {			if (commit) {				INSIST(version->commit_ok);				INSIST(version == rbtdb->future_version);				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.					 */					cleanup_nondirty(version,							 &cleanup_list);				}				/*				 * If the (soon to be former) current version				 * isn't being used by anyone, we can clean				 * it up.				 */				if (rbtdb->current_version->references == 0)					cleanup_version =						rbtdb->current_version;				/*				 * Become the current version.				 */				version->writer = ISC_FALSE;				rbtdb->current_version = version;				rbtdb->current_serial = version->serial;				rbtdb->future_version = NULL;			} else {				/*				 * We're rolling back this transaction.				 */				cleanup_list = version->changed_list;				rollback = ISC_TRUE;				cleanup_version = version;				rbtdb->future_version = NULL;			}		} else {			if (version != rbtdb->current_version) {				/*				 * There are no external or internal references				 * to this version and it can be cleaned up.				 */				cleanup_version = version;				/*				 * Find the version with the least serial				 * number greater than ours.				 */				least_greater = PREV(version, link);				if (least_greater == NULL)					least_greater = rbtdb->current_version;				/*				 * Is this the least open version?				 */				if (version->serial == rbtdb->least_serial) {					/*					 * Yes.  Install the new least open					 * version.					 */					make_least_version(rbtdb,							   least_greater,							   &cleanup_list);				} else {					/*					 * Add any unexecuted cleanups to					 * those of the least greater version.					 */					APPENDLIST(least_greater->changed_list,						   version->changed_list,						   link);				}			}			UNLINK(rbtdb->open_versions, version, link);		}

⌨️ 快捷键说明

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