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.12.4 2004/03/09 05:21:08 marka Exp $
23 * Principal Author: DCL
29 #include <isc/rwlock.h>
32 #include <dns/dbtable.h>
35 #include <dns/result.h>
41 dns_rdataclass_t rdclass;
43 isc_rwlock_t tree_lock;
45 unsigned int references;
46 /* Locked by tree_lock. */
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)
55 dbdetach(void *data, void *arg) {
64 dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
65 dns_dbtable_t **dbtablep)
67 dns_dbtable_t *dbtable;
70 REQUIRE(mctx != NULL);
71 REQUIRE(dbtablep != NULL && *dbtablep == NULL);
73 dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
75 return (ISC_R_NOMEMORY);
78 result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
79 if (result != ISC_R_SUCCESS)
82 result = isc_mutex_init(&dbtable->lock);
83 if (result != ISC_R_SUCCESS)
86 result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
87 if (result != ISC_R_SUCCESS)
91 dbtable->default_db = NULL;
93 dbtable->rdclass = rdclass;
94 dbtable->magic = DBTABLE_MAGIC;
95 dbtable->references = 1;
99 return (ISC_R_SUCCESS);
102 DESTROYLOCK(&dbtable->lock);
105 dns_rbt_destroy(&dbtable->rbt);
108 isc_mem_put(mctx, dbtable, sizeof(*dbtable));
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);
132 isc_mem_put(dbtable->mctx, dbtable, sizeof(*dbtable));
136 dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
137 REQUIRE(VALID_DBTABLE(source));
138 REQUIRE(targetp != NULL && *targetp == NULL);
142 INSIST(source->references > 0);
143 source->references++;
144 INSIST(source->references != 0);
146 UNLOCK(&source->lock);
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);
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);
170 dbtable_free(dbtable);
176 dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
180 REQUIRE(VALID_DBTABLE(dbtable));
181 REQUIRE(dns_db_class(db) == dbtable->rdclass);
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);
194 dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
195 dns_db_t *stored_data = NULL;
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 (void)dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
222 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
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);
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);
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);
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;
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;
286 result = ISC_R_NOTFOUND;
288 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);