]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[v9_9] add zone memory context pools
authorEvan Hunt <each@isc.org>
Thu, 21 Feb 2013 05:40:25 +0000 (21:40 -0800)
committerEvan Hunt <each@isc.org>
Thu, 21 Feb 2013 05:40:25 +0000 (21:40 -0800)
3492. [bug] Fixed a regression in zone loading performance
due to lock contention. [RT #30399]
(cherry picked from commit df925e6c66d45d960fbac0383169763967d2111c)

30 files changed:
CHANGES
bin/named/server.c
bin/named/xfrout.c
lib/dns/acl.c
lib/dns/byaddr.c
lib/dns/dbtable.c
lib/dns/diff.c
lib/dns/dst_api.c
lib/dns/include/dns/zone.h
lib/dns/iptable.c
lib/dns/journal.c
lib/dns/keytable.c
lib/dns/lookup.c
lib/dns/message.c
lib/dns/rbt.c
lib/dns/tests/dnstest.c
lib/dns/tests/zonemgr_test.c
lib/dns/win32/libdns.def
lib/dns/zone.c
lib/isc/Makefile.in
lib/isc/include/isc/pool.h [new file with mode: 0644]
lib/isc/include/isc/radix.h
lib/isc/log.c
lib/isc/pool.c [new file with mode: 0644]
lib/isc/radix.c
lib/isc/tests/Makefile.in
lib/isc/tests/pool_test.c [new file with mode: 0644]
lib/isc/win32/libisc.def
lib/isc/win32/libisc.dsp
lib/isc/win32/libisc.mak

diff --git a/CHANGES b/CHANGES
index bba23b0ca189539507cb43a9626f594c87658c29..fca649bb289b14890b7d5d406db17ebf50246264 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3492.  [bug]           Fixed a regression in zone loading performance
+                       due to lock contention. [RT #30399]
+
 3491.  [bug]           Slave zones using inline-signing must specify a
                        file name. [RT #31946]
 
index 0043656357a4a292f2a8894ebb131fc139e6d411..43ce4f77b7beb02d618d23a16086946e85d3d86c 100644 (file)
@@ -2932,7 +2932,8 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
                                }
                        }
 
-                       CHECK(dns_zone_create(&zone, mctx));
+                       CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
+                                                    &zone));
                        CHECK(dns_zone_setorigin(zone, name));
                        dns_zone_setview(zone, view);
                        CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
@@ -3486,7 +3487,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
                        dns_zone_attach(pview->redirect, &zone);
                        dns_zone_setview(zone, view);
                } else {
-                       CHECK(dns_zone_create(&zone, mctx));
+                       CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr,
+                                                    &zone));
                        CHECK(dns_zone_setorigin(zone, origin));
                        dns_zone_setview(zone, view);
                        CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr,
@@ -3549,7 +3551,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
                 * We cannot reuse an existing zone, we have
                 * to create a new one.
                 */
-               CHECK(dns_zone_create(&zone, mctx));
+               CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
                CHECK(dns_zone_setorigin(zone, origin));
                dns_zone_setview(zone, view);
                if (view->acache != NULL)
@@ -3667,7 +3669,7 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
        }
 
        /* No existing keydata zone was found; create one */
-       CHECK(dns_zone_create(&zone, mctx));
+       CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
        CHECK(dns_zone_setorigin(zone, dns_rootname));
 
        isc_sha256_data((void *)view->name, strlen(view->name), buffer);
index 6b3339223b54ac260456f3c658796c20bb417c59..72d3e2090754dc5958468c3832ef943a6094f1c9 100644 (file)
@@ -247,7 +247,8 @@ ixfr_rrstream_create(isc_mem_t *mctx,
        s = isc_mem_get(mctx, sizeof(*s));
        if (s == NULL)
                return (ISC_R_NOMEMORY);
-       s->common.mctx = mctx;
+       s->common.mctx = NULL;
+       isc_mem_attach(mctx, &s->common.mctx);
        s->common.methods = &ixfr_rrstream_methods;
        s->journal = NULL;
 
@@ -289,7 +290,7 @@ ixfr_rrstream_destroy(rrstream_t **rsp) {
        ixfr_rrstream_t *s = (ixfr_rrstream_t *) *rsp;
        if (s->journal != 0)
                dns_journal_destroy(&s->journal);
-       isc_mem_put(s->common.mctx, s, sizeof(*s));
+       isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
 }
 
 static rrstream_methods_t ixfr_rrstream_methods = {
@@ -335,7 +336,8 @@ axfr_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver,
        s = isc_mem_get(mctx, sizeof(*s));
        if (s == NULL)
                return (ISC_R_NOMEMORY);
-       s->common.mctx = mctx;
+       s->common.mctx = NULL;
+       isc_mem_attach(mctx, &s->common.mctx);
        s->common.methods = &axfr_rrstream_methods;
        s->it_valid = ISC_FALSE;
 
@@ -413,7 +415,7 @@ axfr_rrstream_destroy(rrstream_t **rsp) {
        axfr_rrstream_t *s = (axfr_rrstream_t *) *rsp;
        if (s->it_valid)
                dns_rriterator_destroy(&s->it);
-       isc_mem_put(s->common.mctx, s, sizeof(*s));
+       isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
 }
 
 static rrstream_methods_t axfr_rrstream_methods = {
@@ -455,7 +457,8 @@ soa_rrstream_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *ver,
        s = isc_mem_get(mctx, sizeof(*s));
        if (s == NULL)
                return (ISC_R_NOMEMORY);
-       s->common.mctx = mctx;
+       s->common.mctx = NULL;
+       isc_mem_attach(mctx, &s->common.mctx);
        s->common.methods = &soa_rrstream_methods;
        s->soa_tuple = NULL;
 
@@ -497,7 +500,7 @@ soa_rrstream_destroy(rrstream_t **rsp) {
        soa_rrstream_t *s = (soa_rrstream_t *) *rsp;
        if (s->soa_tuple != NULL)
                dns_difftuple_free(&s->soa_tuple);
-       isc_mem_put(s->common.mctx, s, sizeof(*s));
+       isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
 }
 
 static rrstream_methods_t soa_rrstream_methods = {
@@ -561,7 +564,8 @@ compound_rrstream_create(isc_mem_t *mctx, rrstream_t **soa_stream,
        s = isc_mem_get(mctx, sizeof(*s));
        if (s == NULL)
                return (ISC_R_NOMEMORY);
-       s->common.mctx = mctx;
+       s->common.mctx = NULL;
+       isc_mem_attach(mctx, &s->common.mctx);
        s->common.methods = &compound_rrstream_methods;
        s->components[0] = *soa_stream;
        s->components[1] = *data_stream;
@@ -634,7 +638,7 @@ compound_rrstream_destroy(rrstream_t **rsp) {
        s->components[0]->methods->destroy(&s->components[0]);
        s->components[1]->methods->destroy(&s->components[1]);
        s->components[2] = NULL; /* Copy of components[0]. */
-       isc_mem_put(s->common.mctx, s, sizeof(*s));
+       isc_mem_putanddetach(&s->common.mctx, s, sizeof(*s));
 }
 
 static rrstream_methods_t compound_rrstream_methods = {
index 2906e7ad03f0108e36bb7c2e102732d9491130bc..a738b845305c814a7eb4ac89581a5a40f971933a 100644 (file)
@@ -48,7 +48,10 @@ dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target) {
        acl = isc_mem_get(mctx, sizeof(*acl));
        if (acl == NULL)
                return (ISC_R_NOMEMORY);
-       acl->mctx = mctx;
+
+       acl->mctx = NULL;
+       isc_mem_attach(mctx, &acl->mctx);
+
        acl->name = NULL;
 
        result = isc_refcount_init(&acl->refcount, 1);
@@ -467,7 +470,7 @@ destroy(dns_acl_t *dacl) {
                dns_iptable_detach(&dacl->iptable);
        isc_refcount_destroy(&dacl->refcount);
        dacl->magic = 0;
-       isc_mem_put(dacl->mctx, dacl, sizeof(*dacl));
+       isc_mem_putanddetach(&dacl->mctx, dacl, sizeof(*dacl));
 }
 
 void
index 6a3a6036180a712e2ab05cdc36165af8d092cb44..3fcfb3fd438326e88091f906c2fc23fe7e40a4da 100644 (file)
@@ -224,7 +224,8 @@ dns_byaddr_create(isc_mem_t *mctx, isc_netaddr_t *address, dns_view_t *view,
        byaddr = isc_mem_get(mctx, sizeof(*byaddr));
        if (byaddr == NULL)
                return (ISC_R_NOMEMORY);
-       byaddr->mctx = mctx;
+       byaddr->mctx = NULL;
+       isc_mem_attach(mctx, &byaddr->mctx);
        byaddr->options = options;
 
        byaddr->event = isc_mem_get(mctx, sizeof(*byaddr->event));
@@ -277,7 +278,7 @@ dns_byaddr_create(isc_mem_t *mctx, isc_netaddr_t *address, dns_view_t *view,
        isc_task_detach(&byaddr->task);
 
  cleanup_byaddr:
-       isc_mem_put(mctx, byaddr, sizeof(*byaddr));
+       isc_mem_putanddetach(&mctx, byaddr, sizeof(*byaddr));
 
        return (result);
 }
@@ -310,7 +311,7 @@ dns_byaddr_destroy(dns_byaddr_t **byaddrp) {
 
        DESTROYLOCK(&byaddr->lock);
        byaddr->magic = 0;
-       isc_mem_put(byaddr->mctx, byaddr, sizeof(*byaddr));
+       isc_mem_putanddetach(&byaddr->mctx, byaddr, sizeof(*byaddr));
 
        *byaddrp = NULL;
 }
index 57bbfc1ef81e09dabfc15a20d7479be0bd8afc2e..fac702fd094b9d026b6f78887332d7272f955c46 100644 (file)
@@ -89,7 +89,8 @@ dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
                goto clean3;
 
        dbtable->default_db = NULL;
-       dbtable->mctx = mctx;
+       dbtable->mctx = NULL;
+       isc_mem_attach(mctx, &dbtable->mctx);
        dbtable->rdclass = rdclass;
        dbtable->magic = DBTABLE_MAGIC;
        dbtable->references = 1;
@@ -105,7 +106,7 @@ dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
        dns_rbt_destroy(&dbtable->rbt);
 
  clean1:
-       isc_mem_put(mctx, dbtable, sizeof(*dbtable));
+       isc_mem_putanddetach(&mctx, dbtable, sizeof(*dbtable));
 
        return (result);
 }
@@ -129,7 +130,7 @@ dbtable_free(dns_dbtable_t *dbtable) {
 
        dbtable->magic = 0;
 
-       isc_mem_put(dbtable->mctx, dbtable, sizeof(*dbtable));
+       isc_mem_putanddetach(&dbtable->mctx, dbtable, sizeof(*dbtable));
 }
 
 void
index db665d95ccf007c809a087deaf95434473d84503..283a74705a0ba361d95bb22a88c5a21501b620bf 100644 (file)
@@ -73,7 +73,8 @@ dns_difftuple_create(isc_mem_t *mctx,
        t = isc_mem_allocate(mctx, size);
        if (t == NULL)
                return (ISC_R_NOMEMORY);
-       t->mctx = mctx;
+       t->mctx = NULL;
+       isc_mem_attach(mctx, &t->mctx);
        t->op = op;
 
        datap = (unsigned char *)(t + 1);
@@ -105,10 +106,15 @@ dns_difftuple_create(isc_mem_t *mctx,
 void
 dns_difftuple_free(dns_difftuple_t **tp) {
        dns_difftuple_t *t = *tp;
+       isc_mem_t *mctx;
+
        REQUIRE(DNS_DIFFTUPLE_VALID(t));
+
        dns_name_invalidate(&t->name);
        t->magic = 0;
-       isc_mem_free(t->mctx, t);
+       mctx = t->mctx;
+       isc_mem_free(mctx, t);
+       isc_mem_detach(&mctx);
        *tp = NULL;
 }
 
index 231604811cf6dbf6242ad9ce2ecbdba2b0412d53..98607246effcffb7cac2ab83220d683638176870 100644 (file)
@@ -1135,7 +1135,7 @@ dst_key_free(dst_key_t **keyp) {
                isc_buffer_free(&key->key_tkeytoken);
        }
        memset(key, 0, sizeof(dst_key_t));
-       isc_mem_put(mctx, key, sizeof(dst_key_t));
+       isc_mem_putanddetach(&mctx, key, sizeof(dst_key_t));
        *keyp = NULL;
 }
 
@@ -1334,10 +1334,10 @@ get_key_struct(dns_name_t *name, unsigned int alg,
                isc_mem_put(mctx, key, sizeof(dst_key_t));
                return (NULL);
        }
+       isc_mem_attach(mctx, &key->mctx);
        key->key_alg = alg;
        key->key_flags = flags;
        key->key_proto = protocol;
-       key->mctx = mctx;
        key->keydata.generic = NULL;
        key->key_size = bits;
        key->key_class = rdclass;
index 0cab1fff73cd8460cf82336f417be188883f44f7..00944e75aef20486a353f92d7c2e0fe25452b401 100644 (file)
@@ -1440,6 +1440,18 @@ dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones);
  *\li  zmgr->zonetasks has been initialized.
  */
 
+isc_result_t
+dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep);
+/*%<
+ *     Allocate a new zone using a memory context from the
+ *     zone manager's memory context pool.
+ *
+ * Require:
+ *\li  'zmgr' to be a valid zone manager.
+ *\li  'zonep' != NULL and '*zonep' == NULL.
+ */
+
+
 isc_result_t
 dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
 /*%<
index e960d5c48cd19c5bfe36312bf3dcded0bd39c5dd..85c5b182471b73c13cf803a8e47070185626a4c0 100644 (file)
@@ -36,7 +36,8 @@ dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target) {
        tab = isc_mem_get(mctx, sizeof(*tab));
        if (tab == NULL)
                return (ISC_R_NOMEMORY);
-       tab->mctx = mctx;
+       tab->mctx = NULL;
+       isc_mem_attach(mctx, &tab->mctx);
        isc_refcount_init(&tab->refcount, 1);
        tab->radix = NULL;
        tab->magic = DNS_IPTABLE_MAGIC;
@@ -184,5 +185,5 @@ destroy_iptable(dns_iptable_t *dtab) {
 
        isc_refcount_destroy(&dtab->refcount);
        dtab->magic = 0;
-       isc_mem_put(dtab->mctx, dtab, sizeof(*dtab));
+       isc_mem_putanddetach(&dtab->mctx, dtab, sizeof(*dtab));
 }
index f8f1a9794cfd2b4ca8ad965eedd24648532bf6ff..137f0a632ce9d1593a79b7937ae783a8683ff52a 100644 (file)
@@ -568,7 +568,8 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
        if (j == NULL)
                return (ISC_R_NOMEMORY);
 
-       j->mctx = mctx;
+       j->mctx = NULL;
+       isc_mem_attach(mctx, &j->mctx);
        j->state = JOURNAL_STATE_INVALID;
        j->fp = NULL;
        j->filename = filename;
@@ -679,7 +680,7 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
        }
        if (j->fp != NULL)
                (void)isc_stdio_close(j->fp);
-       isc_mem_put(j->mctx, j, sizeof(*j));
+       isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
        return (result);
 }
 
@@ -1244,7 +1245,7 @@ dns_journal_destroy(dns_journal_t **journalp) {
        if (j->fp != NULL)
                (void)isc_stdio_close(j->fp);
        j->magic = 0;
-       isc_mem_put(j->mctx, j, sizeof(*j));
+       isc_mem_putanddetach(&j->mctx, j, sizeof(*j));
        *journalp = NULL;
 }
 
index 309e9dd2d8d5738e2356b93b0cda25616e7a1047..153f02386ba966abb0dc19233c5b0509df9b4cb7 100644 (file)
@@ -67,7 +67,8 @@ dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
        if (result != ISC_R_SUCCESS)
                goto cleanup_lock;
 
-       keytable->mctx = mctx;
+       keytable->mctx = NULL;
+       isc_mem_attach(mctx, &keytable->mctx);
        keytable->active_nodes = 0;
        keytable->references = 1;
        keytable->magic = KEYTABLE_MAGIC;
@@ -82,7 +83,7 @@ dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep) {
        dns_rbt_destroy(&keytable->table);
 
    cleanup_keytable:
-       isc_mem_put(mctx, keytable, sizeof(*keytable));
+       isc_mem_putanddetach(&mctx, keytable, sizeof(*keytable));
 
        return (result);
 }
@@ -137,7 +138,8 @@ dns_keytable_detach(dns_keytable_t **keytablep) {
                isc_rwlock_destroy(&keytable->rwlock);
                DESTROYLOCK(&keytable->lock);
                keytable->magic = 0;
-               isc_mem_put(keytable->mctx, keytable, sizeof(*keytable));
+               isc_mem_putanddetach(&keytable->mctx,
+                                    keytable, sizeof(*keytable));
        }
 
        *keytablep = NULL;
index d5fc7aae4767d94ef567344a18fd6e65c2bc864e..9130216b852596238d418d6c421facb63ecdf3e8 100644 (file)
@@ -393,7 +393,8 @@ dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
        lookup = isc_mem_get(mctx, sizeof(*lookup));
        if (lookup == NULL)
                return (ISC_R_NOMEMORY);
-       lookup->mctx = mctx;
+       lookup->mctx = NULL;
+       isc_mem_attach(mctx, &lookup->mctx);
        lookup->options = options;
 
        ievent = isc_event_allocate(mctx, lookup, DNS_EVENT_LOOKUPDONE,
@@ -452,7 +453,7 @@ dns_lookup_create(isc_mem_t *mctx, dns_name_t *name, dns_rdatatype_t type,
        isc_task_detach(&lookup->task);
 
  cleanup_lookup:
-       isc_mem_put(mctx, lookup, sizeof(*lookup));
+       isc_mem_putanddetach(&mctx, lookup, sizeof(*lookup));
 
        return (result);
 }
@@ -491,7 +492,7 @@ dns_lookup_destroy(dns_lookup_t **lookupp) {
 
        DESTROYLOCK(&lookup->lock);
        lookup->magic = 0;
-       isc_mem_put(lookup->mctx, lookup, sizeof(*lookup));
+       isc_mem_putanddetach(&lookup->mctx, lookup, sizeof(*lookup));
 
        *lookupp = NULL;
 }
index e0ba4cfffb021daef8a816cba44f0910c7c33d18..721fd3f7fb08e29044f222053e15d9d112d801a4 100644 (file)
@@ -732,7 +732,9 @@ dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
 
        for (i = 0; i < DNS_SECTION_MAX; i++)
                ISC_LIST_INIT(m->sections[i]);
-       m->mctx = mctx;
+
+       m->mctx = NULL;
+       isc_mem_attach(mctx, &m->mctx);
 
        ISC_LIST_INIT(m->scratchpad);
        ISC_LIST_INIT(m->cleanup);
@@ -786,7 +788,7 @@ dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
        if (m->rdspool != NULL)
                isc_mempool_destroy(&m->rdspool);
        m->magic = 0;
-       isc_mem_put(mctx, m, sizeof(dns_message_t));
+       isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
 
        return (ISC_R_NOMEMORY);
 }
@@ -815,7 +817,7 @@ dns_message_destroy(dns_message_t **msgp) {
        isc_mempool_destroy(&msg->namepool);
        isc_mempool_destroy(&msg->rdspool);
        msg->magic = 0;
-       isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
+       isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
 }
 
 static isc_result_t
index eb95d14fbc22ed6f1b13dc273f155fea9d52d8f7..435b28611782bd06c9c6479115eed177b8c9df41 100644 (file)
@@ -248,7 +248,8 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
        if (rbt == NULL)
                return (ISC_R_NOMEMORY);
 
-       rbt->mctx = mctx;
+       rbt->mctx = NULL;
+       isc_mem_attach(mctx, &rbt->mctx);
        rbt->data_deleter = deleter;
        rbt->deleter_arg = deleter_arg;
        rbt->root = NULL;
@@ -259,7 +260,7 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
 #ifdef DNS_RBT_USEHASH
        result = inithash(rbt);
        if (result != ISC_R_SUCCESS) {
-               isc_mem_put(mctx, rbt, sizeof(*rbt));
+               isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
                return (result);
        }
 #endif
@@ -299,7 +300,7 @@ dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
 
        rbt->magic = 0;
 
-       isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
+       isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
        *rbtp = NULL;
        return (ISC_R_SUCCESS);
 }
index e403083457438bff0b464384bba8a6ce2fdfd849..41641b36ed8b89504ae7479380f3514c3159f102 100644 (file)
@@ -212,7 +212,9 @@ dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
        else if (!keepview)
                keepview = ISC_TRUE;
 
-       CHECK(dns_zone_create(&zone, mctx));
+       zone = *zonep;
+       if (zone == NULL)
+               CHECK(dns_zone_create(&zone, mctx));
 
        isc_buffer_constinit(&buffer, name, strlen(name));
        isc_buffer_add(&buffer, strlen(name));
index bed8ed4ffbfd125ffaa9111ba9861805cf835658..3c277ac07f61363b2b0d384553c3fe8fd7c0da42 100644 (file)
@@ -110,6 +110,46 @@ ATF_TC_BODY(zonemgr_managezone, tc) {
        dns_test_end();
 }
 
+ATF_TC(zonemgr_createzone);
+ATF_TC_HEAD(zonemgr_createzone, tc) {
+       atf_tc_set_md_var(tc, "descr", "create and release a zone");
+}
+ATF_TC_BODY(zonemgr_createzone, tc) {
+       dns_zonemgr_t *zonemgr = NULL;
+       dns_zone_t *zone = NULL;
+       isc_result_t result;
+
+       UNUSED(tc);
+
+       result = dns_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
+                                   &zonemgr);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       /* This should not succeed until the dns_zonemgr_setsize() is run */
+       result = dns_zonemgr_createzone(zonemgr, &zone);
+       ATF_REQUIRE_EQ(result, ISC_R_FAILURE);
+
+       result = dns_zonemgr_setsize(zonemgr, 1);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       /* Now it should succeed */
+       result = dns_zonemgr_createzone(zonemgr, &zone);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       ATF_CHECK(zone != NULL);
+
+       if (zone != NULL)
+               dns_zone_detach(&zone);
+
+       dns_zonemgr_shutdown(zonemgr);
+       dns_zonemgr_detach(&zonemgr);
+       ATF_REQUIRE_EQ(zonemgr, NULL);
+
+       dns_test_end();
+}
+
 ATF_TC(zonemgr_unreachable);
 ATF_TC_HEAD(zonemgr_unreachable, tc) {
        atf_tc_set_md_var(tc, "descr", "manage and release a zone");
@@ -182,6 +222,7 @@ ATF_TC_BODY(zonemgr_unreachable, tc) {
 ATF_TP_ADD_TCS(tp) {
        ATF_TP_ADD_TC(tp, zonemgr_create);
        ATF_TP_ADD_TC(tp, zonemgr_managezone);
+       ATF_TP_ADD_TC(tp, zonemgr_createzone);
        ATF_TP_ADD_TC(tp, zonemgr_unreachable);
        return (atf_no_error());
 }
index e1a8e3d54a75059d2484adc03b600a32dcb38c67..fd00e5ec86b3788f0095f08069417a1b575e3044 100644 (file)
@@ -941,6 +941,7 @@ dns_zone_unload
 dns_zonekey_iszonekey
 dns_zonemgr_attach
 dns_zonemgr_create
+dns_zonemgr_createzone
 dns_zonemgr_detach
 dns_zonemgr_forcemaint
 dns_zonemgr_getcount
index d2c44d856c496f637f73dd73b3c31335c4ab9c84..8e2dccfee6e8e2a7bee71e87d61b8529f36ee18a 100644 (file)
@@ -25,6 +25,7 @@
 #include <isc/file.h>
 #include <isc/hex.h>
 #include <isc/mutex.h>
+#include <isc/pool.h>
 #include <isc/print.h>
 #include <isc/random.h>
 #include <isc/ratelimiter.h>
@@ -465,6 +466,7 @@ struct dns_zonemgr {
        isc_taskpool_t *        zonetasks;
        isc_taskpool_t *        loadtasks;
        isc_task_t *            task;
+       isc_pool_t *            mctxpool;
        isc_ratelimiter_t *     rl;
        isc_rwlock_t            rwlock;
        isc_mutex_t             iolock;
@@ -13901,6 +13903,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
        zmgr->socketmgr = socketmgr;
        zmgr->zonetasks = NULL;
        zmgr->loadtasks = NULL;
+       zmgr->mctxpool = NULL;
        zmgr->task = NULL;
        zmgr->rl = NULL;
        ISC_LIST_INIT(zmgr->zones);
@@ -13968,6 +13971,33 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
        return (result);
 }
 
+isc_result_t
+dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) {
+       isc_result_t result;
+       isc_mem_t *mctx = NULL;
+       dns_zone_t *zone = NULL;
+       void *item;
+
+       REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+       REQUIRE(zonep != NULL && *zonep == NULL);
+
+       if (zmgr->mctxpool == NULL)
+               return (ISC_R_FAILURE);
+
+       item = isc_pool_get(zmgr->mctxpool);
+       if (item == NULL)
+               return (ISC_R_FAILURE);
+
+       isc_mem_attach((isc_mem_t *) item, &mctx);
+       result = dns_zone_create(&zone, mctx);
+       isc_mem_detach(&mctx);
+
+       if (result == ISC_R_SUCCESS)
+               *zonep = zone;
+
+       return (result);
+}
+
 isc_result_t
 dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
        isc_result_t result;
@@ -14134,6 +14164,8 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
                isc_taskpool_destroy(&zmgr->zonetasks);
        if (zmgr->loadtasks != NULL)
                isc_taskpool_destroy(&zmgr->loadtasks);
+       if (zmgr->mctxpool != NULL)
+               isc_pool_destroy(&zmgr->mctxpool);
 
        RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
        for (zone = ISC_LIST_HEAD(zmgr->zones);
@@ -14147,21 +14179,54 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
        RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
 }
 
+static isc_result_t
+mctxinit(void **target, void *arg) {
+       isc_result_t result;
+       isc_mem_t *mctx = NULL;
+
+       UNUSED(arg);
+
+       REQUIRE(target != NULL && *target == NULL);
+
+       result = isc_mem_create(0, 0, &mctx);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       isc_mem_setname(mctx, "zonemgr-pool", NULL);
+
+       *target = mctx;
+       return (ISC_R_SUCCESS);
+}
+
+static void
+mctxfree(void **target) {
+       isc_mem_t *mctx = *(isc_mem_t **) target;
+       isc_mem_detach(&mctx);
+       *target = NULL;
+}
+
+#define ZONES_PER_TASK 100
+#define ZONES_PER_MCTX 1000
+
 isc_result_t
 dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
        isc_result_t result;
-       int ntasks = num_zones / 100;
+       int ntasks = num_zones / ZONES_PER_TASK;
+       int nmctx = num_zones / ZONES_PER_MCTX;
        isc_taskpool_t *pool = NULL;
+       isc_pool_t *mctxpool = NULL;
 
        REQUIRE(DNS_ZONEMGR_VALID(zmgr));
 
        /*
         * For anything fewer than 1000 zones we use 10 tasks in
         * the task pools.  More than that, and we'll scale at one
-        * task per 100 zones.
+        * task per 100 zones.  Similarly, for anything smaller than
+        * 2000 zones we use 2 memory contexts, then scale at 1:1000.
         */
        if (ntasks < 10)
                ntasks = 10;
+       if (nmctx < 2)
+               nmctx = 2;
 
        /* Create or resize the zone task pools. */
        if (zmgr->zonetasks == NULL)
@@ -14200,6 +14265,16 @@ dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
        isc_taskpool_setprivilege(zmgr->loadtasks, ISC_TRUE);
 #endif
 
+       /* Create or resize the zone memory context pool. */
+       if (zmgr->mctxpool == NULL)
+               result = isc_pool_create(zmgr->mctx, nmctx, mctxfree,
+                                        mctxinit, NULL, &mctxpool);
+       else
+               result = isc_pool_expand(&zmgr->mctxpool, nmctx, &mctxpool);
+
+       if (result == ISC_R_SUCCESS)
+               zmgr->mctxpool = mctxpool;
+
        return (result);
 }
 
index ff500ffd3fb2f794d1edb548e0b30882c39d656f..8d4c6dc084b612dad30b6a183113c393800c556a 100644 (file)
@@ -58,7 +58,7 @@ OBJS =                @ISC_EXTRA_OBJS@ \
                httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
                lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
                md5.@O@ mem.@O@ mutexblock.@O@ \
-               netaddr.@O@ netscope.@O@ ondestroy.@O@ \
+               netaddr.@O@ netscope.@O@ pool.@O@ ondestroy.@O@ \
                parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
                ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
                serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
@@ -74,7 +74,7 @@ SRCS =                @ISC_EXTRA_SRCS@ \
                httpd.c inet_aton.c iterated_hash.c \
                lex.c lfsr.c lib.c log.c \
                md5.c mem.c mutexblock.c \
-               netaddr.c netscope.c ondestroy.c \
+               netaddr.c netscope.c pool.c ondestroy.c \
                parseint.c portset.c quota.c radix.c random.c \
                ratelimiter.c refcount.c region.c result.c rwlock.c \
                serial.c sha1.c sha2.c sockaddr.c stats.c string.c strtoul.c \
diff --git a/lib/isc/include/isc/pool.h b/lib/isc/include/isc/pool.h
new file mode 100644 (file)
index 0000000..7b33c37
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ISC_OBJPOOL_H
+#define ISC_OBJPOOL_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/pool.h
+ * \brief An object pool is a mechanism for sharing a small pool of
+ * fungible objects among a large number of objects that depend on them.
+ *
+ * This is useful, for example, when it causes performance problems for
+ * large number of zones to share a single memory context or task object,
+ * but it would create a different set of problems for them each to have an
+ * independent task or memory context.
+ */
+
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mem.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/*****
+ ***** Types.
+ *****/
+
+typedef void
+(*isc_pooldeallocator_t)(void **object);
+
+typedef isc_result_t
+(*isc_poolinitializer_t)(void **target, void *arg);
+
+typedef struct isc_pool isc_pool_t;
+
+/*****
+ ***** Functions.
+ *****/
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count,
+               isc_pooldeallocator_t free,
+               isc_poolinitializer_t init, void *initarg,
+               isc_pool_t **poolp);
+/*%<
+ * Create a pool of "count" object pointers. If 'free' is not NULL,
+ * it points to a function that will detach the objects.  'init'
+ * points to a function that will initialize the arguments, and
+ * 'arg' to an argument to be passed into that function (for example,
+ * a relevant manager or context object).
+ *
+ * Requires:
+ *
+ *\li  'mctx' is a valid memory context.
+ *
+ *\li  init != NULL
+ *
+ *\li  poolp != NULL && *poolp == NULL
+ *
+ * Ensures:
+ *
+ *\li  On success, '*poolp' points to the new object pool.
+ *
+ * Returns:
+ *
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMEMORY
+ *\li  #ISC_R_UNEXPECTED
+ */
+
+void *
+isc_pool_get(isc_pool_t *pool);
+/*%<
+ * Returns a pointer to an object from the pool. Currently the object
+ * is chosen from the pool at random.  (This may be changed in the future
+ * to something that guaratees balance.)
+ */
+
+int
+isc_pool_count(isc_pool_t *pool);
+/*%<
+ * Returns the number of objcts in the pool 'pool'.
+ */
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count, isc_pool_t **targetp);
+
+/*%<
+ * If 'size' is larger than the number of objects in the pool pointed to by
+ * 'sourcep', then a new pool of size 'count' is allocated, the existing
+ * objects are copied into it, additional ones created to bring the
+ * total number up to 'count', and the resulting pool is attached to
+ * 'targetp'.
+ *
+ * If 'count' is less than or equal to the number of objects in 'source', then
+ * 'sourcep' is attached to 'targetp' without any other action being taken.
+ *
+ * In either case, 'sourcep' is detached.
+ *
+ * Requires:
+ *
+ * \li 'sourcep' is not NULL and '*source' is not NULL
+ * \li 'targetp' is not NULL and '*source' is NULL
+ *
+ * Ensures:
+ *
+ * \li On success, '*targetp' points to a valid task pool.
+ * \li On success, '*sourcep' points to NULL.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
+
+void
+isc_pool_destroy(isc_pool_t **poolp);
+/*%<
+ * Destroy a task pool.  The tasks in the pool are detached but not
+ * shut down.
+ *
+ * Requires:
+ * \li '*poolp' is a valid task pool.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_OBJPOOL_H */
index 6b413a23b909a8dd722f55ed61b776a4161b0c45..9aa942a2bd24c8b4b990db3d24e36f0c9338c2e6 100644 (file)
        } while(0)
 
 typedef struct isc_prefix {
-    unsigned int family;       /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
-    unsigned int bitlen;       /* 0 for "any" */
-    isc_refcount_t refcount;
-    union {
+       isc_mem_t *mctx;
+       unsigned int family;    /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */
+       unsigned int bitlen;    /* 0 for "any" */
+       isc_refcount_t refcount;
+       union {
                struct in_addr sin;
                struct in6_addr sin6;
-    } add;
+       } add;
 } isc_prefix_t;
 
 typedef void (*isc_radix_destroyfunc_t)(void *);
@@ -90,12 +91,13 @@ typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **);
 
 #define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0)
 typedef struct isc_radix_node {
-   isc_uint32_t bit;                   /* bit length of the prefix */
-   isc_prefix_t *prefix;               /* who we are in radix tree */
-   struct isc_radix_node *l, *r;       /* left and right children */
-   struct isc_radix_node *parent;      /* may be used */
-   void *data[2];                      /* pointers to IPv4 and IPV6 data */
-   int node_num[2];                    /* which node this was in the tree,
+       isc_mem_t *mctx;
+       isc_uint32_t bit;               /* bit length of the prefix */
+       isc_prefix_t *prefix;           /* who we are in radix tree */
+       struct isc_radix_node *l, *r;   /* left and right children */
+       struct isc_radix_node *parent;  /* may be used */
+       void *data[2];                  /* pointers to IPv4 and IPV6 data */
+       int node_num[2];                /* which node this was in the tree,
                                           or -1 for glue nodes */
 } isc_radix_node_t;
 
