dbtable.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2013  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*
00019  * $Id: dbtable.c,v 1.33 2007/06/19 23:47:16 tbox Exp $
00020  */
00021 
00022 /*! \file
00023  * \author
00024  * Principal Author: DCL
00025  */
00026 
00027 #include <config.h>
00028 
00029 #include <isc/mem.h>
00030 #include <isc/rwlock.h>
00031 #include <isc/util.h>
00032 
00033 #include <dns/dbtable.h>
00034 #include <dns/db.h>
00035 #include <dns/rbt.h>
00036 #include <dns/result.h>
00037 
00038 struct dns_dbtable {
00039         /* Unlocked. */
00040         unsigned int            magic;
00041         isc_mem_t *             mctx;
00042         dns_rdataclass_t        rdclass;
00043         isc_mutex_t             lock;
00044         isc_rwlock_t            tree_lock;
00045         /* Locked by lock. */
00046         unsigned int            references;
00047         /* Locked by tree_lock. */
00048         dns_rbt_t *             rbt;
00049         dns_db_t *              default_db;
00050 };
00051 
00052 #define DBTABLE_MAGIC           ISC_MAGIC('D', 'B', '-', '-')
00053 #define VALID_DBTABLE(dbtable)  ISC_MAGIC_VALID(dbtable, DBTABLE_MAGIC)
00054 
00055 static void
00056 dbdetach(void *data, void *arg) {
00057         dns_db_t *db = data;
00058 
00059         UNUSED(arg);
00060 
00061         dns_db_detach(&db);
00062 }
00063 
00064 isc_result_t
00065 dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
00066                    dns_dbtable_t **dbtablep)
00067 {
00068         dns_dbtable_t *dbtable;
00069         isc_result_t result;
00070 
00071         REQUIRE(mctx != NULL);
00072         REQUIRE(dbtablep != NULL && *dbtablep == NULL);
00073 
00074         dbtable = (dns_dbtable_t *)isc_mem_get(mctx, sizeof(*dbtable));
00075         if (dbtable == NULL)
00076                 return (ISC_R_NOMEMORY);
00077 
00078         dbtable->rbt = NULL;
00079         result = dns_rbt_create(mctx, dbdetach, NULL, &dbtable->rbt);
00080         if (result != ISC_R_SUCCESS)
00081                 goto clean1;
00082 
00083         result = isc_mutex_init(&dbtable->lock);
00084         if (result != ISC_R_SUCCESS)
00085                 goto clean2;
00086 
00087         result = isc_rwlock_init(&dbtable->tree_lock, 0, 0);
00088         if (result != ISC_R_SUCCESS)
00089                 goto clean3;
00090 
00091         dbtable->default_db = NULL;
00092         dbtable->mctx = NULL;
00093         isc_mem_attach(mctx, &dbtable->mctx);
00094         dbtable->rdclass = rdclass;
00095         dbtable->magic = DBTABLE_MAGIC;
00096         dbtable->references = 1;
00097 
00098         *dbtablep = dbtable;
00099 
00100         return (ISC_R_SUCCESS);
00101 
00102  clean3:
00103         DESTROYLOCK(&dbtable->lock);
00104 
00105  clean2:
00106         dns_rbt_destroy(&dbtable->rbt);
00107 
00108  clean1:
00109         isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
00110 
00111         return (result);
00112 }
00113 
00114 static inline void
00115 dbtable_free(dns_dbtable_t *dbtable) {
00116         /*
00117          * Caller must ensure that it is safe to call.
00118          */
00119 
00120         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00121 
00122         if (dbtable->default_db != NULL)
00123                 dns_db_detach(&dbtable->default_db);
00124 
00125         dns_rbt_destroy(&dbtable->rbt);
00126 
00127         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00128 
00129         isc_rwlock_destroy(&dbtable->tree_lock);
00130 
00131         dbtable->magic = 0;
00132 
00133         isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
00134 }
00135 
00136 void
00137 dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp) {
00138         REQUIRE(VALID_DBTABLE(source));
00139         REQUIRE(targetp != NULL && *targetp == NULL);
00140 
00141         LOCK(&source->lock);
00142 
00143         INSIST(source->references > 0);
00144         source->references++;
00145         INSIST(source->references != 0);
00146 
00147         UNLOCK(&source->lock);
00148 
00149         *targetp = source;
00150 }
00151 
00152 void
00153 dns_dbtable_detach(dns_dbtable_t **dbtablep) {
00154         dns_dbtable_t *dbtable;
00155         isc_boolean_t free_dbtable = ISC_FALSE;
00156 
00157         REQUIRE(dbtablep != NULL);
00158         dbtable = *dbtablep;
00159         REQUIRE(VALID_DBTABLE(dbtable));
00160 
00161         LOCK(&dbtable->lock);
00162 
00163         INSIST(dbtable->references > 0);
00164         dbtable->references--;
00165         if (dbtable->references == 0)
00166                 free_dbtable = ISC_TRUE;
00167 
00168         UNLOCK(&dbtable->lock);
00169 
00170         if (free_dbtable)
00171                 dbtable_free(dbtable);
00172 
00173         *dbtablep = NULL;
00174 }
00175 
00176 isc_result_t
00177 dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db) {
00178         isc_result_t result;
00179         dns_db_t *clone;
00180 
00181         REQUIRE(VALID_DBTABLE(dbtable));
00182         REQUIRE(dns_db_class(db) == dbtable->rdclass);
00183 
00184         clone = NULL;
00185         dns_db_attach(db, &clone);
00186 
00187         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00188         result = dns_rbt_addname(dbtable->rbt, dns_db_origin(clone), clone);
00189         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00190 
00191         return (result);
00192 }
00193 
00194 void
00195 dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db) {
00196         dns_db_t *stored_data = NULL;
00197         isc_result_t result;
00198         dns_name_t *name;
00199 
00200         REQUIRE(VALID_DBTABLE(dbtable));
00201 
00202         name = dns_db_origin(db);
00203 
00204         /*
00205          * There is a requirement that the association of name with db
00206          * be verified.  With the current rbt.c this is expensive to do,
00207          * because effectively two find operations are being done, but
00208          * deletion is relatively infrequent.
00209          * XXXDCL ... this could be cheaper now with dns_rbt_deletenode.
00210          */
00211 
00212         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00213 
00214         result = dns_rbt_findname(dbtable->rbt, name, 0, NULL,
00215                                   (void **) (void *)&stored_data);
00216 
00217         if (result == ISC_R_SUCCESS) {
00218                 INSIST(stored_data == db);
00219 
00220                 (void)dns_rbt_deletename(dbtable->rbt, name, ISC_FALSE);
00221         }
00222 
00223         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00224 }
00225 
00226 void
00227 dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db) {
00228         REQUIRE(VALID_DBTABLE(dbtable));
00229         REQUIRE(dbtable->default_db == NULL);
00230         REQUIRE(dns_name_compare(dns_db_origin(db), dns_rootname) == 0);
00231 
00232         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00233 
00234         dbtable->default_db = NULL;
00235         dns_db_attach(db, &dbtable->default_db);
00236 
00237         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00238 }
00239 
00240 void
00241 dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **dbp) {
00242         REQUIRE(VALID_DBTABLE(dbtable));
00243         REQUIRE(dbp != NULL && *dbp == NULL);
00244 
00245         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00246 
00247         dns_db_attach(dbtable->default_db, dbp);
00248 
00249         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00250 }
00251 
00252 void
00253 dns_dbtable_removedefault(dns_dbtable_t *dbtable) {
00254         REQUIRE(VALID_DBTABLE(dbtable));
00255 
00256         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00257 
00258         dns_db_detach(&dbtable->default_db);
00259 
00260         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_write);
00261 }
00262 
00263 isc_result_t
00264 dns_dbtable_find(dns_dbtable_t *dbtable, dns_name_t *name,
00265                  unsigned int options, dns_db_t **dbp)
00266 {
00267         dns_db_t *stored_data = NULL;
00268         isc_result_t result;
00269         unsigned int rbtoptions = 0;
00270 
00271         REQUIRE(dbp != NULL && *dbp == NULL);
00272 
00273         if ((options & DNS_DBTABLEFIND_NOEXACT) != 0)
00274                 rbtoptions |= DNS_RBTFIND_NOEXACT;
00275 
00276         RWLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00277 
00278         result = dns_rbt_findname(dbtable->rbt, name, rbtoptions, NULL,
00279                                   (void **) (void *)&stored_data);
00280 
00281         if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
00282                 dns_db_attach(stored_data, dbp);
00283         else if (dbtable->default_db != NULL) {
00284                 dns_db_attach(dbtable->default_db, dbp);
00285                 result = DNS_R_PARTIALMATCH;
00286         } else
00287                 result = ISC_R_NOTFOUND;
00288 
00289         RWUNLOCK(&dbtable->tree_lock, isc_rwlocktype_read);
00290 
00291         return (result);
00292 }

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha