📄 rbtdb.c
字号:
/* * 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 + -