@@ -103,12 +105,12 @@ typedef struct isc_radix_node {
 #define RADIX_TREE_VALID(a)      ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC);
 
 typedef struct isc_radix_tree {
-   unsigned int                magic;
-   isc_mem_t           *mctx;
-   isc_radix_node_t    *head;
-   isc_uint32_t                maxbits;        /* for IP, 32 bit addresses */
-   int num_active_node;                        /* for debugging purposes */
-   int num_added_node;                 /* total number of nodes */
+       unsigned int magic;
+       isc_mem_t *mctx;
+       isc_radix_node_t *head;
+       isc_uint32_t maxbits;           /* for IP, 32 bit addresses */
+       int num_active_node;            /* for debugging purposes */
+       int num_added_node;             /* total number of nodes */
 } isc_radix_tree_t;
 
 isc_result_t
index f1c925cd3fc4d2762c497e52fa59eb0ad1dedd05..c19d127c62afb4f501cbf490c0643e93a5237ed6 100644 (file)
@@ -275,7 +275,8 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
 
        lctx = isc_mem_get(mctx, sizeof(*lctx));
        if (lctx != NULL) {
-               lctx->mctx = mctx;
+               lctx->mctx = NULL;
+               isc_mem_attach(mctx, &lctx->mctx);
                lctx->categories = NULL;
                lctx->category_count = 0;
                lctx->modules = NULL;
@@ -286,7 +287,7 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
 
                result = isc_mutex_init(&lctx->lock);
                if (result != ISC_R_SUCCESS) {
-                       isc_mem_put(mctx, lctx, sizeof(*lctx));
+                       isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
                        return (result);
                }
 
@@ -493,7 +494,7 @@ isc_log_destroy(isc_log_t **lctxp) {
        lctx->mctx = NULL;
        lctx->magic = 0;
 
-       isc_mem_put(mctx, lctx, sizeof(*lctx));
+       isc_mem_putanddetach(&mctx, lctx, sizeof(*lctx));
 
        *lctxp = NULL;
 }
diff --git a/lib/isc/pool.c b/lib/isc/pool.c
new file mode 100644 (file)
index 0000000..e1ff02c
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <isc/mem.h>
+#include <isc/random.h>
+#include <isc/pool.h>
+#include <isc/util.h>
+
+/***
+ *** Types.
+ ***/
+
+struct isc_pool {
+       isc_mem_t *                     mctx;
+       unsigned int                    count;
+       isc_pooldeallocator_t           free;
+       isc_poolinitializer_t           init;
+       void *                          initarg;
+       void **                         pool;
+};
+
+/***
+ *** Functions.
+ ***/
+
+static isc_result_t
+alloc_pool(isc_mem_t *mctx, unsigned int count, isc_pool_t **poolp) {
+       isc_pool_t *pool;
+
+       pool = isc_mem_get(mctx, sizeof(*pool));
+       if (pool == NULL)
+               return (ISC_R_NOMEMORY);
+       pool->count = count;
+       pool->free = NULL;
+       pool->init = NULL;
+       pool->initarg = NULL;
+       pool->mctx = NULL;
+       isc_mem_attach(mctx, &pool->mctx);
+       pool->pool = isc_mem_get(mctx, count * sizeof(void *));
+       if (pool->pool == NULL) {
+               isc_mem_put(mctx, pool, sizeof(*pool));
+               return (ISC_R_NOMEMORY);
+       }
+       memset(pool->pool, 0, count * sizeof(void *));
+
+       *poolp = pool;
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_pool_create(isc_mem_t *mctx, unsigned int count, 
+                  isc_pooldeallocator_t free,
+                  isc_poolinitializer_t init, void *initarg,
+                  isc_pool_t **poolp)
+{
+       isc_pool_t *pool = NULL;
+       isc_result_t result;
+       unsigned int i;
+
+       INSIST(count > 0);
+
+       /* Allocate the pool structure */
+       result = alloc_pool(mctx, count, &pool);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       pool->free = free;
+       pool->init = init;
+       pool->initarg = initarg;
+
+       /* Populate the pool */
+       for (i = 0; i < count; i++) {
+               result = init(&pool->pool[i], initarg);
+               if (result != ISC_R_SUCCESS) {
+                       isc_pool_destroy(&pool);
+                       return (result);
+               }
+       }
+
+       *poolp = pool;
+       return (ISC_R_SUCCESS);
+}
+
+void *
+isc_pool_get(isc_pool_t *pool) {
+       isc_uint32_t i;
+       isc_random_get(&i);
+       return (pool->pool[i % pool->count]);
+}
+
+int
+isc_pool_count(isc_pool_t *pool) {
+       REQUIRE(pool != NULL);
+       return (pool->count);
+}
+
+isc_result_t
+isc_pool_expand(isc_pool_t **sourcep, unsigned int count,
+                  isc_pool_t **targetp)
+{
+       isc_result_t result;
+       isc_pool_t *pool;
+
+       REQUIRE(sourcep != NULL && *sourcep != NULL);
+       REQUIRE(targetp != NULL && *targetp == NULL);
+
+       pool = *sourcep;
+       if (count > pool->count) {
+               isc_pool_t *newpool = NULL;
+               unsigned int i;
+
+               /* Allocate a new pool structure */
+               result = alloc_pool(pool->mctx, count, &newpool);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+
+               newpool->free = pool->free;
+               newpool->init = pool->init;
+               newpool->initarg = pool->initarg;
+
+               /* Copy over the objects from the old pool */
+               for (i = 0; i < pool->count; i++) {
+                       newpool->pool[i] = pool->pool[i];
+                       pool->pool[i] = NULL;
+               }
+
+               /* Populate the new entries */
+               for (i = pool->count; i < count; i++) {
+                       result = pool->init(&newpool->pool[i], pool->initarg);
+                       if (result != ISC_R_SUCCESS) {
+                               isc_pool_destroy(&pool);
+                               return (result);
+                       }
+               }
+
+               isc_pool_destroy(&pool);
+               pool = newpool;
+       }
+
+       *sourcep = NULL;
+       *targetp = pool;
+       return (ISC_R_SUCCESS);
+}
+
+void
+isc_pool_destroy(isc_pool_t **poolp) {
+       unsigned int i;
+       isc_pool_t *pool = *poolp;
+       for (i = 0; i < pool->count; i++) {
+               if (pool->free != NULL && pool->pool[i] != NULL)
+                       pool->free(&pool->pool[i]);
+       }
+       isc_mem_put(pool->mctx, pool->pool, pool->count * sizeof(void *));
+       isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
+       *poolp = NULL;
+}
index ac211efb6a8747743f70067ec786dae54177a51a..65fc4f4a60b02e10aa266e18c25610f3ff985a9a 100644 (file)
@@ -34,7 +34,7 @@ _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family,
            void *dest, int bitlen);
 
 static void
-_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix);
+_deref_prefix(isc_prefix_t *prefix);
 
 static isc_result_t
 _ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix);
