📄 rbtdb.c
字号:
/* * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") * 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 ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC 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.196.18.41 2006/10/26 06:04:29 marka Exp $ *//*! \file *//* * Principal Author: Bob Halley */#include <config.h>#include <isc/event.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/task.h>#include <isc/time.h>#include <isc/util.h>#include <dns/acache.h>#include <dns/db.h>#include <dns/dbiterator.h>#include <dns/events.h>#include <dns/fixedname.h>#include <dns/lib.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/view.h>#include <dns/zone.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;/*% * Make casting easier in symbolic debuggers by using different names * for the 64 bit version. */#define dns_rbtdb_t dns_rbtdb64_t#define rdatasetheader_t rdatasetheader64_t#define rbtdb_version_t rbtdb_version64_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_SIGNSEC \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)#define RBTDB_RDATATYPE_SIGNS \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)#define RBTDB_RDATATYPE_SIGCNAME \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)#define RBTDB_RDATATYPE_SIGDNAME \ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)#define RBTDB_RDATATYPE_NCACHEANY \ RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)/* * We use rwlock for DB lock only when ISC_RWLOCK_USEATOMIC is non 0. * Using rwlock is effective with regard to lookup performance only when * it is implemented in an efficient way. * Otherwise, it is generally wise to stick to the simple locking since rwlock * would require more memory or can even make lookups slower due to its own * overhead (when it internally calls mutex locks). */#ifdef ISC_RWLOCK_USEATOMIC#define DNS_RBTDB_USERWLOCK 1#else#define DNS_RBTDB_USERWLOCK 0#endif#if DNS_RBTDB_USERWLOCK#define RBTDB_INITLOCK(l) isc_rwlock_init((l), 0, 0)#define RBTDB_DESTROYLOCK(l) isc_rwlock_destroy(l)#define RBTDB_LOCK(l, t) RWLOCK((l), (t))#define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t))#else#define RBTDB_INITLOCK(l) isc_mutex_init(l)#define RBTDB_DESTROYLOCK(l) DESTROYLOCK(l)#define RBTDB_LOCK(l, t) LOCK(l)#define RBTDB_UNLOCK(l, t) UNLOCK(l)#endif/* * Since node locking is sensitive to both performance and memory footprint, * we need some trick here. If we have both high-performance rwlock and * high performance and small-memory reference counters, we use rwlock for * node lock and isc_refcount for node references. In this case, we don't have * to protect the access to the counters by locks. * Otherwise, we simply use ordinary mutex lock for node locking, and use * simple integers as reference counters which is protected by the lock. * In most cases, we can simply use wrapper macros such as NODE_LOCK and * NODE_UNLOCK. In some other cases, however, we need to protect reference * counters first and then protect other parts of a node as read-only data. * Special additional macros, NODE_STRONGLOCK(), NODE_WEAKLOCK(), etc, are also * provided for these special cases. When we can use the efficient backend * routines, we should only protect the "other members" by NODE_WEAKLOCK(read). * Otherwise, we should use NODE_STRONGLOCK() to protect the entire critical * section including the access to the reference counter. * Note that we cannot use NODE_LOCK()/NODE_UNLOCK() wherever the protected * section is also protected by NODE_STRONGLOCK(). */#if defined(ISC_RWLOCK_USEATOMIC) && defined(DNS_RBT_USEISCREFCOUNT)typedef isc_rwlock_t nodelock_t;#define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0)#define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l)#define NODE_LOCK(l, t) RWLOCK((l), (t))#define NODE_UNLOCK(l, t) RWUNLOCK((l), (t))#define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l)#define NODE_STRONGLOCK(l) ((void)0)#define NODE_STRONGUNLOCK(l) ((void)0)#define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t)#define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t)#define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l)#elsetypedef isc_mutex_t nodelock_t;#define NODE_INITLOCK(l) isc_mutex_init(l)#define NODE_DESTROYLOCK(l) DESTROYLOCK(l)#define NODE_LOCK(l, t) LOCK(l)#define NODE_UNLOCK(l, t) UNLOCK(l)#define NODE_TRYUPGRADE(l) ISC_R_SUCCESS#define NODE_STRONGLOCK(l) LOCK(l)#define NODE_STRONGUNLOCK(l) UNLOCK(l)#define NODE_WEAKLOCK(l, t) ((void)0)#define NODE_WEAKUNLOCK(l, t) ((void)0)#define NODE_WEAKDOWNGRADE(l) ((void)0)#endif/* * Allow clients with a virtual time of upto 5 minutes in the past to see * records that would have otherwise have expired. */#define RBTDB_VIRTUAL 300struct noqname { dns_name_t name; void * nsec; void * nsecsig;};typedef struct acachectl acachectl_t; 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; struct noqname *noqname; /*%< * We don't use the LIST macros, because the LIST structure has * both head and tail pointers, and is doubly linked. */ struct rdatasetheader *next; /*%< * If this is the top header for an rdataset, 'next' points * to the top header for the next rdataset (i.e., the next type). * Otherwise, it points up to the header whose down pointer points * at this header. */ struct rdatasetheader *down; /*%< * Points to the header for the next older version of * this rdataset. */ isc_uint32_t count; /*%< * Monotonously increased every time this rdataset is bound so that * it is used as the base of the starting point in DNS responses * when the "cyclic" rrset-order is required. Since the ordering * should not be so crucial, no lock is set for the counter for * performance reasons. */ acachectl_t *additional_auth; acachectl_t *additional_glue;} 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 0x0010typedef struct acache_cbarg { dns_rdatasetadditional_t type; unsigned int count; dns_db_t *db; dns_dbnode_t *node; rdatasetheader_t *header;} acache_cbarg_t;struct acachectl { dns_acacheentry_t *entry; acache_cbarg_t *cbarg;};/* * 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. */#define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */typedef struct { nodelock_t lock; /* Protected in the refcount routines. */ isc_refcount_t references; /* Locked by lock. */ 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; /* * Protected in the refcount routines. * XXXJT: should we change the lock policy based on the refcount * performance? */ isc_refcount_t references; /* Locked by database lock. */ isc_boolean_t writer; 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;#if DNS_RBTDB_USERWLOCK isc_rwlock_t lock;#else isc_mutex_t lock;#endif 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; isc_task_t * task; dns_dbnode_t *soanode; dns_dbnode_t *nsnode; /* Locked by tree_lock. */ dns_rbt_t * tree; isc_boolean_t secure; /* Unlocked */ unsigned int quantum;} 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 isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype, dns_acache_t *acache, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, dns_dbnode_t **nodep, dns_name_t *fname, dns_message_t *msg, isc_stdtime_t now);static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype, dns_acache_t *acache, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, dns_name_t *fname);static isc_result_t rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, dns_rdatatype_t qtype);static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate, rdataset_first, rdataset_next, rdataset_current, rdataset_clone, rdataset_count, NULL, rdataset_getnoqname, rdataset_getadditional, rdataset_setadditional, rdataset_putadditional};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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -