2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 21:17:54 +00:00

Create per-thread task and memory context for zonemgr

Previously, the zonemgr created 1 task per 100 zones and 1 memory
context per 1000 zones (with minimum 10 tasks and 2 memory contexts) to
reduce the contention between threads.

Instead of reducing the contention by having many resources, create a
per-nm_thread memory context, loadtask and zonetask and spread the zones
between just per-thread resources.

Note: this commit alone does decrease performance when loading the zone
by couple seconds (in case of 1M zone) and thus there's more work in
this whole MR fixing the performance.
This commit is contained in:
Ondřej Surý 2021-12-17 11:34:57 +01:00 committed by Ondřej Surý
parent abb5e9a575
commit a94678ff77
16 changed files with 116 additions and 796 deletions

View File

@ -9221,14 +9221,6 @@ load_configuration(const char *filename, named_server_t *server,
dns_view_detach(&view); dns_view_detach(&view);
} }
/*
* Zones have been counted; set the zone manager task pool size.
*/
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
"sizing zone task pool based on %d zones", num_zones);
CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
/* /*
* Configure and freeze all explicit views. Explicit * Configure and freeze all explicit views. Explicit
* views that have zones were already created at parsing * views that have zones were already created at parsing
@ -10192,10 +10184,8 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr, CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
named_g_timermgr, named_g_netmgr, named_g_timermgr, named_g_netmgr,
&server->zonemgr), named_g_cpus, &server->zonemgr),
"dns_zonemgr_create"); "dns_zonemgr_create");
CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000), "dns_zonemgr_"
"setsize");
server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,

View File

@ -1783,10 +1783,9 @@ dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
isc_result_t isc_result_t
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_nm_t *netmgr, isc_timermgr_t *timermgr, isc_nm_t *netmgr,
dns_zonemgr_t **zmgrp); unsigned int workers, dns_zonemgr_t **zmgrp);
/*%< /*%<
* Create a zone manager. Note: the zone manager will not be able to * Create a zone manager.
* manage any zones until dns_zonemgr_setsize() has been run.
* *
* Requires: * Requires:
*\li 'mctx' to be a valid memory context. *\li 'mctx' to be a valid memory context.
@ -1795,18 +1794,6 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
*\li 'zmgrp' to point to a NULL pointer. *\li 'zmgrp' to point to a NULL pointer.
*/ */
isc_result_t
dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones);
/*%<
* Set the size of the zone manager task pool. This must be run
* before zmgr can be used for managing zones. Currently, it can only
* be run once; the task pool cannot be resized.
*
* Requires:
*\li zmgr is a valid zone manager.
*\li zmgr->zonetasks has been initialized.
*/
isc_result_t isc_result_t
dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep); dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep);
/*%< /*%<

View File

@ -292,7 +292,8 @@ dns_test_setupzonemgr(void) {
isc_result_t result; isc_result_t result;
REQUIRE(zonemgr == NULL); REQUIRE(zonemgr == NULL);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, &zonemgr); result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, ncpus,
&zonemgr);
return (result); return (result);
} }
@ -301,11 +302,6 @@ dns_test_managezone(dns_zone_t *zone) {
isc_result_t result; isc_result_t result;
REQUIRE(zonemgr != NULL); REQUIRE(zonemgr != NULL);
result = dns_zonemgr_setsize(zonemgr, 1);
if (result != ISC_R_SUCCESS) {
return (result);
}
result = dns_zonemgr_managezone(zonemgr, zone); result = dns_zonemgr_managezone(zonemgr, zone);
return (result); return (result);
} }

View File

@ -64,7 +64,7 @@ zonemgr_create(void **state) {
UNUSED(state); UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, 1,
&myzonemgr); &myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
@ -82,22 +82,15 @@ zonemgr_managezone(void **state) {
UNUSED(state); UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, 1,
&myzonemgr); &myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
result = dns_test_makezone("foo", &zone, NULL, false); result = dns_test_makezone("foo", &zone, NULL, false);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
/* This should not succeed until the dns_zonemgr_setsize() is run */
result = dns_zonemgr_managezone(myzonemgr, zone);
assert_int_equal(result, ISC_R_FAILURE);
assert_int_equal(dns_zonemgr_getcount(myzonemgr, DNS_ZONESTATE_ANY), 0); assert_int_equal(dns_zonemgr_getcount(myzonemgr, DNS_ZONESTATE_ANY), 0);
result = dns_zonemgr_setsize(myzonemgr, 1);
assert_int_equal(result, ISC_R_SUCCESS);
/* Now it should succeed */ /* Now it should succeed */
result = dns_zonemgr_managezone(myzonemgr, zone); result = dns_zonemgr_managezone(myzonemgr, zone);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
@ -123,18 +116,10 @@ zonemgr_createzone(void **state) {
UNUSED(state); UNUSED(state);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, 1,
&myzonemgr); &myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
/* This should not succeed until the dns_zonemgr_setsize() is run */
result = dns_zonemgr_createzone(myzonemgr, &zone);
assert_int_equal(result, ISC_R_FAILURE);
result = dns_zonemgr_setsize(myzonemgr, 1);
assert_int_equal(result, ISC_R_SUCCESS);
/* Now it should succeed */
result = dns_zonemgr_createzone(myzonemgr, &zone); result = dns_zonemgr_createzone(myzonemgr, &zone);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(zone); assert_non_null(zone);
@ -162,16 +147,13 @@ zonemgr_unreachable(void **state) {
TIME_NOW(&now); TIME_NOW(&now);
result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, result = dns_zonemgr_create(dt_mctx, taskmgr, timermgr, NULL, 1,
&myzonemgr); &myzonemgr);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
result = dns_test_makezone("foo", &zone, NULL, false); result = dns_test_makezone("foo", &zone, NULL, false);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
result = dns_zonemgr_setsize(myzonemgr, 1);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_zonemgr_managezone(myzonemgr, zone); result = dns_zonemgr_managezone(myzonemgr, zone);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
@ -224,7 +206,6 @@ zonemgr_unreachable(void **state) {
* - dns_zonemgr_forcemaint * - dns_zonemgr_forcemaint
* - dns_zonemgr_resumexfrs * - dns_zonemgr_resumexfrs
* - dns_zonemgr_shutdown * - dns_zonemgr_shutdown
* - dns_zonemgr_setsize
* - dns_zonemgr_settransfersin * - dns_zonemgr_settransfersin
* - dns_zonemgr_getttransfersin * - dns_zonemgr_getttransfersin
* - dns_zonemgr_settransfersperns * - dns_zonemgr_settransfersperns

View File

@ -26,7 +26,6 @@
#include <isc/stats.h> #include <isc/stats.h>
#include <isc/stdtime.h> #include <isc/stdtime.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/taskpool.h>
#include <isc/time.h> #include <isc/time.h>
#include <isc/util.h> #include <isc/util.h>

View File

@ -35,7 +35,7 @@
#include <isc/stdtime.h> #include <isc/stdtime.h>
#include <isc/strerr.h> #include <isc/strerr.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/taskpool.h> #include <isc/task.h>
#include <isc/thread.h> #include <isc/thread.h>
#include <isc/timer.h> #include <isc/timer.h>
#include <isc/tls.h> #include <isc/tls.h>
@ -595,8 +595,10 @@ struct dns_zonemgr {
isc_taskmgr_t *taskmgr; isc_taskmgr_t *taskmgr;
isc_timermgr_t *timermgr; isc_timermgr_t *timermgr;
isc_nm_t *netmgr; isc_nm_t *netmgr;
isc_taskpool_t *zonetasks; atomic_uint_fast32_t nzonetasks;
isc_taskpool_t *loadtasks; isc_pool_t *zonetasks;
atomic_uint_fast32_t nloadtasks;
isc_pool_t *loadtasks;
isc_task_t *task; isc_task_t *task;
isc_pool_t *mctxpool; isc_pool_t *mctxpool;
isc_ratelimiter_t *checkdsrl; isc_ratelimiter_t *checkdsrl;
@ -970,6 +972,8 @@ static void
zonemgr_putio(dns_io_t **iop); zonemgr_putio(dns_io_t **iop);
static void static void
zonemgr_cancelio(dns_io_t *io); zonemgr_cancelio(dns_io_t *io);
static isc_result_t
zonemgr_setsize(dns_zonemgr_t *zmgr, unsigned int workers);
static void static void
rss_post(dns_zone_t *, isc_event_t *); rss_post(dns_zone_t *, isc_event_t *);
@ -18798,10 +18802,12 @@ zonemgr_keymgmt_find(dns_zonemgr_t *zmgr, dns_zone_t *zone,
isc_result_t isc_result_t
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_nm_t *netmgr, isc_timermgr_t *timermgr, isc_nm_t *netmgr,
dns_zonemgr_t **zmgrp) { unsigned int workers, dns_zonemgr_t **zmgrp) {
dns_zonemgr_t *zmgr; dns_zonemgr_t *zmgr;
isc_result_t result; isc_result_t result;
REQUIRE(workers >= 1);
zmgr = isc_mem_get(mctx, sizeof(*zmgr)); zmgr = isc_mem_get(mctx, sizeof(*zmgr));
zmgr->mctx = NULL; zmgr->mctx = NULL;
isc_refcount_init(&zmgr->refs, 1); isc_refcount_init(&zmgr->refs, 1);
@ -18810,7 +18816,9 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
zmgr->timermgr = timermgr; zmgr->timermgr = timermgr;
zmgr->netmgr = netmgr; zmgr->netmgr = netmgr;
zmgr->zonetasks = NULL; zmgr->zonetasks = NULL;
atomic_init(&zmgr->nzonetasks, 0);
zmgr->loadtasks = NULL; zmgr->loadtasks = NULL;
atomic_init(&zmgr->nloadtasks, 0);
zmgr->mctxpool = NULL; zmgr->mctxpool = NULL;
zmgr->task = NULL; zmgr->task = NULL;
zmgr->checkdsrl = NULL; zmgr->checkdsrl = NULL;
@ -18870,6 +18878,11 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
goto free_startupnotifyrl; goto free_startupnotifyrl;
} }
result = zonemgr_setsize(zmgr, workers);
if (result != ISC_R_SUCCESS) {
goto free_startuprefreshrl;
}
/* Key file I/O locks. */ /* Key file I/O locks. */
zonemgr_keymgmt_init(zmgr); zonemgr_keymgmt_init(zmgr);
@ -18900,6 +18913,8 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
free_iolock: free_iolock:
isc_mutex_destroy(&zmgr->iolock); isc_mutex_destroy(&zmgr->iolock);
#endif /* if 0 */ #endif /* if 0 */
free_startuprefreshrl:
isc_ratelimiter_detach(&zmgr->startuprefreshrl);
free_startupnotifyrl: free_startupnotifyrl:
isc_ratelimiter_detach(&zmgr->startupnotifyrl); isc_ratelimiter_detach(&zmgr->startupnotifyrl);
free_refreshrl: free_refreshrl:
@ -18963,8 +18978,8 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
REQUIRE(zone->timer == NULL); REQUIRE(zone->timer == NULL);
REQUIRE(zone->zmgr == NULL); REQUIRE(zone->zmgr == NULL);
isc_taskpool_gettask(zmgr->zonetasks, &zone->task); isc_task_attach(isc_pool_get(zmgr->zonetasks), &zone->task);
isc_taskpool_gettask(zmgr->loadtasks, &zone->loadtask); isc_task_attach(isc_pool_get(zmgr->loadtasks), &zone->loadtask);
/* /*
* Set the task name. The tag will arbitrarily point to one * Set the task name. The tag will arbitrarily point to one
@ -19097,10 +19112,10 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
isc_task_destroy(&zmgr->task); isc_task_destroy(&zmgr->task);
} }
if (zmgr->zonetasks != NULL) { if (zmgr->zonetasks != NULL) {
isc_taskpool_destroy(&zmgr->zonetasks); isc_pool_destroy(&zmgr->zonetasks);
} }
if (zmgr->loadtasks != NULL) { if (zmgr->loadtasks != NULL) {
isc_taskpool_destroy(&zmgr->loadtasks); isc_pool_destroy(&zmgr->loadtasks);
} }
if (zmgr->mctxpool != NULL) { if (zmgr->mctxpool != NULL) {
isc_pool_destroy(&zmgr->mctxpool); isc_pool_destroy(&zmgr->mctxpool);
@ -19117,6 +19132,49 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
} }
static isc_result_t
taskinit(void **target, void *arg, uint32_t bindto, unsigned int quantum,
bool priv) {
dns_zonemgr_t *zmgr = (dns_zonemgr_t *)arg;
isc_task_t *task = NULL;
isc_result_t result = isc_task_create_bound(zmgr->taskmgr, quantum,
&task, bindto);
if (result != ISC_R_SUCCESS) {
return (result);
}
isc_task_setprivilege(task, priv);
isc_task_setname(task, "zonemgr-taskpool", NULL);
*target = task;
return (ISC_R_SUCCESS);
}
static void
taskfree(void **target) {
isc_task_t *task = *target;
isc_task_detach(&task);
}
static isc_result_t
zonetaskinit(void **target, void *arg) {
dns_zonemgr_t *zmgr = (dns_zonemgr_t *)arg;
uint32_t bindto = atomic_fetch_add(&zmgr->nzonetasks, 1);
return (taskinit(target, arg, bindto, 2, false));
}
static isc_result_t
loadtaskinit(void **target, void *arg) {
/*
* We always set all tasks in the zone-load task pool to
* privileged. This prevents other tasks in the system from
* running while the server task manager is in privileged
* mode.
*/
dns_zonemgr_t *zmgr = (dns_zonemgr_t *)arg;
uint32_t bindto = atomic_fetch_add(&zmgr->nloadtasks, 1);
return (taskinit(target, arg, bindto, UINT_MAX, true));
}
static isc_result_t static isc_result_t
mctxinit(void **target, void *arg) { mctxinit(void **target, void *arg) {
isc_mem_t *mctx = NULL; isc_mem_t *mctx = NULL;
@ -19139,74 +19197,44 @@ mctxfree(void **target) {
*target = NULL; *target = NULL;
} }
#define ZONES_PER_TASK 100 static isc_result_t
#define ZONES_PER_MCTX 1000 zonemgr_setsize(dns_zonemgr_t *zmgr, unsigned int workers) {
isc_result_t
dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
isc_result_t result; isc_result_t result;
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)); /* Create the zone tasks pool. */
REQUIRE(zmgr->zonetasks == NULL);
/* result = isc_pool_create(zmgr->mctx, workers, taskfree, zonetaskinit,
* For anything fewer than 1000 zones we use 10 tasks in zmgr, &zmgr->zonetasks);
* the task pools. More than that, and we'll scale at one if (result != ISC_R_SUCCESS) {
* task per 100 zones. Similarly, for anything smaller than goto fail;
* 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. */ /* Create the zone load tasks pool. */
if (zmgr->zonetasks == NULL) { REQUIRE(zmgr->loadtasks == NULL);
result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx, ntasks, result = isc_pool_create(zmgr->mctx, workers, taskfree, loadtaskinit,
2, false, &pool); zmgr, &zmgr->loadtasks);
} else { if (result != ISC_R_SUCCESS) {
result = isc_taskpool_expand(&zmgr->zonetasks, ntasks, false, goto fail;
&pool);
} }
if (result == ISC_R_SUCCESS) { /* Create the zone memory context pool. */
zmgr->zonetasks = pool; REQUIRE(zmgr->mctxpool == NULL);
result = isc_pool_create(zmgr->mctx, workers, mctxfree, mctxinit, NULL,
&zmgr->mctxpool);
if (result != ISC_R_SUCCESS) {
goto fail;
} }
/* return (ISC_R_SUCCESS);
* We always set all tasks in the zone-load task pool to fail:
* privileged. This prevents other tasks in the system from if (zmgr->mctxpool != NULL) {
* running while the server task manager is in privileged isc_pool_destroy(&zmgr->mctxpool);
* mode.
*/
pool = NULL;
if (zmgr->loadtasks == NULL) {
result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx, ntasks,
UINT_MAX, true, &pool);
} else {
result = isc_taskpool_expand(&zmgr->loadtasks, ntasks, true,
&pool);
} }
if (zmgr->loadtasks != NULL) {
if (result == ISC_R_SUCCESS) { isc_pool_destroy(&zmgr->loadtasks);
zmgr->loadtasks = pool;
} }
if (zmgr->zonetasks != NULL) {
/* Create or resize the zone memory context pool. */ isc_pool_destroy(&zmgr->zonetasks);
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); return (result);