@@ -70,6 +70,8 @@ _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest,
        }
 
        prefix->family = family;
+       prefix->mctx = NULL;
+       isc_mem_attach(mctx, &prefix->mctx);
 
        isc_refcount_init(&prefix->refcount, 1);
 
@@ -78,7 +80,7 @@ _new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest,
 }
 
 static void
-_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix) {
+_deref_prefix(isc_prefix_t *prefix) {
        int refs;
 
        if (prefix == NULL)
@@ -88,7 +90,8 @@ _deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix) {
 
        if (refs <= 0) {
                isc_refcount_destroy(&prefix->refcount);
-               isc_mem_put(mctx, prefix, sizeof(isc_prefix_t));
+               isc_mem_putanddetach(&prefix->mctx, prefix,
+                                    sizeof(isc_prefix_t));
        }
 }
 
@@ -109,7 +112,7 @@ _ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix) {
                isc_result_t ret;
                ret = _new_prefix(mctx, target, prefix->family,
                                  &prefix->add, prefix->bitlen);
-               return ret;
+               return (ret);
        }
 
        isc_refcount_increment(&prefix->refcount, NULL);
@@ -146,7 +149,8 @@ isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits) {
        if (radix == NULL)
                return (ISC_R_NOMEMORY);
 
-       radix->mctx = mctx;
+       radix->mctx = NULL;
+       isc_mem_attach(mctx, &radix->mctx);
        radix->maxbits = maxbits;
        radix->head = NULL;
        radix->num_active_node = 0;
@@ -168,7 +172,6 @@ _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
        REQUIRE(radix != NULL);
 
        if (radix->head != NULL) {
-
                isc_radix_node_t *Xstack[RADIX_MAXBITS+1];
                isc_radix_node_t **Xsp = Xstack;
                isc_radix_node_t *Xrn = radix->head;
@@ -178,7 +181,7 @@ _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
                        isc_radix_node_t *r = Xrn->r;
 
                        if (Xrn->prefix != NULL) {
-                               _deref_prefix(radix->mctx, Xrn->prefix);
+                               _deref_prefix(Xrn->prefix);
                                if (func != NULL && (Xrn->data[0] != NULL ||
                                                     Xrn->data[1] != NULL))
                                        func(Xrn->data);
@@ -209,11 +212,10 @@ _clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
 
 
 void
-isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func)
-{
+isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) {
        REQUIRE(radix != NULL);
        _clear_radix(radix, func);
-       isc_mem_put(radix->mctx, radix, sizeof(*radix));
+       isc_mem_putanddetach(&radix->mctx, radix, sizeof(*radix));
 }
 
 
@@ -221,8 +223,7 @@ isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func)
  * func will be called as func(node->prefix, node->data)
  */
 void
-isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func)
-{
+isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func) {
        isc_radix_node_t *node;
 
        REQUIRE(func != NULL);
@@ -461,8 +462,8 @@ isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target,
                        *target = node;
                        return (ISC_R_SUCCESS);
                } else {
-                       result =
-                               _ref_prefix(radix->mctx, &node->prefix, prefix);
+                       result = _ref_prefix(radix->mctx,
+                                            &node->prefix, prefix);
                        if (result != ISC_R_SUCCESS)
                                return (result);
                }
