Skip to content

Commit 5cd2d5e

Browse files
authored
Merge pull request #213 from AcalaNetwork/add_missing_methods
add keyed future missing methods
2 parents c1a9fdb + c615d35 commit 5cd2d5e

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

governor/src/state/keyed/future.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::prelude::v1::*;
22

33
use crate::{
4-
clock, middleware::RateLimitingMiddleware, state::keyed::KeyedStateStore, Jitter, NotUntil,
5-
RateLimiter,
4+
clock, errors::InsufficientCapacity, middleware::RateLimitingMiddleware,
5+
state::keyed::KeyedStateStore, Jitter, NotUntil, RateLimiter,
66
};
77
use futures_timer::Delay;
8-
use std::hash::Hash;
8+
use std::{hash::Hash, num::NonZeroU32};
99

1010
#[cfg(feature = "std")]
1111
/// # Keyed rate limiters - `async`/`await`
@@ -57,4 +57,47 @@ where
5757
}
5858
}
5959
}
60+
61+
/// Asynchronously resolves as soon as the rate limiter allows it.
62+
///
63+
/// This is similar to `until_key_ready` except it waits for an abitrary number
64+
/// of `n` cells to be available.
65+
///
66+
/// Returns `InsufficientCapacity` if the `n` provided exceeds the maximum
67+
/// capacity of the rate limiter.
68+
pub async fn until_key_n_ready(
69+
&self,
70+
key: &K,
71+
n: NonZeroU32,
72+
) -> Result<MW::PositiveOutcome, InsufficientCapacity> {
73+
self.until_key_n_ready_with_jitter(key, n, Jitter::NONE)
74+
.await
75+
}
76+
77+
/// Asynchronously resolves as soon as the rate limiter allows it, with a
78+
/// randomized wait period.
79+
///
80+
/// This is similar to `until_key_ready_with_jitter` except it waits for an
81+
/// abitrary number of `n` cells to be available.
82+
///
83+
/// Returns `InsufficientCapacity` if the `n` provided exceeds the maximum
84+
/// capacity of the rate limiter.
85+
pub async fn until_key_n_ready_with_jitter(
86+
&self,
87+
key: &K,
88+
n: NonZeroU32,
89+
jitter: Jitter,
90+
) -> Result<MW::PositiveOutcome, InsufficientCapacity> {
91+
loop {
92+
match self.check_key_n(key, n)? {
93+
Ok(x) => {
94+
return Ok(x);
95+
}
96+
Err(negative) => {
97+
let delay = Delay::new(jitter + negative.wait_time_from(self.clock.now()));
98+
delay.await;
99+
}
100+
}
101+
}
102+
}
60103
}

governor/tests/future.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ fn pauses_keyed() {
5555
assert_ge!(i.elapsed(), Duration::from_millis(100));
5656
}
5757

58+
#[test]
59+
fn pauses_keyed_n() {
60+
let lim = RateLimiter::keyed(Quota::per_second(nonzero!(10u32)));
61+
62+
for _ in 0..6 {
63+
lim.check_key(&1u32).unwrap();
64+
}
65+
let i = Instant::now();
66+
block_on(lim.until_key_n_ready(&1u32, nonzero!(5u32))).unwrap();
67+
assert_ge!(i.elapsed(), Duration::from_millis(100));
68+
}
69+
5870
#[test]
5971
fn proceeds() {
6072
let lim = RateLimiter::direct(Quota::per_second(nonzero!(2u32)));
@@ -79,6 +91,14 @@ fn proceeds_keyed() {
7991
assert_le!(i.elapsed(), MAX_TEST_RUN_DURATION);
8092
}
8193

94+
#[test]
95+
fn proceeds_keyed_n() {
96+
let lim = RateLimiter::keyed(Quota::per_second(nonzero!(3u32)));
97+
let i = Instant::now();
98+
block_on(lim.until_key_n_ready(&1u32, nonzero!(2u32))).unwrap();
99+
assert_le!(i.elapsed(), MAX_TEST_RUN_DURATION);
100+
}
101+
82102
#[test]
83103
fn multiple() {
84104
let lim = Arc::new(RateLimiter::direct(Quota::per_second(nonzero!(10u32))));
@@ -125,4 +145,8 @@ fn errors_on_exceeded_capacity() {
125145
let lim = RateLimiter::direct(Quota::per_second(nonzero!(10u32)));
126146

127147
block_on(lim.until_n_ready(nonzero!(11u32))).unwrap_err();
148+
149+
let lim = RateLimiter::keyed(Quota::per_second(nonzero!(10u32)));
150+
151+
block_on(lim.until_key_n_ready(&1u32, nonzero!(11u32))).unwrap_err();
128152
}

0 commit comments

Comments
 (0)