Skip to content

Commit 087083f

Browse files
remove RateLimiter's manual mutation of Timer and use double for tokenCount (#4027)
1 parent 0176ee4 commit 087083f

File tree

2 files changed

+65
-71
lines changed

2 files changed

+65
-71
lines changed

firebase-perf/src/main/java/com/google/firebase/perf/transport/RateLimiter.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static class RateLimiterImpl {
264264
// Token bucket capacity, also the initial number of tokens in the bucket.
265265
private long capacity;
266266
// Number of tokens in the bucket.
267-
private long tokenCount;
267+
private double tokenCount;
268268

269269
private Rate foregroundRate;
270270
private Rate backgroundRate;
@@ -298,22 +298,16 @@ static class RateLimiterImpl {
298298
*/
299299
synchronized boolean check(@NonNull PerfMetric metric) {
300300
Timer now = clock.getTime();
301-
long newTokens =
302-
Math.max(
303-
0,
304-
(long)
305-
(lastTimeTokenReplenished.getDurationMicros(now)
306-
* rate.getTokensPerSeconds()
307-
/ MICROS_IN_A_SECOND));
308-
tokenCount = Math.min(tokenCount + newTokens, capacity);
309-
if (newTokens > 0) {
310-
lastTimeTokenReplenished =
311-
new Timer(
312-
lastTimeTokenReplenished.getMicros()
313-
+ (long) (newTokens * MICROS_IN_A_SECOND / rate.getTokensPerSeconds()));
301+
double newTokens =
302+
(lastTimeTokenReplenished.getDurationMicros(now)
303+
* rate.getTokensPerSeconds()
304+
/ MICROS_IN_A_SECOND);
305+
if (newTokens > 0.0) {
306+
tokenCount = Math.min(tokenCount + newTokens, capacity);
307+
lastTimeTokenReplenished = now;
314308
}
315-
if (tokenCount > 0) {
316-
tokenCount--;
309+
if (tokenCount >= 1.0) {
310+
tokenCount -= 1.0;
317311
return true;
318312
}
319313
if (isLogcatEnabled) {

firebase-perf/src/test/java/com/google/firebase/perf/transport/RateLimiterTest.java

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -93,34 +93,31 @@ public void testRateLimitImpl() {
9393
RateLimiterImpl limiterImpl =
9494
new RateLimiterImpl(TWO_TOKENS_PER_MINUTE, 2, mClock, mockConfigResolver, NETWORK, false);
9595
PerfMetric metric = PerfMetric.getDefaultInstance();
96-
// clock is 15 seconds, token count is 1.
97-
currentTime = currentTime.plusSeconds(15);
98-
assertThat(limiterImpl.check(metric)).isTrue();
99-
// clock is 30 seconds, count is 1.
100-
currentTime = currentTime.plusSeconds(15);
96+
// clock is 30 seconds, count is 2, afterwards is 1
97+
currentTime = currentTime.plusSeconds(30);
10198
assertThat(limiterImpl.check(metric)).isTrue();
102-
// clock is 45 seconds, count is 0.
99+
// clock is 45 seconds, count is 1.5, afterwards is 0.5
103100
currentTime = currentTime.plusSeconds(15);
104101
assertThat(limiterImpl.check(metric)).isTrue();
105-
// clock is 60 seconds, count is 1
102+
// clock is 60 seconds, count is 1, afterwards is 0
106103
currentTime = currentTime.plusSeconds(15);
107104
assertThat(limiterImpl.check(metric)).isTrue();
108-
// clock is 75 seconds, count is 0,
105+
// clock is 75 seconds, count is 0.5, afterwards is 0.5
109106
currentTime = currentTime.plusSeconds(15);
110107
assertThat(limiterImpl.check(metric)).isFalse();
111-
// clock is 90 seconds, count is 1
108+
// clock is 90 seconds, count is 1, afterwards is 0
112109
currentTime = currentTime.plusSeconds(15);
113110
assertThat(limiterImpl.check(metric)).isTrue();
114-
// clock is 105 seconds, count is 0
111+
// clock is 105 seconds, count is 0.5, afterwards is 0.5
115112
currentTime = currentTime.plusSeconds(15);
116113
assertThat(limiterImpl.check(metric)).isFalse();
117-
// clock is 120 seconds, count is 1,
114+
// clock is 120 seconds, count is 1, afterwards is 1
118115
currentTime = currentTime.plusSeconds(15);
119116
assertThat(limiterImpl.check(metric)).isTrue();
120-
// clock is 135 seconds, count is 0,
117+
// clock is 135 seconds, count is 0.5, afterwards is 0.5
121118
currentTime = currentTime.plusSeconds(15);
122119
assertThat(limiterImpl.check(metric)).isFalse();
123-
// clock is 150 seconds, count is 1,
120+
// clock is 150 seconds, count is 1, afterwards is 1
124121
currentTime = currentTime.plusSeconds(15);
125122
assertThat(limiterImpl.check(metric)).isTrue();
126123
}
@@ -136,32 +133,32 @@ public void testRateLimiterImplWithIrregularTimeIntervals() {
136133
when(mockConfigResolver.getNetworkRequestSamplingRate()).thenReturn(1.0f);
137134

138135
// allow 2 logs every minute. token bucket capacity is 2.
139-
// clock is 0, token count is 2.
136+
// clock is 0s, token count is 2.0.
140137
RateLimiterImpl limiterImpl =
141138
new RateLimiterImpl(TWO_TOKENS_PER_MINUTE, 2, mClock, mockConfigResolver, NETWORK, false);
142139
PerfMetric metric = PerfMetric.getDefaultInstance();
143-
// clock is 20 seconds, count before check is 2, 0 new tokens added, count after check is 1
140+
// clock is 20s, count before check is 2.00, 0.00 new tokens added, count after check is 1.00
144141
currentTime = currentTime.plusSeconds(20);
145142
assertThat(limiterImpl.check(metric)).isTrue();
146-
// clock is 40 seconds, count before check is 1, 1 new tokens added, count after check is 1
147-
currentTime = currentTime.plusSeconds(20);
143+
// clock is 60s, count before check is 1.00, 1.00 new tokens added, count after check is 1.00
144+
currentTime = currentTime.plusSeconds(40);
148145
assertThat(limiterImpl.check(metric)).isTrue();
149-
// clock is 59 seconds, count before check is 1, 0 new tokens added, count after check is 0
150-
currentTime = currentTime.plusSeconds(19);
146+
// clock is 89s, count before check is 1.00, 0.96 new tokens added, count after check is 0.96
147+
currentTime = currentTime.plusSeconds(29);
151148
assertThat(limiterImpl.check(metric)).isTrue();
152-
// clock is 60 seconds, count before check is 0, 1 new tokens added, count after check is 0
153-
currentTime = currentTime.plusSeconds(1);
149+
// clock is 95s, count before check is 0.96, 0.20 new tokens added, count after check is 0.16
150+
currentTime = currentTime.plusSeconds(6);
154151
assertThat(limiterImpl.check(metric)).isTrue();
155-
// clock is 80 seconds, count before check is 0, 0 new tokens added, count after check is 0
156-
currentTime = currentTime.plusSeconds(20);
152+
// clock is 110s, count before check is 0.16, 0.50 new tokens added, count after check is 0.66
153+
currentTime = currentTime.plusSeconds(15);
157154
assertThat(limiterImpl.check(metric)).isFalse();
158-
// clock is 130 seconds, count before check is 0, 2 new tokens added, count after check is 1
155+
// clock is 160s, count before check is 0.66, 1.34 new tokens added, count after check is 1.00
159156
currentTime = currentTime.plusSeconds(50);
160157
assertThat(limiterImpl.check(metric)).isTrue();
161-
// clock is 131 seconds, count before check is 1, 0 new tokens added, count after check is 0
158+
// clock is 161s, count before check is 1.00, 0.03 new tokens added, count after check is 0.03
162159
currentTime = currentTime.plusSeconds(1);
163160
assertThat(limiterImpl.check(metric)).isTrue();
164-
// clock is 132 seconds, count before check is 0, 0 new tokens added, count after check is 0
161+
// clock is 162s, count before check is 0.03, 0.03 new tokens added, count after check is 0.06
165162
currentTime = currentTime.plusSeconds(1);
166163
assertThat(limiterImpl.check(metric)).isFalse();
167164
}
@@ -182,29 +179,29 @@ public void testRateLimiterImplWithIrregularTimeIntervals() {
182179
new RateLimiterImpl(TWO_TOKENS_PER_MINUTE, 2, mClock, mockConfigResolver, NETWORK, false);
183180
PerfMetric metric = PerfMetric.getDefaultInstance();
184181

185-
// clock is 20 seconds, count before check is 2, 0 new tokens added, count after check is 1
186-
currentTime = currentTime.plusSeconds(20);
182+
// clock is 0, count before check is 2, 0 new tokens added, count after check is 1
183+
currentTime = currentTime.plusSeconds(0);
187184
assertThat(limiterImpl.check(metric)).isTrue();
188-
// clock is 40 seconds, count before check is 1, 1 new tokens added, count after check is 1
189-
currentTime = currentTime.plusSeconds(20);
185+
// clock is 30, count before check is 1, 1 new tokens added, count after check is 1
186+
currentTime = currentTime.plusSeconds(30);
190187
assertThat(limiterImpl.check(metric)).isTrue();
191-
// clock is 59 seconds, count before check is 1, 0 new tokens added, count after check is 0
192-
currentTime = currentTime.plusSeconds(19);
188+
// clock is 59, count before check is 1, 0.96 new tokens added, count after check is 0.96
189+
currentTime = currentTime.plusSeconds(29);
193190
assertThat(limiterImpl.check(metric)).isTrue();
194-
// clock is 60 seconds, count before check is 0, 1 new tokens added, count after check is 0
191+
// clock is 60, count before check is 0.96, 0.04 new tokens added, count after check is 0
195192
currentTime = currentTime.plusSeconds(1);
196193
assertThat(limiterImpl.check(metric)).isTrue();
197194

198-
// clock is 660 seconds, count before check is 0, 2 new tokens added, count after check is 1
195+
// clock is 660, count before check is 0, 2 new tokens added, count after check is 1
199196
currentTime = currentTime.plusSeconds(600);
200197
assertThat(limiterImpl.check(metric)).isTrue();
201-
// clock is 661 seconds, count before check is 1, 0 new tokens added, count after check is 0
198+
// clock is 661, count before check is 1, 0.03 new tokens added, count after check is 0.03
202199
currentTime = currentTime.plusSeconds(1);
203200
assertThat(limiterImpl.check(metric)).isTrue();
204-
// clock is 662 seconds, count before check is 0, 0 new tokens added, count after check is 0
201+
// clock is 662, count before check is 0.03, 0.03 new tokens added, count after check is 0.06
205202
currentTime = currentTime.plusSeconds(1);
206203
assertThat(limiterImpl.check(metric)).isFalse();
207-
// clock is 663 seconds, count before check is 0, 0 new tokens added, count after check is 0
204+
// clock is 663, count before check is 0.06, 0.03 new tokens added, count after check is 0.10
208205
currentTime = currentTime.plusSeconds(1);
209206
assertThat(limiterImpl.check(metric)).isFalse();
210207
}
@@ -330,46 +327,46 @@ public void testRateLimit() {
330327
PerfMetric.newBuilder()
331328
.setNetworkRequestMetric(NetworkRequestMetric.getDefaultInstance())
332329
.build();
333-
// clock is 15 seconds, token count is 1.
334-
currentTime = currentTime.plusSeconds(15);
335-
assertThat(limiter.isEventRateLimited(trace)).isFalse();
336-
assertThat(limiter.isEventRateLimited(network)).isFalse();
337-
// clock is 30 seconds, count is 0.
330+
// clock is 15 seconds, token count afterwards is 1.
338331
currentTime = currentTime.plusSeconds(15);
339332
assertThat(limiter.isEventRateLimited(trace)).isFalse();
340333
assertThat(limiter.isEventRateLimited(network)).isFalse();
341-
// clock is 45 seconds, count is 0.
334+
// clock is 30 seconds, count afterwards is 0.5.
342335
currentTime = currentTime.plusSeconds(15);
343336
assertThat(limiter.isEventRateLimited(trace)).isFalse();
344337
assertThat(limiter.isEventRateLimited(network)).isFalse();
345-
// clock is 60 seconds, count is 0
338+
// clock is 45 seconds, count afterwards is 0
346339
currentTime = currentTime.plusSeconds(15);
347340
assertThat(limiter.isEventRateLimited(trace)).isFalse();
348341
assertThat(limiter.isEventRateLimited(network)).isFalse();
349-
// clock is 75 seconds, count is 0,
342+
// clock is 60 seconds, count afterwards is 0.5
350343
currentTime = currentTime.plusSeconds(15);
351344
assertThat(limiter.isEventRateLimited(trace)).isTrue();
352345
assertThat(limiter.isEventRateLimited(network)).isTrue();
353-
// clock is 90 seconds, count is 0
346+
// clock is 75 seconds, count afterwards is 0
354347
currentTime = currentTime.plusSeconds(15);
355348
assertThat(limiter.isEventRateLimited(trace)).isFalse();
356349
assertThat(limiter.isEventRateLimited(network)).isFalse();
357-
// clock is 105 seconds, count is 0
350+
// clock is 90 seconds, count afterwards is 0.5
358351
currentTime = currentTime.plusSeconds(15);
359352
assertThat(limiter.isEventRateLimited(trace)).isTrue();
360353
assertThat(limiter.isEventRateLimited(network)).isTrue();
361-
// clock is 120 seconds, count is 0,
354+
// clock is 105 seconds, count afterwards is 0
362355
currentTime = currentTime.plusSeconds(15);
363356
assertThat(limiter.isEventRateLimited(trace)).isFalse();
364357
assertThat(limiter.isEventRateLimited(network)).isFalse();
365-
// clock is 135 seconds, count is 0,
358+
// clock is 120 seconds, count afterwards is 0.5
366359
currentTime = currentTime.plusSeconds(15);
367360
assertThat(limiter.isEventRateLimited(trace)).isTrue();
368361
assertThat(limiter.isEventRateLimited(network)).isTrue();
369-
// clock is 150 seconds, count is 0,
362+
// clock is 135 seconds, count afterwards is 0
370363
currentTime = currentTime.plusSeconds(15);
371364
assertThat(limiter.isEventRateLimited(trace)).isFalse();
372365
assertThat(limiter.isEventRateLimited(network)).isFalse();
366+
// clock is 150 seconds, count afterwards is 0.5
367+
currentTime = currentTime.plusSeconds(15);
368+
assertThat(limiter.isEventRateLimited(trace)).isTrue();
369+
assertThat(limiter.isEventRateLimited(network)).isTrue();
373370
}
374371

375372
@Test
@@ -722,16 +719,19 @@ public void testChangeRate() {
722719
RateLimiterImpl limiterImpl =
723720
new RateLimiterImpl(TWO_TOKENS_PER_MINUTE, 2, mClock, mockConfigResolver, TRACE, false);
724721
PerfMetric metric = PerfMetric.getDefaultInstance();
725-
// clock is 15 seconds, token count is 1.
726-
currentTime = currentTime.plusSeconds(15);
722+
// clock is 0 seconds, token count is 2, afterwards is 1
723+
currentTime = currentTime.plusSeconds(0);
727724
assertThat(limiterImpl.check(metric)).isTrue();
728-
// clock is 30 seconds, count is 0.
725+
// clock is 15 seconds, count is 1.5, afterwards is 0.5
729726
currentTime = currentTime.plusSeconds(15);
730727
assertThat(limiterImpl.check(metric)).isTrue();
731-
// clock is 45 seconds, count is 0.
728+
// clock is 30 seconds, count is 1, afterwards is 0
732729
currentTime = currentTime.plusSeconds(15);
733730
assertThat(limiterImpl.check(metric)).isTrue();
734-
// clock is 60 seconds, count is 0
731+
// clock is 45 seconds, count is 0.5, afterwards is 0.5
732+
currentTime = currentTime.plusSeconds(15);
733+
assertThat(limiterImpl.check(metric)).isFalse();
734+
// clock is 60 seconds, count is 1, afterwards is 0
735735
currentTime = currentTime.plusSeconds(15);
736736
assertThat(limiterImpl.check(metric)).isTrue();
737737

0 commit comments

Comments
 (0)