1 /* $NetBSD: dbtable.c,v 1.5 2014/12/10 04:37:58 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Id: dbtable.c,v 1.33 2007/06/19 23:47:16 tbox Exp
26 * Principal Author: DCL
32 #include <isc/rwlock.h>
35 #include <dns/dbtable.h>
38 #include <dns/result.h>
44 dns_rdataclass_t rdclass
;
46 isc_rwlock_t tree_lock
;
48 unsigned int references
;
49 /* Locked by tree_lock. */
51 dns_db_t
* default_db
;
54 #define DBTABLE_MAGIC ISC_MAGIC('D', 'B', '-', '-')
55 #define VALID_DBTABLE(dbtable) ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
58 dbdetach(void *data
, void *arg
) {
67 dns_dbtable_create(isc_mem_t
*mctx
, dns_rdataclass_t rdclass
,
68 dns_dbtable_t
**dbtablep
)
70 dns_dbtable_t
*dbtable
;
73 REQUIRE(mctx
!= NULL
);
74 REQUIRE(dbtablep
!= NULL
&& *dbtablep
== NULL
);
76 dbtable
= (dns_dbtable_t
*)isc_mem_get(mctx
, sizeof(*dbtable
));
78 return (ISC_R_NOMEMORY
);
81 result
= dns_rbt_create(mctx
, dbdetach
, NULL
, &dbtable
->rbt
);
82 if (result
!= ISC_R_SUCCESS
)
85 result
= isc_mutex_init(&dbtable
->lock
);
86 if (result
!= ISC_R_SUCCESS
)
89 result
= isc_rwlock_init(&dbtable
->tree_lock
, 0, 0);
90 if (result
!= ISC_R_SUCCESS
)
93 dbtable
->default_db
= NULL
;
95 isc_mem_attach(mctx
, &dbtable
->mctx
);
96 dbtable
->rdclass
= rdclass
;
97 dbtable
->magic
= DBTABLE_MAGIC
;
98 dbtable
->references
= 1;
102 return (ISC_R_SUCCESS
);
105 DESTROYLOCK(&dbtable
->lock
);
108 dns_rbt_destroy(&dbtable
->rbt
);
111 isc_mem_putanddetach(&mctx
, dbtable
, sizeof(*dbtable
));
117 dbtable_free(dns_dbtable_t
*dbtable
) {
119 * Caller must ensure that it is safe to call.
122 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
124 if (dbtable
->default_db
!= NULL
)
125 dns_db_detach(&dbtable
->default_db
);
127 dns_rbt_destroy(&dbtable
->rbt
);
129 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
131 isc_rwlock_destroy(&dbtable
->tree_lock
);
135 isc_mem_putanddetach(&dbtable
->mctx
, dbtable
, sizeof(*dbtable
));
139 dns_dbtable_attach(dns_dbtable_t
*source
, dns_dbtable_t
**targetp
) {
140 REQUIRE(VALID_DBTABLE(source
));
141 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
145 INSIST(source
->references
> 0);
146 source
->references
++;
147 INSIST(source
->references
!= 0);
149 UNLOCK(&source
->lock
);
155 dns_dbtable_detach(dns_dbtable_t
**dbtablep
) {
156 dns_dbtable_t
*dbtable
;
157 isc_boolean_t free_dbtable
= ISC_FALSE
;
159 REQUIRE(dbtablep
!= NULL
);
161 REQUIRE(VALID_DBTABLE(dbtable
));
163 LOCK(&dbtable
->lock
);
165 INSIST(dbtable
->references
> 0);
166 dbtable
->references
--;
167 if (dbtable
->references
== 0)
168 free_dbtable
= ISC_TRUE
;
170 UNLOCK(&dbtable
->lock
);
173 dbtable_free(dbtable
);
179 dns_dbtable_add(dns_dbtable_t
*dbtable
, dns_db_t
*db
) {
183 REQUIRE(VALID_DBTABLE(dbtable
));
184 REQUIRE(dns_db_class(db
) == dbtable
->rdclass
);
187 dns_db_attach(db
, &clone
);
189 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
190 result
= dns_rbt_addname(dbtable
->rbt
, dns_db_origin(clone
), clone
);
191 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
197 dns_dbtable_remove(dns_dbtable_t
*dbtable
, dns_db_t
*db
) {
198 dns_db_t
*stored_data
= NULL
;
202 REQUIRE(VALID_DBTABLE(dbtable
));
204 name
= dns_db_origin(db
);
207 * There is a requirement that the association of name with db
208 * be verified. With the current rbt.c this is expensive to do,
209 * because effectively two find operations are being done, but
210 * deletion is relatively infrequent.
211 * XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
214 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
216 result
= dns_rbt_findname(dbtable
->rbt
, name
, 0, NULL
,
217 (void **) (void *)&stored_data
);
219 if (result
== ISC_R_SUCCESS
) {
220 INSIST(stored_data
== db
);
222 (void)dns_rbt_deletename(dbtable
->rbt
, name
, ISC_FALSE
);
225 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
229 dns_dbtable_adddefault(dns_dbtable_t
*dbtable
, dns_db_t
*db
) {
230 REQUIRE(VALID_DBTABLE(dbtable
));
231 REQUIRE(dbtable
->default_db
== NULL
);
232 REQUIRE(dns_name_compare(dns_db_origin(db
), dns_rootname
) == 0);
234 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
236 dbtable
->default_db
= NULL
;
237 dns_db_attach(db
, &dbtable
->default_db
);
239 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
243 dns_dbtable_getdefault(dns_dbtable_t
*dbtable
, dns_db_t
**dbp
) {
244 REQUIRE(VALID_DBTABLE(dbtable
));
245 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
247 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_read
);
249 dns_db_attach(dbtable
->default_db
, dbp
);
251 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_read
);
255 dns_dbtable_removedefault(dns_dbtable_t
*dbtable
) {
256 REQUIRE(VALID_DBTABLE(dbtable
));
258 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
260 dns_db_detach(&dbtable
->default_db
);
262 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_write
);
266 dns_dbtable_find(dns_dbtable_t
*dbtable
, dns_name_t
*name
,
267 unsigned int options
, dns_db_t
**dbp
)
269 dns_db_t
*stored_data
= NULL
;
271 unsigned int rbtoptions
= 0;
273 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
275 if ((options
& DNS_DBTABLEFIND_NOEXACT
) != 0)
276 rbtoptions
|= DNS_RBTFIND_NOEXACT
;
278 RWLOCK(&dbtable
->tree_lock
, isc_rwlocktype_read
);
280 result
= dns_rbt_findname(dbtable
->rbt
, name
, rbtoptions
, NULL
,
281 (void **) (void *)&stored_data
);
283 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_PARTIALMATCH
)
284 dns_db_attach(stored_data
, dbp
);
285 else if (dbtable
->default_db
!= NULL
) {
286 dns_db_attach(dbtable
->default_db
, dbp
);
287 result
= DNS_R_PARTIALMATCH
;
289 result
= ISC_R_NOTFOUND
;
291 RWUNLOCK(&dbtable
->tree_lock
, isc_rwlocktype_read
);