@@ -623,7 +624,7 @@ isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
                 * make sure there is a prefix associated with it!
                 */
                if (node->prefix != NULL)
-                       _deref_prefix(radix->mctx, node->prefix);
+                       _deref_prefix(node->prefix);
 
                node->prefix = NULL;
                node->data[0] = node->data[1] = NULL;
@@ -632,7 +633,7 @@ isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
 
        if (node->r == NULL && node->l == NULL) {
                parent = node->parent;
-               _deref_prefix(radix->mctx, node->prefix);
+               _deref_prefix(node->prefix);
                isc_mem_put(radix->mctx, node, sizeof(*node));
                radix->num_active_node--;
 
@@ -680,7 +681,7 @@ isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) {
        parent = node->parent;
        child->parent = parent;
 
-       _deref_prefix(radix->mctx, node->prefix);
+       _deref_prefix(node->prefix);
        isc_mem_put(radix->mctx, node, sizeof(*node));
        radix->num_active_node--;
 
index b209ecb4271d35aaf93f8d78b934bc2d1174ca9d..41f1ceb49200356319ecfe1aae86b14f090918ce 100644 (file)
@@ -37,12 +37,12 @@ LIBS =              @LIBS@ @ATFLIBS@
 OBJS =         isctest.@O@
 SRCS =         isctest.c taskpool_test.c socket_test.c hash_test.c \
                sockaddr_test.c symtab_test.c task_test.c queue_test.c \
-               parse_test.c
+               parse_test.c pool_test.c
 
 SUBDIRS =
 TARGETS =      taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
                sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
-               queue_test@EXEEXT@ parse_test@EXEEXT@
+               queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@
 
 @BIND9_MAKE_RULES@
 
@@ -78,6 +78,10 @@ sockaddr_test@EXEEXT@: sockaddr_test.@O@ isctest.@O@ ${ISCDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        sockaddr_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
 
+pool_test@EXEEXT@: pool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+                       pool_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
 
 unit::
        sh ${top_srcdir}/unit/unittest.sh
diff --git a/lib/isc/tests/pool_test.c b/lib/isc/tests/pool_test.c
new file mode 100644 (file)
index 0000000..9d34fd2
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/mem.h>
+#include <isc/pool.h>
+
+#include "isctest.h"
+
+static isc_result_t
+poolinit(void **target, void *arg) {
+       isc_result_t result;
+
+       isc_taskmgr_t *mgr = (isc_taskmgr_t *) arg;
+       isc_task_t *task = NULL;
+       result = isc_task_create(mgr, 0, &task);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       *target = (void *) task;
+       return (ISC_R_SUCCESS);
+}
+
+static void
+poolfree(void **target) {
+       isc_task_t *task = *(isc_task_t **) target;
+       isc_task_destroy(&task);
+       *target = NULL;
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a pool */
+ATF_TC(create_pool);
+ATF_TC_HEAD(create_pool, tc) {
+       atf_tc_set_md_var(tc, "descr", "create a pool");
+}
+ATF_TC_BODY(create_pool, tc) {
+       isc_result_t result;
+       isc_pool_t *pool = NULL;
+
+       UNUSED(tc);
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_pool_create(mctx, 8, poolfree, poolinit, taskmgr, &pool);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool), 8);
+
+       isc_pool_destroy(&pool);
+       ATF_REQUIRE_EQ(pool, NULL);
+
+       isc_test_end();
+}
+
+/* Resize a pool */
+ATF_TC(expand_pool);
+ATF_TC_HEAD(expand_pool, tc) {
+       atf_tc_set_md_var(tc, "descr", "expand a pool");
+}
+ATF_TC_BODY(expand_pool, tc) {
+       isc_result_t result;
+       isc_pool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
+
+       UNUSED(tc);
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_pool_create(mctx, 10, poolfree, poolinit, taskmgr, &pool1);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool1), 10);
+
+       /* resizing to a smaller size should have no effect */
+       hold = pool1;
+       result = isc_pool_expand(&pool1, 5, &pool2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+       ATF_REQUIRE_EQ(pool2, hold);
+       ATF_REQUIRE_EQ(pool1, NULL);
+       pool1 = pool2;
+       pool2 = NULL;
+
+       /* resizing to the same size should have no effect */
+       hold = pool1;
+       result = isc_pool_expand(&pool1, 10, &pool2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool2), 10);
+       ATF_REQUIRE_EQ(pool2, hold);
+       ATF_REQUIRE_EQ(pool1, NULL);
+       pool1 = pool2;
+       pool2 = NULL;
+
+       /* resizing to larger size should make a new pool */
+       hold = pool1;
+       result = isc_pool_expand(&pool1, 20, &pool2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool2), 20);
+       ATF_REQUIRE(pool2 != hold);
+       ATF_REQUIRE_EQ(pool1, NULL);
+
+       isc_pool_destroy(&pool2);
+       ATF_REQUIRE_EQ(pool2, NULL);
+
+       isc_test_end();
+}
+
+/* Get objects */
+ATF_TC(get_objects);
+ATF_TC_HEAD(get_objects, tc) {
+       atf_tc_set_md_var(tc, "descr", "get objects");
+}
+ATF_TC_BODY(get_objects, tc) {
+       isc_result_t result;
+       isc_pool_t *pool = NULL;
+       void *item;
+       isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+       UNUSED(tc);
+
+       result = isc_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_pool_create(mctx, 2, poolfree, poolinit, taskmgr, &pool);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(isc_pool_count(pool), 2);
+
+       item = isc_pool_get(pool);
+       ATF_REQUIRE(item != NULL);
+       isc_task_attach((isc_task_t *) item, &task1);
+
+       item = isc_pool_get(pool);
+       ATF_REQUIRE(item != NULL);
+       isc_task_attach((isc_task_t *) item, &task2);
+
+       item = isc_pool_get(pool);
+       ATF_REQUIRE(item != NULL);
+       isc_task_attach((isc_task_t *) item, &task3);
+
+       isc_task_detach(&task1);
+       isc_task_detach(&task2);
+       isc_task_detach(&task3);
+
+       isc_pool_destroy(&pool);
+       ATF_REQUIRE_EQ(pool, NULL);
+
+       isc_test_end();
+}
+
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+       ATF_TP_ADD_TC(tp, create_pool);
+       ATF_TP_ADD_TC(tp, expand_pool);
+       ATF_TP_ADD_TC(tp, get_objects);
+
+       return (atf_no_error());
+}
+
index ccc9d5c5161c8128ff9ddfd0216db01422d8b03c..b6304d75da4c0a04c3067318b3d8156aeec5b396 100644 (file)
@@ -415,6 +415,11 @@ isc_os_ncpus
 isc_parse_uint16
 isc_parse_uint32
 isc_parse_uint8
