From 0cc5eddce25de7560a951a6a7495cc62f03a4e81 Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Mon, 20 Nov 2017 16:48:48 +0100 Subject: [PATCH] extbans/timedban (~t): fix unset not working for +e/+I and reduce load by spreading the unset event over multiple events (process roughly a quarter each time). Not important for small networks but for big ones.. --- src/modules/extbans/timedban.c | 56 ++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/modules/extbans/timedban.c b/src/modules/extbans/timedban.c index 933a03bc2..bc36d5345 100644 --- a/src/modules/extbans/timedban.c +++ b/src/modules/extbans/timedban.c @@ -25,15 +25,28 @@ #define TIMEDBAN_VERSION "v1.0" -/* Call timeout event every seconds */ -#define TIMEDBAN_TIMER 5 - /* Maximum time (in minutes) for a ban */ #define TIMEDBAN_MAX_TIME 9999 /* Maximum length of a ban */ #define MAX_LENGTH 128 +/* Split timeout event in amount of iterations */ +#define TIMEDBAN_TIMER_ITERATION_SPLIT 4 + +/* Call timeout event every seconds. + * NOTE: until all channels are processed it takes + * TIMEDBAN_TIMER_ITERATION_SPLIT * TIMEDBAN_TIMER. + */ +#define TIMEDBAN_TIMER 2 + +/* We allow a ban to (potentially) expire slightly before the deadline. + * For example with TIMEDBAN_TIMER_ITERATION_SPLIT=4 and TIMEDBAN_TIMER=2 + * a 1 minute ban would expire at 56-63 seconds, rather than 60-67 seconds. + * This is usually preferred. + */ +#define TIMEDBAN_TIMER_DELTA ((TIMEDBAN_TIMER_ITERATION_SPLIT*TIMEDBAN_TIMER)/2) + ModuleHeader MOD_HEADER(timedban) = { "timedban", @@ -359,7 +372,7 @@ TS expire_on; t = atoi(banstr+3); *p = ':'; /* restored.. */ - expire_on = ban->when + (t * 60); + expire_on = ban->when + (t * 60) - TIMEDBAN_TIMER_DELTA; if (expire_on < TStime()) return 1; @@ -372,11 +385,24 @@ static char pbuf[512]; /** This removes any expired timedbans */ EVENT(timedban_timeout) { -aChannel *chptr; -Ban *ban, *nextban; + aChannel *chptr; + Ban *ban, *nextban; + static int current_iteration = 0; + + if (++current_iteration >= TIMEDBAN_TIMER_ITERATION_SPLIT) + current_iteration = 0; for (chptr = channel; chptr; chptr = chptr->nextch) { + /* This is a very quick check, at the cost of it being + * biased since there's always a tendency of more channel + * names to start with one specific letter. But hashing + * is too costly. So we stick with this. It should be + * good enough. Alternative would be some chptr->id value. + */ + if (((unsigned int)chptr->chname[1] % TIMEDBAN_TIMER_ITERATION_SPLIT) != current_iteration) + continue; /* not this time, maybe next */ + *mbuf = *pbuf = '\0'; for (ban = chptr->banlist; ban; ban=nextban) { @@ -387,6 +413,24 @@ Ban *ban, *nextban; del_listmode(&chptr->banlist, chptr, ban->banstr); } } + for (ban = chptr->exlist; ban; ban=nextban) + { + nextban = ban->next; + if (!strncmp(ban->banstr, "~t:", 3) && timedban_has_ban_expired(ban)) + { + add_send_mode_param(chptr, &me, '-', 'b', ban->banstr); + del_listmode(&chptr->exlist, chptr, ban->banstr); + } + } + for (ban = chptr->invexlist; ban; ban=nextban) + { + nextban = ban->next; + if (!strncmp(ban->banstr, "~t:", 3) && timedban_has_ban_expired(ban)) + { + add_send_mode_param(chptr, &me, '-', 'b', ban->banstr); + del_listmode(&chptr->invexlist, chptr, ban->banstr); + } + } if (*pbuf) { sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s", me.name, chptr->chname, mbuf, pbuf);