@@ -108,14 +108,29 @@ pub struct BandwidthLimits {
108108
109109#[ derive( Debug ) ]
110110pub struct RateLimiter {
111- config : RateLimits ,
112111 bandwidth : BandwidthRateLimiter ,
113- global : Option < Mutex < TokenBucket > > ,
114- // NB: These maps grow unbounded but we accept this as we expect an overall limited
115- // number of usecases and scopes. We emit gauge metrics to monitor their size.
116- usecases : papaya:: HashMap < String , Mutex < TokenBucket > > ,
117- scopes : papaya:: HashMap < Scopes , Mutex < TokenBucket > > ,
118- rules : papaya:: HashMap < usize , Mutex < TokenBucket > > ,
112+ throughput : ThroughputRateLimiter ,
113+ }
114+
115+ impl RateLimiter {
116+ pub fn new ( config : RateLimits ) -> Self {
117+ Self {
118+ bandwidth : BandwidthRateLimiter :: new ( config. bandwidth ) ,
119+ throughput : ThroughputRateLimiter :: new ( config. throughput ) ,
120+ }
121+ }
122+
123+ /// Checks if the given context is within the rate limits.
124+ ///
125+ /// Returns `true` if the context is within the rate limits, `false` otherwise.
126+ pub fn check ( & self , context : & ObjectContext ) -> bool {
127+ self . throughput . check ( context) && self . bandwidth . check ( )
128+ }
129+
130+ /// Returns a reference to the shared bytes accumulator, used for bandwidth-based rate-limiting.
131+ pub fn bytes_accumulator ( & self ) -> Arc < AtomicU64 > {
132+ Arc :: clone ( & self . bandwidth . accumulator )
133+ }
119134}
120135
121136#[ derive( Debug ) ]
@@ -176,36 +191,33 @@ impl BandwidthRateLimiter {
176191 }
177192}
178193
179- impl RateLimiter {
180- pub fn new ( config : RateLimits ) -> Self {
194+ #[ derive( Debug ) ]
195+ struct ThroughputRateLimiter {
196+ config : ThroughputLimits ,
197+ global : Option < Mutex < TokenBucket > > ,
198+ // NB: These maps grow unbounded but we accept this as we expect an overall limited
199+ // number of usecases and scopes. We emit gauge metrics to monitor their size.
200+ usecases : papaya:: HashMap < String , Mutex < TokenBucket > > ,
201+ scopes : papaya:: HashMap < Scopes , Mutex < TokenBucket > > ,
202+ rules : papaya:: HashMap < usize , Mutex < TokenBucket > > ,
203+ }
204+
205+ impl ThroughputRateLimiter {
206+ fn new ( config : ThroughputLimits ) -> Self {
181207 let global = config
182- . throughput
183208 . global_rps
184- . map ( |rps| Mutex :: new ( TokenBucket :: new ( rps, config. throughput . burst ) ) ) ;
209+ . map ( |rps| Mutex :: new ( TokenBucket :: new ( rps, config. burst ) ) ) ;
185210
186211 Self {
187- config : config. clone ( ) ,
188- bandwidth : BandwidthRateLimiter :: new ( config. bandwidth ) ,
212+ config,
189213 global,
190214 usecases : papaya:: HashMap :: new ( ) ,
191215 scopes : papaya:: HashMap :: new ( ) ,
192216 rules : papaya:: HashMap :: new ( ) ,
193217 }
194218 }
195219
196- /// Returns a reference to the shared bytes accumulator, used for bandwidth-based rate-limiting.
197- pub fn bytes_accumulator ( & self ) -> Arc < AtomicU64 > {
198- Arc :: clone ( & self . bandwidth . accumulator )
199- }
200-
201- /// Checks if the given context is within the rate limits.
202- ///
203- /// Returns `true` if the context is within the rate limits, `false` otherwise.
204- pub fn check ( & self , context : & ObjectContext ) -> bool {
205- self . check_throughput ( context) && self . bandwidth . check ( )
206- }
207-
208- fn check_throughput ( & self , context : & ObjectContext ) -> bool {
220+ fn check ( & self , context : & ObjectContext ) -> bool {
209221 // NB: We intentionally use unwrap and crash the server if the mutexes are poisoned.
210222
211223 // Global check
@@ -236,7 +248,7 @@ impl RateLimiter {
236248 }
237249
238250 // Rule checks - each matching rule has its own dedicated bucket
239- for ( idx, rule) in self . config . throughput . rules . iter ( ) . enumerate ( ) {
251+ for ( idx, rule) in self . config . rules . iter ( ) . enumerate ( ) {
240252 if !rule. matches ( context) {
241253 continue ;
242254 }
@@ -254,28 +266,27 @@ impl RateLimiter {
254266 }
255267
256268 fn create_bucket ( & self , rps : u32 ) -> Mutex < TokenBucket > {
257- Mutex :: new ( TokenBucket :: new ( rps, self . config . throughput . burst ) )
269+ Mutex :: new ( TokenBucket :: new ( rps, self . config . burst ) )
258270 }
259271
260272 /// Returns the effective RPS for per-usecase limiting, if configured.
261273 fn usecase_rps ( & self ) -> Option < u32 > {
262- let global_rps = self . config . throughput . global_rps ?;
263- let pct = self . config . throughput . usecase_pct ?;
274+ let global_rps = self . config . global_rps ?;
275+ let pct = self . config . usecase_pct ?;
264276 Some ( ( ( global_rps as f64 ) * ( pct as f64 / 100.0 ) ) as u32 )
265277 }
266278
267279 /// Returns the effective RPS for per-scope limiting, if configured.
268280 fn scope_rps ( & self ) -> Option < u32 > {
269- let global_rps = self . config . throughput . global_rps ?;
270- let pct = self . config . throughput . scope_pct ?;
281+ let global_rps = self . config . global_rps ?;
282+ let pct = self . config . scope_pct ?;
271283 Some ( ( ( global_rps as f64 ) * ( pct as f64 / 100.0 ) ) as u32 )
272284 }
273285
274286 /// Returns the effective RPS for a rule, if it has a valid limit.
275287 fn rule_rps ( & self , rule : & ThroughputRule ) -> Option < u32 > {
276288 let pct_limit = rule. pct . and_then ( |p| {
277289 self . config
278- . throughput
279290 . global_rps
280291 . map ( |g| ( ( g as f64 ) * ( p as f64 / 100.0 ) ) as u32 )
281292 } ) ;
0 commit comments