From df925e6c66d45d960fbac0383169763967d2111c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 20 Feb 2013 21:39:05 -0800 Subject: [PATCH] [master] add zone memory context pools 3492. [bug] Fixed a regression in zone loading performance due to lock contention. [RT #30399] --- CHANGES | 3 + bin/named/server.c | 10 +- bin/named/xfrout.c | 20 ++-- lib/dns/acl.c | 7 +- lib/dns/byaddr.c | 7 +- lib/dns/dbtable.c | 7 +- lib/dns/diff.c | 10 +- lib/dns/dst_api.c | 4 +- lib/dns/include/dns/zone.h | 12 +++ lib/dns/iptable.c | 5 +- lib/dns/journal.c | 7 +- lib/dns/keytable.c | 8 +- lib/dns/lookup.c | 7 +- lib/dns/message.c | 8 +- lib/dns/rbt.c | 7 +- lib/dns/tests/dnstest.c | 4 +- lib/dns/tests/zonemgr_test.c | 41 ++++++++ lib/dns/win32/libdns.def | 1 + lib/dns/zone.c | 79 ++++++++++++++- lib/isc/Makefile.in | 4 +- lib/isc/include/isc/pool.h | 149 ++++++++++++++++++++++++++++ lib/isc/include/isc/radix.h | 36 +++---- lib/isc/log.c | 7 +- lib/isc/pool.c | 177 +++++++++++++++++++++++++++++++++ lib/isc/radix.c | 35 +++---- lib/isc/tests/Makefile.in | 8 +- lib/isc/tests/pool_test.c | 186 +++++++++++++++++++++++++++++++++++ lib/isc/win32/libisc.def | 5 + lib/isc/win32/libisc.dsp | 4 + lib/isc/win32/libisc.mak | 24 +++++ 30 files changed, 797 insertions(+), 85 deletions(-) create mode 100644 lib/isc/include/isc/pool.h create mode 100644 lib/isc/pool.c create mode 100644 lib/isc/tests/pool_test.c diff --git a/CHANGES b/CHANGES index 3cec7e7ba8..135233864e 100644 --- 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] diff --git a/bin/named/server.c b/bin/named/server.c index 28434187e9..af5d9ce046 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3028,7 +3028,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, @@ -3582,7 +3583,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, @@ -3645,7 +3647,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) @@ -3763,7 +3765,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); diff --git a/bin/named/xfrout.c b/bin/named/xfrout.c index 135b54c558..c11e5b3f44 100644 --- a/bin/named/xfrout.c +++ b/bin/named/xfrout.c @@ -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 = { diff --git a/lib/dns/acl.c b/lib/dns/acl.c index 2906e7ad03..a738b84530 100644 --- a/lib/dns/acl.c +++ b/lib/dns/acl.c @@ -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 diff --git a/lib/dns/byaddr.c b/lib/dns/byaddr.c index 6a3a603618..3fcfb3fd43 100644 --- a/lib/dns/byaddr.c +++ b/lib/dns/byaddr.c @@ -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; } diff --git a/lib/dns/dbtable.c b/lib/dns/dbtable.c index 57bbfc1ef8..fac702fd09 100644 --- a/lib/dns/dbtable.c +++ b/lib/dns/dbtable.c @@ -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 diff --git a/lib/dns/diff.c b/lib/dns/diff.c index db665d95cc..283a74705a 100644 --- a/lib/dns/diff.c +++ b/lib/dns/diff.c @@ -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; } diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 6b0a9b7fff..730497e951 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1149,7 +1149,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; } @@ -1348,10 +1348,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; diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index ed03a9af53..59861dfab2 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -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); /*%< diff --git a/lib/dns/iptable.c b/lib/dns/iptable.c index e960d5c48c..85c5b18247 100644 --- a/lib/dns/iptable.c +++ b/lib/dns/iptable.c @@ -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)); } diff --git a/lib/dns/journal.c b/lib/dns/journal.c index f8f1a9794c..137f0a632c 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -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; } diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index 309e9dd2d8..153f02386b 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -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; diff --git a/lib/dns/lookup.c b/lib/dns/lookup.c index d5fc7aae47..9130216b85 100644 --- a/lib/dns/lookup.c +++ b/lib/dns/lookup.c @@ -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; } diff --git a/lib/dns/message.c b/lib/dns/message.c index 44336d018b..7a0f6a0534 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -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 diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 9643dab8e1..947be1f476 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -755,7 +755,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; @@ -767,7 +768,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 @@ -809,7 +810,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); } diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c index e403083457..41641b36ed 100644 --- a/lib/dns/tests/dnstest.c +++ b/lib/dns/tests/dnstest.c @@ -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)); diff --git a/lib/dns/tests/zonemgr_test.c b/lib/dns/tests/zonemgr_test.c index bed8ed4ffb..3c277ac07f 100644 --- a/lib/dns/tests/zonemgr_test.c +++ b/lib/dns/tests/zonemgr_test.c @@ -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()); } diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index c9908645f1..71e058ba89 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -951,6 +951,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 diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 842a3aa1f8..30590fc1f2 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -469,6 +470,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; @@ -14004,6 +14006,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); @@ -14071,6 +14074,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; @@ -14237,6 +14267,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); @@ -14250,21 +14282,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) @@ -14303,6 +14368,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); } diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index ff500ffd3f..8d4c6dc084 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -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 index 0000000000..7b33c37bb7 --- /dev/null +++ b/lib/isc/include/isc/pool.h @@ -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 +#include +#include + +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 */ diff --git a/lib/isc/include/isc/radix.h b/lib/isc/include/isc/radix.h index 6b413a23b9..9aa942a2bd 100644 --- a/lib/isc/include/isc/radix.h +++ b/lib/isc/include/isc/radix.h @@ -54,13 +54,14 @@ } 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 diff --git a/lib/isc/log.c b/lib/isc/log.c index f1c925cd3f..c19d127c62 100644 --- a/lib/isc/log.c +++ b/lib/isc/log.c @@ -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 index 0000000000..e1ff02c576 --- /dev/null +++ b/lib/isc/pool.c @@ -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 + +#include + +#include +#include +#include +#include + +/*** + *** 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; +} diff --git a/lib/isc/radix.c b/lib/isc/radix.c index ac211efb6a..65fc4f4a60 100644 --- a/lib/isc/radix.c +++ b/lib/isc/radix.c @@ -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--; diff --git a/lib/isc/tests/Makefile.in b/lib/isc/tests/Makefile.in index b209ecb427..41f1ceb492 100644 --- a/lib/isc/tests/Makefile.in +++ b/lib/isc/tests/Makefile.in @@ -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 index 0000000000..9d34fd2236 --- /dev/null +++ b/lib/isc/tests/pool_test.c @@ -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 + +#include + +#include + +#include +#include + +#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()); +} + diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def index d1dedfa261..cfecd94271 100644 --- a/lib/isc/win32/libisc.def +++ b/lib/isc/win32/libisc.def @@ -418,6 +418,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 diff --git a/lib/isc/win32/libisc.dsp b/lib/isc/win32/libisc.dsp index 8e4441c39f..8b570cc3ef 100644 --- a/lib/isc/win32/libisc.dsp +++ b/lib/isc/win32/libisc.dsp @@ -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 diff --git a/lib/isc/win32/libisc.mak b/lib/isc/win32/libisc.mak index e15b46b3f8..e61756b87a 100644 --- a/lib/isc/win32/libisc.mak +++ b/lib/isc/win32/libisc.mak @@ -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