From 262958b8a01e594e3d9e2da75b1e56425a3c5cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 16 Oct 2013 19:22:53 +0200 Subject: [PATCH 1/2] Rework rate limit to only refill when needed --- include/ucore/rate_limit.h | 7 ++-- src/rate_limit.c | 77 +++++++++++++++++++------------------- test/test_ratelimit.c | 14 +++---- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/include/ucore/rate_limit.h b/include/ucore/rate_limit.h index 0437674..fedfd55 100644 --- a/include/ucore/rate_limit.h +++ b/include/ucore/rate_limit.h @@ -65,8 +65,8 @@ struct RateLimit { * @param tickets number of tickets (bucket depth) * @param period per this period */ -#define UC_RATELIMIT_INITIALIZER(tickets, period)\ -{ tickets, period, tickets * period, 0} +#define UC_RATELIMIT_INITIALIZER(tickets)\ +{ tickets, period, 0, -period} @@ -79,9 +79,8 @@ struct RateLimit { * @param r RateLimit to initialize * @param tickets number of tickets (bucket depth) * @param period per this period - * @param current_ts the current timestamp */ -void uc_ratelimit_init(struct RateLimit *r, long tickets, long period, long current_ts); +void uc_ratelimit_init(struct RateLimit *r, long tickets, long period); /** * Reset a RateLimit, filling up the tickets again. diff --git a/src/rate_limit.c b/src/rate_limit.c index 5805967..14299fe 100644 --- a/src/rate_limit.c +++ b/src/rate_limit.c @@ -1,18 +1,18 @@ #include +#include #include "ucore/rate_limit.h" -void uc_ratelimit_init(struct RateLimit *r, long tickets, long period, long current_ts) +void uc_ratelimit_init(struct RateLimit *r, long tickets, long period) { r->tickets = tickets; r->period = period; - r->funds = r->period * tickets; - r->last_ts = current_ts; + r->funds = 0; //we fill it on first _allow call + r->last_ts = -period; //-period ensures the first tick can start + //at >= 0 and still refill the bicket assert(tickets > 0); - assert(period > 0); assert(r->period > 0); - assert(r->funds > 0); } void uc_ratelimit_reset(struct RateLimit *r, long current_ts) @@ -29,43 +29,44 @@ int uc_ratelimit_allow(struct RateLimit *r, long current_ts) int allowed; long diff_period; - //Find elapsed time - diff_period = current_ts - r->last_ts; - - if (diff_period > r->period + 1) { - //help prevent overflow when calculating available_tickets below - diff_period = r->period + 1; - } else if (diff_period < 0) { - //If time went backwards, we halt the time for this round - diff_period = 0; - } - - //Calculate the cost of tickets that became available since - //the last time. - r->funds += diff_period * r->tickets; - - //the below is the real algorithm, with period = - //tickets * period. - //we have optimized this to the expression used above - //r->funds += diff_period * - // ((r->tickets * r->period) / r->period); - - //throttle handing out tickets - if (r->funds > r->period * r->tickets) { - r->funds = r->period * r->tickets; - } - - //If we have enough to buy atleast one ticket, we can allow - if (r->funds >= r->period) { + if (r->funds >= r->period) { + //we have enough r->funds -= r->period; allowed = 1; - } else { - //not enough to buy a ticket - allowed = 0; + } else { //refill + //Find elapsed time + diff_period = current_ts - r->last_ts; + + if (diff_period > r->period + 1) { + //help prevent overflow when calculating available_tickets below + diff_period = r->period + 1; + } else if (diff_period < 0) { + //time went backwards, skip this round + diff_period = 0; + } + + //Calculate the cost of tickets that became available + r->funds += diff_period * r->tickets; + + + //throttle handing out tickets + if (r->funds > r->period * r->tickets) { + r->funds = r->period * r->tickets; + } + + //If we have enough to buy atleast one ticket, we can allow + if (r->funds >= r->period) { + r->funds -= r->period; + allowed = 1; + } else { + //not enough to buy a ticket + allowed = 0; + } + + //save this period. + r->last_ts = current_ts; } - //save this period. - r->last_ts = current_ts; return allowed; } diff --git a/test/test_ratelimit.c b/test/test_ratelimit.c index 072c9ea..0b09753 100644 --- a/test/test_ratelimit.c +++ b/test/test_ratelimit.c @@ -7,9 +7,9 @@ START_TEST (test_ratelimit_1) long now = 10; int i; - uc_ratelimit_init(&r, 30, 2, now); + uc_ratelimit_init(&r, 30, 2); for (i = 0; i < 30; i++) { - fail_if(!uc_ratelimit_allow(&r, now)); + fail_if(!uc_ratelimit_allow(&r, now), "i = %d", i); } fail_if(uc_ratelimit_allow(&r, now)); END_TEST @@ -18,7 +18,7 @@ START_TEST (test_ratelimit_2) struct RateLimit r; long now = 10; - uc_ratelimit_init(&r, 1, 1, now); + uc_ratelimit_init(&r, 1, 1); fail_if(!uc_ratelimit_allow(&r, now)); fail_if(uc_ratelimit_allow(&r, now)); @@ -34,7 +34,7 @@ START_TEST (test_ratelimit_3) long now = 10; int i; - uc_ratelimit_init(&r, 10, 5, now); + uc_ratelimit_init(&r, 10, 5); for (i = 0; i < 10; i++) { fail_if(!uc_ratelimit_allow(&r, now)); @@ -70,7 +70,7 @@ START_TEST (test_ratelimit_4) long now = 10; int i; - uc_ratelimit_init(&r, 10, 5, now); + uc_ratelimit_init(&r, 10, 5); for (i = 0; i < 10; i++) { fail_if(!uc_ratelimit_allow(&r, now)); @@ -92,7 +92,7 @@ START_TEST (test_ratelimit_5) struct RateLimit r; long now = 1400000000; - uc_ratelimit_init(&r, 1, 10, now); + uc_ratelimit_init(&r, 1, 10); fail_if(!uc_ratelimit_allow(&r, now)); fail_if(uc_ratelimit_allow(&r, now)); @@ -117,7 +117,7 @@ START_TEST (test_ratelimit_time_backward) struct RateLimit r; long now = 1400000000; - uc_ratelimit_init(&r, 1, 10, now); + uc_ratelimit_init(&r, 1, 10); fail_if(!uc_ratelimit_allow(&r, now)); fail_if(uc_ratelimit_allow(&r, now)); From b91d5870b80c00a8af85ea5fdfecd66b13185fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 16 Oct 2013 19:23:16 +0200 Subject: [PATCH 2/2] Update rate_limit example --- test/rate_limit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rate_limit.c b/test/rate_limit.c index bb6408c..d3d8bea 100644 --- a/test/rate_limit.c +++ b/test/rate_limit.c @@ -10,7 +10,7 @@ int main() struct RateLimit r; time_t start = time(NULL); - uc_ratelimit_init(&r, 3, 10, start); + uc_ratelimit_init(&r, 30, 2); for(i = 0; i < 120; i++) { int k;