+isc_pool_create
+isc_pool_count
+isc_pool_destroy
+isc_pool_expand
+isc_pool_get
 isc_portset_add
 isc_portset_addrange
 isc_portset_create
index 8e4441c39fabe4235a92cd3cc477399411293d23..8b570cc3efe2c5dd196b086eaf808b8016392f2e 100644 (file)
@@ -711,6 +711,10 @@ SOURCE=..\parseint.c
 # End Source File
 # Begin Source File
 
+SOURCE=..\pool.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\portset.c
 # End Source File
 # Begin Source File
index e15b46b3f862368533d1c2dda6bfd414e89a9ea2..e61756b87aa89b48a0334e9b5b609c3a1db2894b 100644 (file)
@@ -162,6 +162,7 @@ CLEAN :
        -@erase "$(INTDIR)\ondestroy.obj"
        -@erase "$(INTDIR)\os.obj"
        -@erase "$(INTDIR)\parseint.obj"
+       -@erase "$(INTDIR)\pool.obj"
        -@erase "$(INTDIR)\portset.obj"
        -@erase "$(INTDIR)\quota.obj"
        -@erase "$(INTDIR)\radix.obj"
@@ -286,6 +287,7 @@ LINK32_OBJS= \
        "$(INTDIR)\taskpool.obj" \
        "$(INTDIR)\timer.obj" \
        "$(INTDIR)\parseint.obj" \
