-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Differentiate between GCRA burst capacity and tolerance #251
Differentiate between GCRA burst capacity and tolerance #251
Conversation
A rate limiter constructed with burst capacity 2 should never allow more than 2 cells in a short burst.
In GCRA terms, the total capacity of the rate limiter is `Τ + τ`, where `Τ` is the nominal cell arrival interval and `τ` is (extra) tolerance allowed for bursts. The current implementation has a subtle issue, caused by conflating capacity and tolerance, which results in one extra cell being allowed after arrival intervals equal or greater than "capacity + 1", as reported in boinkor-net#107 and boinkor-net#249. This problem was partially hidden by a compensating addition of Τ to initial TAT in the case of the first cell (i.e. when the rate limiter has no state recorded for it). To fix the issue, correct the value `tau` used for making the decision, making it the tolerance, and remove the adjustment for the first cell that's no longer necessary. Fixes: boinkor-net#107 Fixes: boinkor-net#249
The cargo deny failure is unrelated to these changes, but I can allow-list the "Unicode-3.0" license for Relevant except from the cargo deny run log:
|
Thanks for the contribution - your explanation and the change seems really good on first glance (haven't read through all of it yet, but soon)! I'm OK with allowlisting the unicode license - it's a bit annoying that ~every project needs to add that specific one combination of licenses to its list, but oh well (: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. I have one open/question that I'm sure you thought of already (and that my morning brain just can't reason through fully yet), but otherwise I'm super excited to include this and fix all those bugs (:
.into(); | ||
let t: Nanos = quota.replenish_1_per.into(); | ||
let t: Nanos = cmp::max(quota.replenish_1_per, Duration::from_nanos(1)).into(); | ||
let tau: Nanos = t * (quota.max_burst.get() - 1).into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, hm, hm. I think this might cause tau
to become 0 if you pick a burst capacity of 1... I'm slightly convinced that won't cause problems in the tat
calculation below, but not fully certain. a tau=0
case is fine, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will cause tau
to be zero, intentionally. If the burst capacity is one, we want to reject any cells that arrive before the TAT. Only with capacities greater than one that we want to allow for non-zero tolerance tau
.
The TAT is (ignoring the max operation) the time the last cell arrived + the nominal interval t
. So if tau
was greater than zero for a burst capacity of one, it would cause us to allow a cell to be accepted before the nominal interval has passed since the last cell, effectively accepting a burst of two and violating the burst capacity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I forgot to answer your actual question: yes, tau=0
should be fine in the decision calculations.
What I'm less sure about is if I adjusted all places where tau
is used outside of the gcra
module... in fact, let me take another look today and see if I didn't miss anything the tests also didn't catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm glad I did another pass, as I found an issue in gcra::test_n_all_and_update
. Fixed it and adjusted the relevant test case to cover that case too.
fe0a3dc
to
a527973
Compare
a527973
to
d4685a3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks really good. I'm extra glad that this makes the additional_weight
handling easier!
Thanks! |
Thank you! I'll cut a release containing this soon & will credit you in the changelog (: |
In GCRA terms, the total capacity of the rate limiter is
Τ + τ
, whereΤ
is the nominal cell arrival interval andτ
is (extra) tolerance allowed for bursts.The current implementation has a subtle issue, caused by conflating capacity and tolerance, which results in one extra cell being allowed after arrival intervals equal or greater than "capacity + 1", as reported in #107 and #249. The problem was partially hidden in other cases by a compensating addition of
Τ
to initialTAT
in the case of the first cell (i.e. when the rate limiter has no state recorded for it).To fix the issue, correct the value
tau
used for making the decision, making it the tolerance and not the capacity, and remove the compensation for the first cell that's no longer necessary.This PR also adds a new specific test for the "capacity + 1" interval scenario, as well as fixes an existing test that incorrectly expected one of these extra cells. Finally, some needless lifetimes reported by clippy are also removed since the project opts for
#[deny(warnings)]
.Fixes: #107
Fixes: #249