mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-03 13:59:27 -04:00
Merge branch '3555-refactor-isc_ratelimiter-API' into 'main'
Refactor isc_ratelimiter API Closes #3555 See merge request isc-projects/bind9!6842
This commit is contained in:
commit
9beb68513b
7 changed files with 450 additions and 85 deletions
|
|
@ -10008,6 +10008,11 @@ run_server(isc_task_t *task, isc_event_t *event) {
|
|||
|
||||
isc_event_free(&event);
|
||||
|
||||
CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_loopmgr,
|
||||
named_g_taskmgr, named_g_netmgr,
|
||||
&server->zonemgr),
|
||||
"dns_zonemgr_create");
|
||||
|
||||
CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, named_g_netmgr,
|
||||
&named_g_dispatchmgr),
|
||||
"creating dispatch manager");
|
||||
|
|
@ -10322,11 +10327,6 @@ named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
|
|||
server->sighup = isc_signal_new(
|
||||
named_g_loopmgr, named_server_reloadwanted, server, SIGHUP);
|
||||
|
||||
CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_loopmgr,
|
||||
named_g_taskmgr, named_g_netmgr,
|
||||
&server->zonemgr),
|
||||
"dns_zonemgr_create");
|
||||
|
||||
CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
|
||||
isc_sockstatscounter_max),
|
||||
"isc_stats_create");
|
||||
|
|
|
|||
|
|
@ -18865,7 +18865,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
|||
dns_zonemgr_t **zmgrp) {
|
||||
dns_zonemgr_t *zmgr;
|
||||
isc_result_t result;
|
||||
isc_loop_t *mainloop = isc_loop_main(loopmgr);
|
||||
isc_loop_t *loop = isc_loop_current(loopmgr);
|
||||
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(loopmgr != NULL);
|
||||
|
|
@ -18899,35 +18899,11 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
|
|||
/* Unreachable lock. */
|
||||
isc_rwlock_init(&zmgr->urlock, 0, 0);
|
||||
|
||||
result = isc_ratelimiter_create(mainloop, &zmgr->checkdsrl);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto free_urlock;
|
||||
}
|
||||
|
||||
result = isc_ratelimiter_create(mainloop, &zmgr->notifyrl);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto free_checkdsrl;
|
||||
}
|
||||
|
||||
result = isc_ratelimiter_create(mainloop, &zmgr->refreshrl);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto free_notifyrl;
|
||||
}
|
||||
|
||||
result = isc_ratelimiter_create(mainloop, &zmgr->startupnotifyrl);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto free_refreshrl;
|
||||
}
|
||||
|
||||
result = isc_ratelimiter_create(mainloop, &zmgr->startuprefreshrl);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto free_startupnotifyrl;
|
||||
}
|
||||
isc_ratelimiter_create(loop, &zmgr->checkdsrl);
|
||||
isc_ratelimiter_create(loop, &zmgr->notifyrl);
|
||||
isc_ratelimiter_create(loop, &zmgr->refreshrl);
|
||||
isc_ratelimiter_create(loop, &zmgr->startupnotifyrl);
|
||||
isc_ratelimiter_create(loop, &zmgr->startuprefreshrl);
|
||||
|
||||
zmgr->zonetasks = isc_mem_get(
|
||||
zmgr->mctx, zmgr->workers * sizeof(zmgr->zonetasks[0]));
|
||||
|
|
@ -19012,19 +18988,15 @@ free_zonetasks:
|
|||
|
||||
isc_ratelimiter_shutdown(zmgr->startuprefreshrl);
|
||||
isc_ratelimiter_detach(&zmgr->startuprefreshrl);
|
||||
free_startupnotifyrl:
|
||||
isc_ratelimiter_shutdown(zmgr->startupnotifyrl);
|
||||
isc_ratelimiter_detach(&zmgr->startupnotifyrl);
|
||||
free_refreshrl:
|
||||
isc_ratelimiter_shutdown(zmgr->refreshrl);
|
||||
isc_ratelimiter_detach(&zmgr->refreshrl);
|
||||
free_notifyrl:
|
||||
isc_ratelimiter_shutdown(zmgr->notifyrl);
|
||||
isc_ratelimiter_detach(&zmgr->notifyrl);
|
||||
free_checkdsrl:
|
||||
isc_ratelimiter_shutdown(zmgr->checkdsrl);
|
||||
isc_ratelimiter_detach(&zmgr->checkdsrl);
|
||||
free_urlock:
|
||||
|
||||
isc_rwlock_destroy(&zmgr->urlock);
|
||||
isc_rwlock_destroy(&zmgr->rwlock);
|
||||
isc_mem_put(zmgr->mctx, zmgr, sizeof(*zmgr));
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ ISC_LANG_BEGINDECLS
|
|||
***** Functions.
|
||||
*****/
|
||||
|
||||
isc_result_t
|
||||
isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **ratelimiterp);
|
||||
void
|
||||
isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **rlp);
|
||||
/*%<
|
||||
* Create a rate limiter. The execution interval is initially undefined.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ isc_refcount_decrement(isc_refcount_t *target) {
|
|||
} \
|
||||
\
|
||||
void name##_detach(name##_t **ptrp) { \
|
||||
REQUIRE(ptrp != NULL && *ptrp != NULL); \
|
||||
name##_t *ptr = *ptrp; \
|
||||
*ptrp = NULL; \
|
||||
name##_unref(ptr); \
|
||||
|
|
|
|||
|
|
@ -52,14 +52,23 @@ struct isc_ratelimiter {
|
|||
};
|
||||
|
||||
static void
|
||||
ratelimiter_tick(void *arg);
|
||||
isc__ratelimiter_tick(void *arg);
|
||||
|
||||
isc_result_t
|
||||
isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **ratelimiterp) {
|
||||
static void
|
||||
isc__ratelimiter_start(void *arg);
|
||||
|
||||
static void
|
||||
isc__ratelimiter_doshutdown(void *arg);
|
||||
|
||||
void
|
||||
isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **rlp) {
|
||||
isc_ratelimiter_t *rl = NULL;
|
||||
isc_mem_t *mctx = isc_loop_getmctx(loop);
|
||||
isc_mem_t *mctx;
|
||||
|
||||
INSIST(ratelimiterp != NULL && *ratelimiterp == NULL);
|
||||
REQUIRE(loop != NULL);
|
||||
REQUIRE(rlp != NULL && *rlp == NULL);
|
||||
|
||||
mctx = isc_loop_getmctx(loop);
|
||||
|
||||
rl = isc_mem_get(mctx, sizeof(*rl));
|
||||
*rl = (isc_ratelimiter_t){
|
||||
|
|
@ -74,10 +83,11 @@ isc_ratelimiter_create(isc_loop_t *loop, isc_ratelimiter_t **ratelimiterp) {
|
|||
isc_interval_set(&rl->interval, 0, 0);
|
||||
ISC_LIST_INIT(rl->pending);
|
||||
|
||||
isc_timer_create(rl->loop, isc__ratelimiter_tick, rl, &rl->timer);
|
||||
|
||||
isc_mutex_init(&rl->lock);
|
||||
|
||||
*ratelimiterp = rl;
|
||||
return (ISC_R_SUCCESS);
|
||||
*rlp = rl;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -87,10 +97,7 @@ isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) {
|
|||
|
||||
LOCK(&rl->lock);
|
||||
rl->interval = *interval;
|
||||
/*
|
||||
* If the timer is currently running, its rate will change during
|
||||
* the next tick.
|
||||
*/
|
||||
/* The interval will be adjusted on the next tick */
|
||||
UNLOCK(&rl->lock);
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +120,37 @@ isc_ratelimiter_setpushpop(isc_ratelimiter_t *rl, bool pushpop) {
|
|||
UNLOCK(&rl->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
isc__ratelimiter_start(void *arg) {
|
||||
isc_ratelimiter_t *rl = arg;
|
||||
isc_interval_t interval;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
||||
LOCK(&rl->lock);
|
||||
switch (rl->state) {
|
||||
case isc_ratelimiter_ratelimited:
|
||||
/* The first tick happens immediately */
|
||||
isc_interval_set(&interval, 0, 0);
|
||||
isc_timer_start(rl->timer, isc_timertype_once, &interval);
|
||||
break;
|
||||
case isc_ratelimiter_shuttingdown:
|
||||
/* The ratelimiter is shutting down */
|
||||
break;
|
||||
case isc_ratelimiter_idle:
|
||||
/*
|
||||
* This could happen if we are changing the interval on the
|
||||
* ratelimiter, but all the events were processed and the timer
|
||||
* was stopped before the new interval could be applied.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNLOCK(&rl->lock);
|
||||
isc_ratelimiter_detach(&rl);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
|
||||
isc_event_t **eventp) {
|
||||
|
|
@ -133,9 +171,9 @@ isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task,
|
|||
case isc_ratelimiter_idle:
|
||||
/* Start the ratelimiter */
|
||||
isc_ratelimiter_ref(rl);
|
||||
isc_async_run(rl->loop, ratelimiter_tick, rl);
|
||||
isc_async_run(rl->loop, isc__ratelimiter_start, rl);
|
||||
rl->state = isc_ratelimiter_ratelimited;
|
||||
/* FALLTHROUGH */
|
||||
FALLTHROUGH;
|
||||
case isc_ratelimiter_ratelimited:
|
||||
event->ev_sender = task;
|
||||
*eventp = NULL;
|
||||
|
|
@ -172,11 +210,10 @@ isc_ratelimiter_dequeue(isc_ratelimiter_t *rl, isc_event_t *event) {
|
|||
}
|
||||
|
||||
static void
|
||||
ratelimiter_tick(void *arg) {
|
||||
isc__ratelimiter_tick(void *arg) {
|
||||
isc_ratelimiter_t *rl = (isc_ratelimiter_t *)arg;
|
||||
isc_event_t *event;
|
||||
uint32_t pertic;
|
||||
bool do_destroy = false;
|
||||
ISC_LIST(isc_event_t) pending;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
|
@ -184,68 +221,88 @@ ratelimiter_tick(void *arg) {
|
|||
ISC_LIST_INIT(pending);
|
||||
|
||||
LOCK(&rl->lock);
|
||||
|
||||
REQUIRE(rl->timer != NULL);
|
||||
|
||||
if (rl->state == isc_ratelimiter_shuttingdown) {
|
||||
UNLOCK(&rl->lock);
|
||||
do_destroy = (rl->timer != NULL);
|
||||
goto done;
|
||||
INSIST(EMPTY(rl->pending));
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (rl->timer == NULL) {
|
||||
isc_timer_create(rl->loop, ratelimiter_tick, rl, &rl->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the timer was already running with a different rate,
|
||||
* this updates it to the correct one.
|
||||
*/
|
||||
isc_timer_start(rl->timer, isc_timertype_ticker, &rl->interval);
|
||||
|
||||
pertic = rl->pertic;
|
||||
while (pertic != 0) {
|
||||
pertic--;
|
||||
event = ISC_LIST_HEAD(rl->pending);
|
||||
if (event != NULL) {
|
||||
/* There is work to do. Let's do it after unlocking. */
|
||||
ISC_LIST_UNLINK(rl->pending, event, ev_ratelink);
|
||||
ISC_LIST_APPEND(pending, event, ev_ratelink);
|
||||
} else {
|
||||
/* There's no more work to do, destroy the timer */
|
||||
do_destroy = true;
|
||||
/*
|
||||
* We processed all the scheduled work, but there's a
|
||||
* room for at least one more event (we haven't consumed
|
||||
* all of the "pertick"), so we can stop the ratelimiter
|
||||
* now, and don't worry about isc_ratelimiter_enqueue()
|
||||
* sending an extra event immediately.
|
||||
*/
|
||||
rl->state = isc_ratelimiter_idle;
|
||||
break;
|
||||
}
|
||||
pertic--;
|
||||
}
|
||||
|
||||
if (rl->state != isc_ratelimiter_idle) {
|
||||
/* Reschedule the timer */
|
||||
isc_timer_start(rl->timer, isc_timertype_once, &rl->interval);
|
||||
}
|
||||
unlock:
|
||||
UNLOCK(&rl->lock);
|
||||
|
||||
while ((event = ISC_LIST_HEAD(pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(pending, event, ev_ratelink);
|
||||
isc_task_send(event->ev_sender, &event);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* No work left to do. Stop and destroy the timer. */
|
||||
if (do_destroy) {
|
||||
isc_timer_destroy(&rl->timer);
|
||||
isc_ratelimiter_detach(&rl);
|
||||
}
|
||||
void
|
||||
isc__ratelimiter_doshutdown(void *arg) {
|
||||
isc_ratelimiter_t *rl = arg;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
||||
LOCK(&rl->lock);
|
||||
INSIST(rl->state == isc_ratelimiter_shuttingdown);
|
||||
INSIST(EMPTY(rl->pending));
|
||||
|
||||
isc_timer_stop(rl->timer);
|
||||
isc_timer_destroy(&rl->timer);
|
||||
isc_loop_detach(&rl->loop);
|
||||
UNLOCK(&rl->lock);
|
||||
isc_ratelimiter_detach(&rl);
|
||||
}
|
||||
|
||||
void
|
||||
isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) {
|
||||
isc_event_t *event;
|
||||
ISC_LIST(isc_event_t) pending;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
||||
LOCK(&rl->lock);
|
||||
rl->state = isc_ratelimiter_shuttingdown;
|
||||
ISC_LIST_INIT(pending);
|
||||
|
||||
while ((event = ISC_LIST_HEAD(rl->pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(rl->pending, event, ev_ratelink);
|
||||
LOCK(&rl->lock);
|
||||
if (rl->state != isc_ratelimiter_shuttingdown) {
|
||||
rl->state = isc_ratelimiter_shuttingdown;
|
||||
ISC_LIST_MOVE(pending, rl->pending);
|
||||
isc_ratelimiter_ref(rl);
|
||||
isc_async_run(rl->loop, isc__ratelimiter_doshutdown, rl);
|
||||
}
|
||||
UNLOCK(&rl->lock);
|
||||
|
||||
while ((event = ISC_LIST_HEAD(pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(pending, event, ev_ratelink);
|
||||
event->ev_attributes |= ISC_EVENTATTR_CANCELED;
|
||||
isc_task_send(event->ev_sender, &event);
|
||||
}
|
||||
isc_loop_detach(&rl->loop);
|
||||
UNLOCK(&rl->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ check_PROGRAMS = \
|
|||
quota_test \
|
||||
radix_test \
|
||||
random_test \
|
||||
ratelimiter_test\
|
||||
regex_test \
|
||||
result_test \
|
||||
safe_test \
|
||||
|
|
|
|||
334
tests/isc/ratelimiter_test.c
Normal file
334
tests/isc/ratelimiter_test.c
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#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/event.h>
|
||||
#include <isc/job.h>
|
||||
#include <isc/loop.h>
|
||||
#include <isc/ratelimiter.h>
|
||||
#include <isc/task.h>
|
||||
|
||||
#include "ratelimiter.c"
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
|
||||
|
||||
isc_ratelimiter_t *rl = NULL;
|
||||
|
||||
ISC_LOOP_TEST_IMPL(ratelimiter_create) {
|
||||
rl = NULL;
|
||||
expect_assert_failure(isc_ratelimiter_create(NULL, &rl));
|
||||
expect_assert_failure(isc_ratelimiter_create(mainloop, NULL));
|
||||
rl = (isc_ratelimiter_t *)&rl;
|
||||
expect_assert_failure(isc_ratelimiter_create(mainloop, &rl));
|
||||
|
||||
rl = NULL;
|
||||
isc_ratelimiter_create(mainloop, &rl);
|
||||
isc_ratelimiter_shutdown(rl);
|
||||
|
||||
isc_ratelimiter_detach(&rl);
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_IMPL(ratelimiter_shutdown) {
|
||||
rl = NULL;
|
||||
|
||||
expect_assert_failure(isc_ratelimiter_shutdown(NULL));
|
||||
expect_assert_failure(isc_ratelimiter_shutdown(rl));
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_IMPL(ratelimiter_detach) {
|
||||
rl = NULL;
|
||||
|
||||
expect_assert_failure(isc_ratelimiter_detach(NULL));
|
||||
expect_assert_failure(isc_ratelimiter_detach(&rl));
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
}
|
||||
|
||||
static int ticks = 0;
|
||||
static isc_task_t *rl_task = NULL;
|
||||
static isc_time_t start_time;
|
||||
static isc_time_t tick_time;
|
||||
|
||||
static void
|
||||
tick(isc_task_t *task, isc_event_t *event) {
|
||||
assert_ptr_equal(task, rl_task);
|
||||
isc_event_free(&event);
|
||||
|
||||
ticks++;
|
||||
|
||||
assert_int_equal(isc_time_now(&tick_time), ISC_R_SUCCESS);
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
|
||||
isc_task_detach(&rl_task);
|
||||
isc_ratelimiter_shutdown(rl);
|
||||
isc_ratelimiter_detach(&rl);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_common) {
|
||||
isc_result_t result = isc_task_create(taskmgr, &rl_task, 0);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
rl = NULL;
|
||||
isc_time_set(&tick_time, 0, 0);
|
||||
assert_int_equal(isc_time_now(&start_time), ISC_R_SUCCESS);
|
||||
isc_ratelimiter_create(mainloop, &rl);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_enqueue) {
|
||||
ticks = 0;
|
||||
setup_loop_ratelimiter_common(arg);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue) { assert_int_equal(ticks, 1); }
|
||||
|
||||
ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue) {
|
||||
isc_result_t result;
|
||||
isc_event_t *event = NULL;
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
result = isc_ratelimiter_enqueue(rl, rl_task, &event);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_enqueue_shutdown) {
|
||||
ticks = 0;
|
||||
setup_loop_ratelimiter_common(arg);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) {
|
||||
assert_int_equal(ticks, 1);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_enqueue_shutdown) {
|
||||
isc_event_t *event = NULL;
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
expect_assert_failure(isc_ratelimiter_enqueue(NULL, rl_task, &event));
|
||||
expect_assert_failure(isc_ratelimiter_enqueue(rl, NULL, &event));
|
||||
expect_assert_failure(isc_ratelimiter_enqueue(rl, rl_task, NULL));
|
||||
expect_assert_failure(
|
||||
isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ NULL }));
|
||||
|
||||
assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
isc_ratelimiter_shutdown(rl);
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event),
|
||||
ISC_R_SHUTTINGDOWN);
|
||||
|
||||
isc_event_free(&event);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_dequeue) {
|
||||
ticks = 0;
|
||||
setup_loop_ratelimiter_common(arg);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEARDOWN_IMPL(ratelimiter_dequeue) { /* */
|
||||
assert_int_equal(ticks, 1);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_dequeue) {
|
||||
isc_event_t *event = NULL;
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
assert_int_equal(
|
||||
isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }),
|
||||
ISC_R_SUCCESS);
|
||||
assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_SUCCESS);
|
||||
isc_event_free(&event);
|
||||
assert_null(event);
|
||||
|
||||
/* This event didn't get scheduled */
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
assert_int_equal(isc_ratelimiter_dequeue(rl, event), ISC_R_NOTFOUND);
|
||||
assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event),
|
||||
ISC_R_SUCCESS);
|
||||
assert_null(event);
|
||||
}
|
||||
|
||||
static isc_time_t tock_time;
|
||||
|
||||
static void
|
||||
tock(isc_task_t *task, isc_event_t *event) {
|
||||
assert_ptr_equal(task, rl_task);
|
||||
isc_event_free(&event);
|
||||
|
||||
ticks++;
|
||||
assert_int_equal(isc_time_now(&tock_time), ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_pertick_interval) {
|
||||
ticks = 0;
|
||||
isc_time_set(&tock_time, 0, 0);
|
||||
setup_loop_ratelimiter_common(arg);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pertick_interval) {
|
||||
uint64_t t = isc_time_microdiff(&tick_time, &tock_time);
|
||||
assert_int_equal(ticks, 2);
|
||||
assert_true(t >= 1000000);
|
||||
|
||||
t = isc_time_microdiff(&tock_time, &start_time);
|
||||
assert_true(t < 1000000);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pertick_interval) {
|
||||
isc_event_t *event = NULL;
|
||||
isc_interval_t interval;
|
||||
|
||||
isc_interval_set(&interval, 1, NS_PER_S / 10);
|
||||
|
||||
expect_assert_failure(isc_ratelimiter_setinterval(NULL, &interval));
|
||||
expect_assert_failure(isc_ratelimiter_setinterval(rl, NULL));
|
||||
expect_assert_failure(isc_ratelimiter_setpertic(NULL, 1));
|
||||
expect_assert_failure(isc_ratelimiter_setpertic(rl, 0));
|
||||
expect_assert_failure(isc_ratelimiter_setpushpop(NULL, false));
|
||||
|
||||
isc_ratelimiter_setinterval(rl, &interval);
|
||||
isc_ratelimiter_setpertic(rl, 1);
|
||||
isc_ratelimiter_setpushpop(rl, false);
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
assert_int_equal(isc_ratelimiter_enqueue(rl, rl_task, &event),
|
||||
ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
ISC_LOOP_SETUP_IMPL(ratelimiter_pushpop) {
|
||||
ticks = 0;
|
||||
isc_time_set(&tock_time, 0, 0);
|
||||
setup_loop_ratelimiter_common(arg);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEARDOWN_IMPL(ratelimiter_pushpop) {
|
||||
uint64_t t = isc_time_microdiff(&tock_time, &tick_time);
|
||||
assert_int_equal(ticks, 2);
|
||||
assert_true(t < 1000000);
|
||||
}
|
||||
|
||||
ISC_LOOP_TEST_SETUP_TEARDOWN_IMPL(ratelimiter_pushpop) {
|
||||
isc_event_t *event = NULL;
|
||||
isc_interval_t interval;
|
||||
|
||||
isc_interval_set(&interval, 1, NS_PER_S / 10);
|
||||
|
||||
isc_ratelimiter_setinterval(rl, &interval);
|
||||
isc_ratelimiter_setpertic(rl, 2);
|
||||
isc_ratelimiter_setpushpop(rl, true);
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tick, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
assert_int_equal(
|
||||
isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
event = isc_event_allocate(mctx, NULL, ISC_TASKEVENT_TEST, tock, NULL,
|
||||
sizeof(isc_event_t));
|
||||
assert_non_null(event);
|
||||
|
||||
assert_int_equal(
|
||||
isc_ratelimiter_enqueue(rl, rl_task, &(isc_event_t *){ event }),
|
||||
ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
setup_test(void **state) {
|
||||
int r;
|
||||
|
||||
r = setup_loopmgr(state);
|
||||
if (r != 0) {
|
||||
return (r);
|
||||
}
|
||||
r = setup_taskmgr(state);
|
||||
if (r != 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
teardown_test(void **state) {
|
||||
int r;
|
||||
|
||||
r = teardown_taskmgr(state);
|
||||
if (r != 0) {
|
||||
return (r);
|
||||
}
|
||||
r = teardown_loopmgr(state);
|
||||
if (r != 0) {
|
||||
return (r);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_create, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_shutdown, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_detach, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_enqueue, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_enqueue_shutdown, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_dequeue, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_pertick_interval, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(ratelimiter_pushpop, setup_test, teardown_test)
|
||||
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
Loading…
Reference in a new issue