View File

@ -90,7 +90,6 @@ libisc_la_HEADERS = \
include/isc/symtab.h \ include/isc/symtab.h \
include/isc/syslog.h \ include/isc/syslog.h \
include/isc/task.h \ include/isc/task.h \
include/isc/taskpool.h \
include/isc/thread.h \ include/isc/thread.h \
include/isc/time.h \ include/isc/time.h \
include/isc/timer.h \ include/isc/timer.h \
@ -191,7 +190,6 @@ libisc_la_SOURCES = \
syslog.c \ syslog.c \
task.c \ task.c \
task_p.h \ task_p.h \
taskpool.c \
thread.c \ thread.c \
time.c \ time.c \
timer.c \ timer.c \

View File

@ -84,45 +84,7 @@ void *
isc_pool_get(isc_pool_t *pool); isc_pool_get(isc_pool_t *pool);
/*%< /*%<
* Returns a pointer to an object from the pool. Currently the object * 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 * is chosen from the pool at random.
* 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 void

View File

@ -1,135 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
/*****
***** Module Info
*****/
/*! \file isc/taskpool.h
* \brief A task pool is a mechanism for sharing a small number of tasks
* among a large number of objects such that each object is
* assigned a unique task, but each task may be shared by several
* objects.
*
* Task pools are used to let objects that can exist in large
* numbers (e.g., zones) use tasks for synchronization without
* the memory overhead and unfair scheduling competition that
* could result from creating a separate task for each object.
*/
/***
*** Imports.
***/
#include <stdbool.h>
#include <isc/lang.h>
#include <isc/task.h>
ISC_LANG_BEGINDECLS
/*****
***** Types.
*****/
typedef struct isc_taskpool isc_taskpool_t;
/*****
***** Functions.
*****/
isc_result_t
isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
unsigned int quantum, bool priv, isc_taskpool_t **poolp);
/*%<
* Create a task pool of "ntasks" tasks, each with quantum
* "quantum".
*
* Requires:
*
*\li 'tmgr' is a valid task manager.
*
*\li 'mctx' is a valid memory context.
*
*\li poolp != NULL && *poolp == NULL
*
* Ensures:
*
*\li On success, '*taskp' points to the new task pool.
*
* Returns:
*
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*\li #ISC_R_UNEXPECTED
*/
void
isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp);
/*%<
* Attach to a task from the pool. Currently the next task is chosen
* from the pool at random. (This may be changed in the future to
* something that guaratees balance.)
*/
int
isc_taskpool_size(isc_taskpool_t *pool);
/*%<
* Returns the number of tasks in the task pool 'pool'.
*/
isc_result_t
isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size, bool priv,
isc_taskpool_t **targetp);
/*%<
* If 'size' is larger than the number of tasks in the pool pointed to by
* 'sourcep', then a new taskpool of size 'size' is allocated, the existing
* tasks from are moved into it, additional tasks are created to bring the
* total number up to 'size', and the resulting pool is attached to
* 'targetp'.
*
* If 'size' is less than or equal to the tasks in pool '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_taskpool_destroy(isc_taskpool_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

View File

@ -37,24 +37,6 @@ struct isc_pool {
*** Functions. *** 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));
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 *));
memset(pool->pool, 0, count * sizeof(void *));
*poolp = pool;
return (ISC_R_SUCCESS);
}
isc_result_t isc_result_t
isc_pool_create(isc_mem_t *mctx, unsigned int count, isc_pool_create(isc_mem_t *mctx, unsigned int count,
isc_pooldeallocator_t release, isc_poolinitializer_t init, isc_pooldeallocator_t release, isc_poolinitializer_t init,
@ -66,14 +48,16 @@ isc_pool_create(isc_mem_t *mctx, unsigned int count,
INSIST(count > 0); INSIST(count > 0);
/* Allocate the pool structure */ /* Allocate the pool structure */
result = alloc_pool(mctx, count, &pool); pool = isc_mem_get(mctx, sizeof(*pool));
if (result != ISC_R_SUCCESS) { *pool = (isc_pool_t){
return (result); .count = count,
} .free = release,
.init = init,
pool->free = release; .initarg = initarg,
pool->init = init; };
pool->initarg = initarg; isc_mem_attach(mctx, &pool->mctx);
pool->pool = isc_mem_get(mctx, count * sizeof(void *));
memset(pool->pool, 0, count * sizeof(void *));
/* Populate the pool */ /* Populate the pool */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
@ -93,61 +77,6 @@ isc_pool_get(isc_pool_t *pool) {
return (pool->pool[isc_random_uniform(pool->count)]); return (pool->pool[isc_random_uniform(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;
*sourcep = NULL;
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;
/* Populate the new entries */
for (i = pool->count; i < count; i++) {
result = newpool->init(&newpool->pool[i],
newpool->initarg);
if (result != ISC_R_SUCCESS) {
isc_pool_destroy(&newpool);
return (result);
}
}
/* 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;
}
isc_pool_destroy(&pool);
pool = newpool;
}
*targetp = pool;
return (ISC_R_SUCCESS);
}
void void
isc_pool_destroy(isc_pool_t **poolp) { isc_pool_destroy(isc_pool_t **poolp) {
unsigned int i; unsigned int i;

View File

@ -1,157 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <stdbool.h>
#include <isc/mem.h>
#include <isc/random.h>
#include <isc/taskpool.h>
#include <isc/util.h>
/***
*** Types.
***/
struct isc_taskpool {
isc_mem_t *mctx;
isc_taskmgr_t *tmgr;
unsigned int ntasks;
unsigned int quantum;
isc_task_t **tasks;
};
/***
*** Functions.
***/
static void
alloc_pool(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
unsigned int quantum, isc_taskpool_t **poolp) {
isc_taskpool_t *pool;
unsigned int i;
pool = isc_mem_get(mctx, sizeof(*pool));
pool->mctx = NULL;
isc_mem_attach(mctx, &pool->mctx);
pool->ntasks = ntasks;
pool->quantum = quantum;
pool->tmgr = tmgr;
pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
for (i = 0; i < ntasks; i++) {
pool->tasks[i] = NULL;
}
*poolp = pool;
}
isc_result_t
isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks,
unsigned int quantum, bool priv, isc_taskpool_t **poolp) {
unsigned int i;
isc_taskpool_t *pool = NULL;
INSIST(ntasks > 0);
/* Allocate the pool structure */
alloc_pool(tmgr, mctx, ntasks, quantum, &pool);
/* Create the tasks */
for (i = 0; i < ntasks; i++) {
isc_result_t result = isc_task_create_bound(tmgr, quantum,
&pool->tasks[i], i);
if (result != ISC_R_SUCCESS) {
isc_taskpool_destroy(&pool);
return (result);
}
isc_task_setprivilege(pool->tasks[i], priv);
isc_task_setname(pool->tasks[i], "taskpool", NULL);
}
*poolp = pool;
return (ISC_R_SUCCESS);
}
void
isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp) {
isc_task_attach(pool->tasks[isc_random_uniform(pool->ntasks)], targetp);
}
int
isc_taskpool_size(isc_taskpool_t *pool) {
REQUIRE(pool != NULL);
return (pool->ntasks);
}
isc_result_t
isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size, bool priv,
isc_taskpool_t **targetp) {
isc_taskpool_t *pool;
REQUIRE(sourcep != NULL && *sourcep != NULL);
REQUIRE(targetp != NULL && *targetp == NULL);
pool = *sourcep;
*sourcep = NULL;
if (size > pool->ntasks) {
isc_taskpool_t *newpool = NULL;
unsigned int i;
/* Allocate a new pool structure */
alloc_pool(pool->tmgr, pool->mctx, size, pool->quantum,
&newpool);
/* Copy over the tasks from the old pool */
for (i = 0; i < pool->ntasks; i++) {
newpool->tasks[i] = pool->tasks[i];
pool->tasks[i] = NULL;
}
/* Create new tasks */
for (i = pool->ntasks; i < size; i++) {
isc_result_t result =
isc_task_create_bound(pool->tmgr, pool->quantum,
&newpool->tasks[i], i);
if (result != ISC_R_SUCCESS) {
*sourcep = pool;
isc_taskpool_destroy(&newpool);
return (result);
}
isc_task_setprivilege(newpool->tasks[i], priv);
isc_task_setname(newpool->tasks[i], "taskpool", NULL);
}
isc_taskpool_destroy(&pool);
pool = newpool;
}
*targetp = pool;
return (ISC_R_SUCCESS);
}
void
isc_taskpool_destroy(isc_taskpool_t **poolp) {
unsigned int i;
isc_taskpool_t *pool = *poolp;
*poolp = NULL;
for (i = 0; i < pool->ntasks; i++) {
if (pool->tasks[i] != NULL) {
isc_task_detach(&pool->tasks[i]);
}
}
isc_mem_put(pool->mctx, pool->tasks,
pool->ntasks * sizeof(isc_task_t *));
isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool));
}

