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

📄 rbtdb.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (C) 1999-2003  Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* $Id: rbtdb.c,v 1.168.2.13 2003/10/17 05:39:44 marka Exp $ *//* * Principal Author: Bob Halley */#include <config.h>#include <isc/mem.h>#include <isc/print.h>#include <isc/mutex.h>#include <isc/random.h>#include <isc/refcount.h>#include <isc/rwlock.h>#include <isc/string.h>#include <isc/util.h>#include <dns/db.h>#include <dns/dbiterator.h>#include <dns/fixedname.h>#include <dns/log.h>#include <dns/masterdump.h>#include <dns/rbt.h>#include <dns/rdata.h>#include <dns/rdataset.h>#include <dns/rdatasetiter.h>#include <dns/rdataslab.h>#include <dns/result.h>#include <dns/zonekey.h>#ifdef DNS_RBTDB_VERSION64#include "rbtdb64.h"#else#include "rbtdb.h"#endif#ifdef DNS_RBTDB_VERSION64#define RBTDB_MAGIC			ISC_MAGIC('R', 'B', 'D', '8')#else#define RBTDB_MAGIC			ISC_MAGIC('R', 'B', 'D', '4')#endif/* * Note that "impmagic" is not the first four bytes of the struct, so * ISC_MAGIC_VALID cannot be used. */#define VALID_RBTDB(rbtdb)	((rbtdb) != NULL && \				 (rbtdb)->common.impmagic == RBTDB_MAGIC)#ifdef DNS_RBTDB_VERSION64typedef isc_uint64_t			rbtdb_serial_t;#elsetypedef isc_uint32_t			rbtdb_serial_t;#endiftypedef isc_uint32_t			rbtdb_rdatatype_t;#define RBTDB_RDATATYPE_BASE(type)	((dns_rdatatype_t)((type) & 0xFFFF))#define RBTDB_RDATATYPE_EXT(type)	((dns_rdatatype_t)((type) >> 16))#define RBTDB_RDATATYPE_VALUE(b, e)	(((e) << 16) | (b))#define RBTDB_RDATATYPE_SIGNXT \		RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_nxt)#define RBTDB_RDATATYPE_SIGNS \		RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_ns)#define RBTDB_RDATATYPE_SIGCNAME \		RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_cname)#define RBTDB_RDATATYPE_SIGDNAME \		RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_dname)#define RBTDB_RDATATYPE_NCACHEANY \		RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)typedef struct rdatasetheader {	/*	 * Locked by the owning node's lock.	 */	rbtdb_serial_t			serial;	dns_ttl_t			ttl;	rbtdb_rdatatype_t		type;	isc_uint16_t			attributes;	dns_trust_t			trust;	/*	 * We don't use the LIST macros, because the LIST structure has	 * both head and tail pointers, and is doubly linked.	 */	struct rdatasetheader		*next;	struct rdatasetheader		*down;} rdatasetheader_t;#define RDATASET_ATTR_NONEXISTENT	0x0001#define RDATASET_ATTR_STALE		0x0002#define RDATASET_ATTR_IGNORE		0x0004#define RDATASET_ATTR_RETAIN		0x0008#define RDATASET_ATTR_NXDOMAIN		0x0010/* * XXX * When the cache will pre-expire data (due to memory low or other * situations) before the rdataset's TTL has expired, it MUST * respect the RETAIN bit and not expire the data until its TTL is * expired. */#undef IGNORE			/* WIN32 winbase.h defines this. */#define EXISTS(header) \	(((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)#define NONEXISTENT(header) \	(((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)#define IGNORE(header) \	(((header)->attributes & RDATASET_ATTR_IGNORE) != 0)#define RETAIN(header) \	(((header)->attributes & RDATASET_ATTR_RETAIN) != 0)#define NXDOMAIN(header) \	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)#define DEFAULT_NODE_LOCK_COUNT		7		/* Should be prime. */typedef struct {	isc_mutex_t			lock;	/* Locked by lock. */	unsigned int			references;	isc_boolean_t			exiting;} rbtdb_nodelock_t;typedef struct rbtdb_changed {	dns_rbtnode_t *			node;	isc_boolean_t			dirty;	ISC_LINK(struct rbtdb_changed)	link;} rbtdb_changed_t;typedef ISC_LIST(rbtdb_changed_t)	rbtdb_changedlist_t;typedef struct rbtdb_version {	/* Not locked */	rbtdb_serial_t			serial;	/* Locked by database lock. */	isc_boolean_t			writer;	unsigned int			references;	isc_boolean_t			commit_ok;	rbtdb_changedlist_t		changed_list;	ISC_LINK(struct rbtdb_version)	link;} rbtdb_version_t;typedef ISC_LIST(rbtdb_version_t)	rbtdb_versionlist_t;typedef struct {	/* Unlocked. */	dns_db_t			common;	isc_mutex_t			lock;	isc_rwlock_t			tree_lock;	unsigned int			node_lock_count;	rbtdb_nodelock_t *	       	node_locks;	dns_rbtnode_t *			origin_node;	/* Locked by lock. */	unsigned int			active;	isc_refcount_t			references;	unsigned int			attributes;	rbtdb_serial_t			current_serial;	rbtdb_serial_t			least_serial;	rbtdb_serial_t			next_serial;	rbtdb_version_t *		current_version;	rbtdb_version_t *		future_version;	rbtdb_versionlist_t		open_versions;	isc_boolean_t			overmem;	/* Locked by tree_lock. */	dns_rbt_t *			tree;	isc_boolean_t			secure;} dns_rbtdb_t;#define RBTDB_ATTR_LOADED		0x01#define RBTDB_ATTR_LOADING		0x02/* * Search Context */typedef struct {	dns_rbtdb_t *		rbtdb;	rbtdb_version_t *	rbtversion;	rbtdb_serial_t		serial;	unsigned int		options;	dns_rbtnodechain_t	chain;	isc_boolean_t		copy_name;	isc_boolean_t		need_cleanup;	isc_boolean_t		wild;	dns_rbtnode_t *	       	zonecut;	rdatasetheader_t *	zonecut_rdataset;	rdatasetheader_t *	zonecut_sigrdataset;	dns_fixedname_t		zonecut_name;	isc_stdtime_t		now;} rbtdb_search_t;/* * Load Context */typedef struct {	dns_rbtdb_t *		rbtdb;	isc_stdtime_t		now;} rbtdb_load_t;static void rdataset_disassociate(dns_rdataset_t *rdataset);static isc_result_t rdataset_first(dns_rdataset_t *rdataset);static isc_result_t rdataset_next(dns_rdataset_t *rdataset);static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);static unsigned int rdataset_count(dns_rdataset_t *rdataset);static dns_rdatasetmethods_t rdataset_methods = {	rdataset_disassociate,	rdataset_first,	rdataset_next,	rdataset_current,	rdataset_clone,	rdataset_count};static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);static void rdatasetiter_current(dns_rdatasetiter_t *iterator,				 dns_rdataset_t *rdataset);static dns_rdatasetitermethods_t rdatasetiter_methods = {	rdatasetiter_destroy,	rdatasetiter_first,	rdatasetiter_next,	rdatasetiter_current};typedef struct rbtdb_rdatasetiter {	dns_rdatasetiter_t		common;	rdatasetheader_t *		current;} rbtdb_rdatasetiter_t;static void		dbiterator_destroy(dns_dbiterator_t **iteratorp);static isc_result_t	dbiterator_first(dns_dbiterator_t *iterator);static isc_result_t	dbiterator_last(dns_dbiterator_t *iterator);static isc_result_t	dbiterator_seek(dns_dbiterator_t *iterator,					dns_name_t *name);static isc_result_t	dbiterator_prev(dns_dbiterator_t *iterator);static isc_result_t	dbiterator_next(dns_dbiterator_t *iterator);static isc_result_t	dbiterator_current(dns_dbiterator_t *iterator,					   dns_dbnode_t **nodep,					   dns_name_t *name);static isc_result_t	dbiterator_pause(dns_dbiterator_t *iterator);static isc_result_t	dbiterator_origin(dns_dbiterator_t *iterator,					  dns_name_t *name);static dns_dbiteratormethods_t dbiterator_methods = {	dbiterator_destroy,	dbiterator_first,	dbiterator_last,	dbiterator_seek,	dbiterator_prev,	dbiterator_next,	dbiterator_current,	dbiterator_pause,	dbiterator_origin};#define DELETION_BATCH_MAX 64/* * If 'paused' is ISC_TRUE, then the tree lock is not being held. */typedef struct rbtdb_dbiterator {	dns_dbiterator_t		common;	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)/* * 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(dns_rbtdb_t *rbtdb) {	unsigned int i;	isc_ondestroy_t ondest;	isc_mem_t *mctx;	REQUIRE(EMPTY(rbtdb->open_versions));	REQUIRE(rbtdb->future_version == NULL);	if (rbtdb->current_version != NULL)		isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,			    sizeof (rbtdb_version_t));	if (dns_name_dynamic(&rbtdb->common.origin))		dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);	if (rbtdb->tree != NULL)		dns_rbt_destroy(&rbtdb->tree);	for (i = 0; i < rbtdb->node_lock_count; i++)		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);	DESTROYLOCK(&rbtdb->lock);	rbtdb->common.magic = 0;	rbtdb->common.impmagic = 0;	ondest = rbtdb->common.ondest;	mctx = rbtdb->common.mctx;	isc_mem_put(mctx, rbtdb, sizeof *rbtdb);	isc_mem_detach(&mctx);	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 */	/*	 * Even though there are no external direct references, there still	 * may be nodes in use.	 */	for (i = 0; i < rbtdb->node_lock_count; i++) {		LOCK(&rbtdb->node_locks[i].lock);		rbtdb->node_locks[i].exiting = ISC_TRUE;		if (rbtdb->node_locks[i].references == 0)			inactive++;		UNLOCK(&rbtdb->node_locks[i].lock);	}	if (inactive != 0) {		LOCK(&rbtdb->lock);		rbtdb->active -= inactive;		if (rbtdb->active == 0)			want_free = ISC_TRUE;		UNLOCK(&rbtdb->lock);		if (want_free)			free_rbtdb(rbtdb);	}}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;	REQUIRE(VALID_RBTDB(rbtdb));	LOCK(&rbtdb->lock);	version = rbtdb->current_version;	if (version->references == 0)		PREPEND(rbtdb->open_versions, version, link);	version->references++;	UNLOCK(&rbtdb->lock);	*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){	rbtdb_version_t *version;	version = isc_mem_get(mctx, sizeof *version);	if (version == NULL)		return (NULL);	version->serial = serial;	version->references = references;	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);	LOCK(&rbtdb->lock);	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;	}	UNLOCK(&rbtdb->lock);	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;	REQUIRE(VALID_RBTDB(rbtdb));	LOCK(&rbtdb->lock);	INSIST(rbtversion->references > 0);	rbtversion->references++;	INSIST(rbtversion->references != 0);	UNLOCK(&rbtdb->lock);	*targetp = rbtversion;}

⌨️ 快捷键说明

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