2 * Copyright (C) 2004, 2005, 2007, 2013 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.33 2007/06/19 23:47:16 tbox Exp $
24 * Principal Author: DCL
30 #include <isc/rwlock.h>
33 #include <dns/dbtable.h>
36 #include <dns/result.h>
42 dns_rdataclass_t rdclass;
44 isc_rwlock_t tree_lock;
46 unsigned int references;
47 /* Locked by tree_lock. */
49 dns_db_t * default_db;
52 #define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
53 #define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
56 dbdetach(void *data, void *arg) {
65 dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
66 dns_dbtable_t **dbtablep)
68 dns_dbtable_t *dbtable;
71 REQUIRE(mctx != NULL);
72 REQUIRE(dbtablep != NULL && *dbtablep == NULL);
74 dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
76 return (ISC_R_NOMEMORY);
79 result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
80 if (result != ISC_R_SUCCESS)
83 result = isc_mutex_init(&dbtable->lock);
84 if (result != ISC_R_SUCCESS)
87 result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
88 if (result != ISC_R_SUCCESS)
91 dbtable->default_db = NULL;
93 isc_mem_attach(mctx, &dbtable->mctx);
94 dbtable->rdclass = rdclass;
95 dbtable->magic = DBTABLE_MAGIC;
96 dbtable->references = 1;
100 return (ISC_R_SUCCESS);
103 DESTROYLOCK(&dbtable->lock);
106 dns_rbt_destroy(&dbtable->rbt);
109 isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
115 dbtable_free(dns_dbtable_t *dbtable) {
117 * Caller must ensure that it is safe to call.
120 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
122 if (dbtable->default_db != NULL)
123 dns_db_detach(&dbtable->default_db);
125 dns_rbt_destroy(&dbtable->rbt);
127 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
129 isc_rwlock_destroy(&dbtable->tree_lock);
133 isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
137 dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
138 REQUIRE(VALID_DBTABLE(source));
139 REQUIRE(targetp != NULL && *targetp == NULL);
143 INSIST(source->references > 0);
144 source->references++;
145 INSIST(source->references != 0);
147 UNLOCK(&source->lock);
153 dns_dbtable_detach(dns_dbtable_t **dbtablep) {
154 dns_dbtable_t *dbtable;
155 isc_boolean_t free_dbtable = ISC_FALSE;
157 REQUIRE(dbtablep != NULL);
159 REQUIRE(VALID_DBTABLE(dbtable));
161 LOCK(&dbtable->lock);
163 INSIST(dbtable->references > 0);
164 dbtable->references--;
165 if (dbtable->references == 0)
166 free_dbtable = ISC_TRUE;
168 UNLOCK(&dbtable->lock);
171 dbtable_free(dbtable);
177 dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
181 REQUIRE(VALID_DBTABLE(dbtable));
182 REQUIRE(dns_db_class(db) == dbtable->rdclass);
185 dns_db_attach(db, &clone);
187 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
188 result = dns_rbt_addname(dbtable->rbt, dns_db_origin(clone), clone);
189 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
195 dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
196 dns_db_t *stored_data = NULL;
200 REQUIRE(VALID_DBTABLE(dbtable));
202 name = dns_db_origin(db);
205 * There is a requirement that the association of name with db
206 * be verified. With the current rbt.c this is expensive to do,
207 * because effectively two find operations are being done, but
208 * deletion is relatively infrequent.
209 * XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
212 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
214 result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
215 (void **) (void *)&stored_data);
217 if (result == ISC_R_SUCCESS) {
218 INSIST(stored_data == db);
220 (void)dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
223 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
227 dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
228 REQUIRE(VALID_DBTABLE(dbtable));
229 REQUIRE(dbtable->default_db == NULL);
230 REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
232 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
234 dbtable->default_db = NULL;
235 dns_db_attach(db, &dbtable->default_db);
237 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
241 dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
242 REQUIRE(VALID_DBTABLE(dbtable));
243 REQUIRE(dbp != NULL && *dbp == NULL);
245 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
247 dns_db_attach(dbtable->default_db, dbp);
249 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
253 dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
254 REQUIRE(VALID_DBTABLE(dbtable));
256 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
258 dns_db_detach(&dbtable->default_db);
260 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
264 dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
265 unsigned int options, dns_db_t **dbp)
267 dns_db_t *stored_data = NULL;
269 unsigned int rbtoptions = 0;
271 REQUIRE(dbp != NULL && *dbp == NULL);
273 if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
274 rbtoptions |= DNS_RBTFIND_NOEXACT;
276 RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
278 result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
279 (void **) (void *)&stored_data);
281 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
282 dns_db_attach(stored_data, dbp);
283 else if (dbtable->default_db != NULL) {
284 dns_db_attach(dbtable->default_db, dbp);
285 result = DNS_R_PARTIALMATCH;
287 result = ISC_R_NOTFOUND;
289 RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);