Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / dbtable.c
blobe814722dc77268dbb711edd0b09d118294e8db3c
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
19 * $Id: dbtable.c,v 1.25.2.2 2004/04/15 01:38:06 marka Exp $
23 * Principal Author: DCL
26 #include <config.h>
28 #include <isc/mem.h>
29 #include <isc/rwlock.h>
30 #include <isc/util.h>
32 #include <dns/dbtable.h>
33 #include <dns/db.h>
34 #include <dns/rbt.h>
35 #include <dns/result.h>
37 struct dns_dbtable {
38 /* Unlocked. */
39 unsigned int magic;
40 isc_mem_t * mctx;
41 dns_rdataclass_t rdclass;
42 isc_mutex_t lock;
43 isc_rwlock_t tree_lock;
44 /* Locked by lock. */
45 unsigned int references;
46 /* Locked by tree_lock. */
47 dns_rbt_t * rbt;
48 dns_db_t * default_db;
51 #define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
52 #define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
54 static void
55 dbdetach(void *data, void *arg) {
56 dns_db_t *db = data;
58 UNUSED(arg);
60 dns_db_detach(&db);
63 isc_result_t
64 dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
65 dns_dbtable_t **dbtablep)
67 dns_dbtable_t *dbtable;
68 isc_result_t result;
70 REQUIRE(mctx != NULL);
71 REQUIRE(dbtablep != NULL && *dbtablep == NULL);
73 dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
74 if (dbtable == NULL)
75 return (ISC_R_NOMEMORY);
77 dbtable->rbt = NULL;
78 result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
79 if (result != ISC_R_SUCCESS)
80 goto clean1;
82 result = isc_mutex_init(&dbtable->lock);
83 if (result != ISC_R_SUCCESS)
84 goto clean2;
86 result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
87 if (result != ISC_R_SUCCESS)
88 goto clean3;
91 dbtable->default_db = NULL;
92 dbtable->mctx = mctx;
93 dbtable->rdclass = rdclass;
94 dbtable->magic = DBTABLE_MAGIC;
95 dbtable->references = 1;
97 *dbtablep = dbtable;
99 return (ISC_R_SUCCESS);
101 clean3:
102 DESTROYLOCK(&dbtable->lock);
104 clean2:
105 dns_rbt_destroy(&dbtable->rbt);
107 clean1:
108 isc_mem_put(mctx, dbtable, sizeof(*dbtable));
110 return (result);
113 static inline void
114 dbtable_free(dns_dbtable_t *dbtable) {
116 * Caller must ensure that it is safe to call.
119 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
121 if (dbtable->default_db != NULL)
122 dns_db_detach(&dbtable->default_db);
124 dns_rbt_destroy(&dbtable->rbt);
126 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
128 isc_rwlock_destroy(&dbtable->tree_lock);
130 dbtable->magic = 0;
132 isc_mem_put(dbtable->mctx, dbtable, sizeof(*dbtable));
135 void
136 dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
137 REQUIRE(VALID_DBTABLE(source));
138 REQUIRE(targetp != NULL && *targetp == NULL);
140 LOCK(&source->lock);
142 INSIST(source->references > 0);
143 source->references++;
144 INSIST(source->references != 0);
146 UNLOCK(&source->lock);
148 *targetp = source;
151 void
152 dns_dbtable_detach(dns_dbtable_t **dbtablep) {
153 dns_dbtable_t *dbtable;
154 isc_boolean_t free_dbtable = ISC_FALSE;
156 REQUIRE(dbtablep != NULL);
157 dbtable = *dbtablep;
158 REQUIRE(VALID_DBTABLE(dbtable));
160 LOCK(&dbtable->lock);
162 INSIST(dbtable->references > 0);
163 dbtable->references--;
164 if (dbtable->references == 0)
165 free_dbtable = ISC_TRUE;
167 UNLOCK(&dbtable->lock);
169 if (free_dbtable)
170 dbtable_free(dbtable);
172 *dbtablep = NULL;
175 isc_result_t
176 dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
177 isc_result_t result;
178 dns_db_t *clone;
180 REQUIRE(VALID_DBTABLE(dbtable));
181 REQUIRE(dns_db_class(db) == dbtable->rdclass);
183 clone = NULL;
184 dns_db_attach(db, &clone);
186 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
187 result = dns_rbt_addname(dbtable->rbt, dns_db_origin(clone), clone);
188 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
190 return (result);
193 void
194 dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
195 dns_db_t *stored_data = NULL;
196 isc_result_t result;
197 dns_name_t *name;
199 REQUIRE(VALID_DBTABLE(dbtable));
201 name = dns_db_origin(db);
204 * There is a requirement that the association of name with db
205 * be verified. With the current rbt.c this is expensive to do,
206 * because effectively two find operations are being done, but
207 * deletion is relatively infrequent.
208 * XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
211 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
213 result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
214 (void **) (void *)&stored_data);
216 if (result == ISC_R_SUCCESS) {
217 INSIST(stored_data == db);
219 dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
222 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
225 void
226 dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
227 REQUIRE(VALID_DBTABLE(dbtable));
228 REQUIRE(dbtable->default_db == NULL);
229 REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
231 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
233 dbtable->default_db = NULL;
234 dns_db_attach(db, &dbtable->default_db);
236 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
239 void
240 dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
241 REQUIRE(VALID_DBTABLE(dbtable));
242 REQUIRE(dbp != NULL && *dbp == NULL);
244 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
246 dns_db_attach(dbtable->default_db, dbp);
248 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
251 void
252 dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
253 REQUIRE(VALID_DBTABLE(dbtable));
255 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
257 dns_db_detach(&dbtable->default_db);
259 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
262 isc_result_t
263 dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
264 unsigned int options, dns_db_t **dbp)
266 dns_db_t *stored_data = NULL;
267 isc_result_t result;
268 unsigned int rbtoptions = 0;
270 REQUIRE(dbp != NULL && *dbp == NULL);
272 if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
273 rbtoptions |= DNS_RBTFIND_NOEXACT;
275 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
277 result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
278 (void **) (void *)&stored_data);
280 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
281 dns_db_attach(stored_data, dbp);
282 else if (dbtable->default_db != NULL) {
283 dns_db_attach(dbtable->default_db, dbp);
284 result = DNS_R_PARTIALMATCH;
285 } else
286 result = ISC_R_NOTFOUND;
288 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
290 return (result);