View File

@ -42,7 +42,6 @@ check_PROGRAMS = \
stats_test \ stats_test \
symtab_test \ symtab_test \
task_test \ task_test \
taskpool_test \
time_test \ time_test \
timer_test timer_test

View File

@ -84,57 +84,11 @@ create_pool(void **state) {
result = isc_pool_create(test_mctx, 8, poolfree, poolinit, taskmgr, result = isc_pool_create(test_mctx, 8, poolfree, poolinit, taskmgr,
&pool); &pool);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool), 8);
isc_pool_destroy(&pool); isc_pool_destroy(&pool);
assert_null(pool); assert_null(pool);
} }
/* Resize a pool */
static void
expand_pool(void **state) {
isc_result_t result;
isc_pool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
UNUSED(state);
result = isc_pool_create(test_mctx, 10, poolfree, poolinit, taskmgr,
&pool1);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool1), 10);
/* resizing to a smaller size should have no effect */
hold = pool1;
result = isc_pool_expand(&pool1, 5, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool2), 10);
assert_ptr_equal(pool2, hold);
assert_null(pool1);
pool1 = pool2;
pool2 = NULL;
/* resizing to the same size should have no effect */
hold = pool1;
result = isc_pool_expand(&pool1, 10, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool2), 10);
assert_ptr_equal(pool2, hold);
assert_null(pool1);
pool1 = pool2;
pool2 = NULL;
/* resizing to larger size should make a new pool */
hold = pool1;
result = isc_pool_expand(&pool1, 20, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool2), 20);
assert_ptr_not_equal(pool2, hold);
assert_null(pool1);
isc_pool_destroy(&pool2);
assert_null(pool2);
}
/* Get objects */ /* Get objects */
static void static void
get_objects(void **state) { get_objects(void **state) {
@ -148,7 +102,6 @@ get_objects(void **state) {
result = isc_pool_create(test_mctx, 2, poolfree, poolinit, taskmgr, result = isc_pool_create(test_mctx, 2, poolfree, poolinit, taskmgr,
&pool); &pool);
assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_pool_count(pool), 2);
item = isc_pool_get(pool); item = isc_pool_get(pool);
assert_non_null(item); assert_non_null(item);
@ -174,7 +127,6 @@ int
main(void) { main(void) {
const struct CMUnitTest tests[] = { const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(create_pool, _setup, _teardown), cmocka_unit_test_setup_teardown(create_pool, _setup, _teardown),
cmocka_unit_test_setup_teardown(expand_pool, _setup, _teardown),
cmocka_unit_test_setup_teardown(get_objects, _setup, _teardown), cmocka_unit_test_setup_teardown(get_objects, _setup, _teardown),
}; };

View File

@ -1,204 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#if HAVE_CMOCKA
#include <sched.h> /* IWYU pragma: keep */
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/task.h>
#include <isc/taskpool.h>
#include <isc/util.h>
#include "isctest.h"
#define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K')
#define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC)
static int
_setup(void **state) {
isc_result_t result;
UNUSED(state);
result = isc_test_begin(NULL, true, 0);
assert_int_equal(result, ISC_R_SUCCESS);
return (0);
}
static int
_teardown(void **state) {
UNUSED(state);
isc_test_end();
return (0);
}
/* Create a taskpool */
static void
create_pool(void **state) {
isc_result_t result;
isc_taskpool_t *pool = NULL;
UNUSED(state);
result = isc_taskpool_create(taskmgr, test_mctx, 8, 2, false, &pool);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool), 8);
isc_taskpool_destroy(&pool);
assert_null(pool);
}
/* Resize a taskpool */
static void
expand_pool(void **state) {
isc_result_t result;
isc_taskpool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL;
UNUSED(state);
result = isc_taskpool_create(taskmgr, test_mctx, 10, 2, false, &pool1);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool1), 10);
/* resizing to a smaller size should have no effect */
hold = pool1;
result = isc_taskpool_expand(&pool1, 5, false, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool2), 10);
assert_ptr_equal(pool2, hold);
assert_null(pool1);
pool1 = pool2;
pool2 = NULL;
/* resizing to the same size should have no effect */
hold = pool1;
result = isc_taskpool_expand(&pool1, 10, false, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool2), 10);
assert_ptr_equal(pool2, hold);
assert_null(pool1);
pool1 = pool2;
pool2 = NULL;
/* resizing to larger size should make a new pool */
hold = pool1;
result = isc_taskpool_expand(&pool1, 20, false, &pool2);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool2), 20);
assert_ptr_not_equal(pool2, hold);
assert_null(pool1);
isc_taskpool_destroy(&pool2);
assert_null(pool2);
}
/* Get tasks */
static void
get_tasks(void **state) {
isc_result_t result;
isc_taskpool_t *pool = NULL;
isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
UNUSED(state);
result = isc_taskpool_create(taskmgr, test_mctx, 2, 2, false, &pool);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool), 2);
/* two tasks in pool; make sure we can access them more than twice */
isc_taskpool_gettask(pool, &task1);
assert_true(VALID_TASK(task1));
isc_taskpool_gettask(pool, &task2);
assert_true(VALID_TASK(task2));
isc_taskpool_gettask(pool, &task3);
assert_true(VALID_TASK(task3));
isc_task_destroy(&task1);
isc_task_destroy(&task2);
isc_task_destroy(&task3);
isc_taskpool_destroy(&pool);
assert_null(pool);
}
/* Set privileges */
static void
set_privilege(void **state) {
isc_result_t result;
isc_taskpool_t *pool = NULL;
isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
UNUSED(state);
result = isc_taskpool_create(taskmgr, test_mctx, 2, 2, true, &pool);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(isc_taskpool_size(pool), 2);
isc_taskpool_gettask(pool, &task1);
isc_taskpool_gettask(pool, &task2);
isc_taskpool_gettask(pool, &task3);
assert_true(VALID_TASK(task1));
assert_true(VALID_TASK(task2));
assert_true(VALID_TASK(task3));
assert_true(isc_task_getprivilege(task1));
assert_true(isc_task_getprivilege(task2));
assert_true(isc_task_getprivilege(task3));
isc_task_destroy(&task1);
isc_task_destroy(&task2);
isc_task_destroy(&task3);
isc_taskpool_destroy(&pool);
assert_null(pool);
}
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(create_pool, _setup, _teardown),
cmocka_unit_test_setup_teardown(expand_pool, _setup, _teardown),
cmocka_unit_test_setup_teardown(get_tasks, _setup, _teardown),
cmocka_unit_test_setup_teardown(set_privilege, _setup,
_teardown),
};
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (SKIPPED_TEST_EXIT_CODE);
}
#endif /* if HAVE_CMOCKA */

View File

@ -448,7 +448,8 @@ ns_test_setupzonemgr(void) {
isc_result_t result; isc_result_t result;
REQUIRE(zonemgr == NULL); REQUIRE(zonemgr == NULL);
result = dns_zonemgr_create(mctx, taskmgr, timermgr, NULL, &zonemgr); result = dns_zonemgr_create(mctx, taskmgr, timermgr, NULL, ncpus,
&zonemgr);
return (result); return (result);
} }
@ -457,11 +458,6 @@ ns_test_managezone(dns_zone_t *zone) {
isc_result_t result; isc_result_t result;
REQUIRE(zonemgr != NULL); REQUIRE(zonemgr != NULL);
result = dns_zonemgr_setsize(zonemgr, 1);
if (result != ISC_R_SUCCESS) {
return (result);
}
result = dns_zonemgr_managezone(zonemgr, zone); result = dns_zonemgr_managezone(zonemgr, zone);
return (result); return (result);
} }

View File

@ -19,7 +19,6 @@
#include <isc/serial.h> #include <isc/serial.h>
#include <isc/stats.h> #include <isc/stats.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/taskpool.h>
#include <isc/util.h> #include <isc/util.h>
#include <dns/db.h> #include <dns/db.h>