+       "$(INTDIR)\pool.obj" \
        "$(INTDIR)\portset.obj" \
        "$(INTDIR)\region.obj"
 
@@ -403,6 +405,8 @@ CLEAN :
        -@erase "$(INTDIR)\os.sbr"
        -@erase "$(INTDIR)\parseint.obj"
        -@erase "$(INTDIR)\parseint.sbr"
+       -@erase "$(INTDIR)\pool.obj"
+       -@erase "$(INTDIR)\pool.sbr"
        -@erase "$(INTDIR)\portset.obj"
        -@erase "$(INTDIR)\portset.sbr"
        -@erase "$(INTDIR)\quota.obj"
@@ -555,6 +559,7 @@ BSC32_SBRS= \
        "$(INTDIR)\taskpool.sbr" \
        "$(INTDIR)\timer.sbr" \
        "$(INTDIR)\parseint.sbr" \
+       "$(INTDIR)\pool.sbr" \
        "$(INTDIR)\portset.sbr" \
        "$(INTDIR)\region.sbr"
 
@@ -643,6 +648,7 @@ LINK32_OBJS= \
        "$(INTDIR)\taskpool.obj" \
        "$(INTDIR)\timer.obj" \
        "$(INTDIR)\parseint.obj" \
+       "$(INTDIR)\pool.obj" \
        "$(INTDIR)\portset.obj" \
        "$(INTDIR)\region.obj"
 
@@ -1688,6 +1694,24 @@ SOURCE=..\parseint.c
        $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
+!ENDIF 
+
+SOURCE=..\pool.c
+
+!IF  "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\pool.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\pool.obj"   "$(INTDIR)\pool.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
 !ENDIF 
 
 SOURCE=..\portset.c