1
2
3
4
5
6
7
8
9
10
11
12 package org.apache.hadoop.hbase.quotas;
13
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertFalse;
16 import static org.junit.Assert.assertTrue;
17
18 import java.util.concurrent.TimeUnit;
19 import org.apache.hadoop.hbase.testclassification.SmallTests;
20 import org.apache.hadoop.hbase.util.EnvironmentEdge;
21 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
22 import org.apache.hadoop.hbase.util.ManualEnvironmentEdge;
23 import org.junit.Test;
24 import org.junit.experimental.categories.Category;
25
26
27
28
29 @Category({ SmallTests.class })
30 public class TestRateLimiter {
31 @Test
32 public void testWaitIntervalTimeUnitSeconds() {
33 testWaitInterval(TimeUnit.SECONDS, 10, 100);
34 }
35
36 @Test
37 public void testWaitIntervalTimeUnitMinutes() {
38 testWaitInterval(TimeUnit.MINUTES, 10, 6000);
39 }
40
41 @Test
42 public void testWaitIntervalTimeUnitHours() {
43 testWaitInterval(TimeUnit.HOURS, 10, 360000);
44 }
45
46 @Test
47 public void testWaitIntervalTimeUnitDays() {
48 testWaitInterval(TimeUnit.DAYS, 10, 8640000);
49 }
50
51 private void testWaitInterval(final TimeUnit timeUnit, final long limit,
52 final long expectedWaitInterval) {
53 RateLimiter limiter = new AverageIntervalRateLimiter();
54 limiter.set(limit, timeUnit);
55
56 long nowTs = 0;
57
58
59 for (int i = 0; i < (limit - 1); ++i) {
60 assertTrue(limiter.canExecute());
61 limiter.consume();
62 long waitInterval = limiter.waitInterval();
63 assertEquals(0, waitInterval);
64 }
65
66 for (int i = 0; i < (limit * 4); ++i) {
67
68
69 limiter.setNextRefillTime(limiter.getNextRefillTime() - nowTs);
70 assertTrue(limiter.canExecute());
71 assertEquals(0, limiter.waitInterval());
72 limiter.consume();
73
74 long waitInterval = limiter.waitInterval();
75 assertEquals(expectedWaitInterval, waitInterval);
76
77
78 nowTs = waitInterval;
79
80
81 long temp = nowTs + 500;
82 limiter.setNextRefillTime(limiter.getNextRefillTime() + temp);
83 assertFalse(limiter.canExecute());
84
85 limiter.setNextRefillTime(limiter.getNextRefillTime() - temp);
86 }
87 }
88
89 @Test
90 public void testOverconsumptionAverageIntervalRefillStrategy() {
91 RateLimiter limiter = new AverageIntervalRateLimiter();
92 limiter.set(10, TimeUnit.SECONDS);
93
94
95
96 assertTrue(limiter.canExecute());
97 limiter.consume(20);
98
99 assertEquals(100, limiter.waitInterval(1));
100
101 assertEquals(1000, limiter.waitInterval(10));
102
103 limiter.setNextRefillTime(limiter.getNextRefillTime() - 900);
104
105 assertTrue(limiter.canExecute(1));
106 limiter.setNextRefillTime(limiter.getNextRefillTime() - 100);
107
108 assertTrue(limiter.canExecute());
109 assertEquals(0, limiter.waitInterval());
110 }
111
112 @Test
113 public void testOverconsumptionFixedIntervalRefillStrategy() throws InterruptedException {
114 RateLimiter limiter = new FixedIntervalRateLimiter();
115 limiter.set(10, TimeUnit.SECONDS);
116
117
118 EnvironmentEdge edge = new EnvironmentEdge() {
119 private final long ts = System.currentTimeMillis();
120 @Override
121 public long currentTime() {
122 return ts;
123 }
124 };
125 EnvironmentEdgeManager.injectEdge(edge);
126
127
128 assertTrue(limiter.canExecute());
129 limiter.consume(20);
130
131 assertEquals(1000, limiter.waitInterval(1));
132
133 assertEquals(1000, limiter.waitInterval(10));
134 EnvironmentEdgeManager.reset();
135
136 limiter.setNextRefillTime(limiter.getNextRefillTime() - 900);
137
138 assertFalse(limiter.canExecute(1));
139 limiter.setNextRefillTime(limiter.getNextRefillTime() - 100);
140
141
142 assertTrue(limiter.canExecute());
143 assertEquals(0, limiter.waitInterval());
144 }
145
146 @Test
147 public void testFixedIntervalResourceAvailability() throws Exception {
148 RateLimiter limiter = new FixedIntervalRateLimiter();
149 limiter.set(10, TimeUnit.SECONDS);
150
151 assertTrue(limiter.canExecute(10));
152 limiter.consume(3);
153 assertEquals(7, limiter.getAvailable());
154 assertFalse(limiter.canExecute(10));
155 limiter.setNextRefillTime(limiter.getNextRefillTime() - 1000);
156 assertTrue(limiter.canExecute(10));
157 assertEquals(10, limiter.getAvailable());
158 }
159
160 @Test
161 public void testLimiterBySmallerRate() throws InterruptedException {
162
163 RateLimiter limiter = new FixedIntervalRateLimiter();
164 limiter.set(10, TimeUnit.SECONDS);
165
166 int count = 0;
167 while ((count++) < 10) {
168
169 limiter.setNextRefillTime(limiter.getNextRefillTime() - 500);
170 for (int i = 0; i < 3; i++) {
171
172 assertEquals(true, limiter.canExecute());
173 limiter.consume();
174 }
175 }
176 }
177
178 @Test
179 public void testCanExecuteOfAverageIntervalRateLimiter() throws InterruptedException {
180 RateLimiter limiter = new AverageIntervalRateLimiter();
181
182 limiter.set(100, TimeUnit.SECONDS);
183 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
184 assertEquals(50, testCanExecuteByRate(limiter, 50));
185
186
187 limiter.set(100, TimeUnit.SECONDS);
188 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
189 assertEquals(100, testCanExecuteByRate(limiter, 100));
190
191
192 limiter.set(100, TimeUnit.SECONDS);
193 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
194 assertEquals(200, testCanExecuteByRate(limiter, 200));
195
196
197 limiter.set(100, TimeUnit.SECONDS);
198 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
199 assertEquals(200, testCanExecuteByRate(limiter, 500));
200 }
201
202 @Test
203 public void testCanExecuteOfFixedIntervalRateLimiter() throws InterruptedException {
204 RateLimiter limiter = new FixedIntervalRateLimiter();
205
206 limiter.set(100, TimeUnit.SECONDS);
207 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
208 assertEquals(50, testCanExecuteByRate(limiter, 50));
209
210
211 limiter.set(100, TimeUnit.SECONDS);
212 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
213 assertEquals(100, testCanExecuteByRate(limiter, 100));
214
215
216 limiter.set(100, TimeUnit.SECONDS);
217 limiter.setNextRefillTime(EnvironmentEdgeManager.currentTime());
218 assertEquals(100, testCanExecuteByRate(limiter, 200));
219 }
220
221 public int testCanExecuteByRate(RateLimiter limiter, int rate) {
222 int request = 0;
223 int count = 0;
224 while ((request++) < rate) {
225 limiter.setNextRefillTime(limiter.getNextRefillTime() - limiter.getTimeUnitInMillis() / rate);
226 if (limiter.canExecute()) {
227 count++;
228 limiter.consume();
229 }
230 }
231 return count;
232 }
233
234 @Test
235 public void testRefillOfAverageIntervalRateLimiter() throws InterruptedException {
236 RateLimiter limiter = new AverageIntervalRateLimiter();
237 limiter.set(60, TimeUnit.SECONDS);
238 assertEquals(60, limiter.getAvailable());
239
240 assertEquals(60, limiter.refill(limiter.getLimit()));
241
242 limiter.consume(30);
243
244
245 limiter.setNextRefillTime(limiter.getNextRefillTime() - 200);
246 assertEquals(12, limiter.refill(limiter.getLimit()));
247
248
249 limiter.setNextRefillTime(limiter.getNextRefillTime() - 500);
250 assertEquals(30, limiter.refill(limiter.getLimit()));
251
252
253 limiter.setNextRefillTime(limiter.getNextRefillTime() - 1000);
254 assertEquals(60, limiter.refill(limiter.getLimit()));
255
256
257 limiter.setNextRefillTime(limiter.getNextRefillTime() - 3000);
258 assertEquals(60, limiter.refill(limiter.getLimit()));
259 limiter.setNextRefillTime(limiter.getNextRefillTime() - 5000);
260 assertEquals(60, limiter.refill(limiter.getLimit()));
261 }
262
263 @Test
264 public void testRefillOfFixedIntervalRateLimiter() throws InterruptedException {
265 RateLimiter limiter = new FixedIntervalRateLimiter();
266 limiter.set(60, TimeUnit.SECONDS);
267 assertEquals(60, limiter.getAvailable());
268
269 assertEquals(60, limiter.refill(limiter.getLimit()));
270
271 limiter.consume(30);
272
273
274 limiter.setNextRefillTime(limiter.getNextRefillTime() - 200);
275 assertEquals(0, limiter.refill(limiter.getLimit()));
276
277
278 limiter.setNextRefillTime(limiter.getNextRefillTime() - 500);
279 assertEquals(0, limiter.refill(limiter.getLimit()));
280
281
282 limiter.setNextRefillTime(limiter.getNextRefillTime() - 1000);
283 assertEquals(60, limiter.refill(limiter.getLimit()));
284
285
286 limiter.setNextRefillTime(limiter.getNextRefillTime() - 3000);
287 assertEquals(60, limiter.refill(limiter.getLimit()));
288 limiter.setNextRefillTime(limiter.getNextRefillTime() - 5000);
289 assertEquals(60, limiter.refill(limiter.getLimit()));
290 }
291
292 @Test
293 public void testUnconfiguredLimiters() throws InterruptedException {
294
295 ManualEnvironmentEdge testEdge = new ManualEnvironmentEdge();
296 EnvironmentEdgeManager.injectEdge(testEdge);
297 long limit = Long.MAX_VALUE;
298
299
300 RateLimiter avgLimiter = new AverageIntervalRateLimiter();
301 RateLimiter fixLimiter = new FixedIntervalRateLimiter();
302
303 assertEquals(limit, avgLimiter.getAvailable());
304 assertEquals(limit, fixLimiter.getAvailable());
305
306 assertTrue(avgLimiter.canExecute(limit));
307 avgLimiter.consume(limit);
308
309 assertTrue(fixLimiter.canExecute(limit));
310 fixLimiter.consume(limit);
311
312
313 assertTrue(limit == avgLimiter.getAvailable());
314 assertTrue(limit == fixLimiter.getAvailable());
315
316
317 testEdge.incValue(100);
318
319 assertTrue(avgLimiter.canExecute(limit));
320 avgLimiter.consume(limit);
321
322 assertTrue(fixLimiter.canExecute(limit));
323 fixLimiter.consume(limit);
324
325
326 assertTrue(limit == avgLimiter.getAvailable());
327 assertTrue(limit == fixLimiter.getAvailable());
328
329 EnvironmentEdgeManager.reset();
330 }
331
332 @Test
333 public void testExtremeLimiters() throws InterruptedException {
334
335 ManualEnvironmentEdge testEdge = new ManualEnvironmentEdge();
336 EnvironmentEdgeManager.injectEdge(testEdge);
337 long limit = Long.MAX_VALUE - 1;
338
339 RateLimiter avgLimiter = new AverageIntervalRateLimiter();
340 avgLimiter.set(limit, TimeUnit.SECONDS);
341 RateLimiter fixLimiter = new FixedIntervalRateLimiter();
342 fixLimiter.set(limit, TimeUnit.SECONDS);
343
344 assertEquals(limit, avgLimiter.getAvailable());
345 assertEquals(limit, fixLimiter.getAvailable());
346
347 assertTrue(avgLimiter.canExecute(limit / 2));
348 avgLimiter.consume(limit / 2);
349
350 assertTrue(fixLimiter.canExecute(limit / 2));
351 fixLimiter.consume(limit / 2);
352
353
354 assertTrue((limit - (limit / 2)) == avgLimiter.getAvailable());
355 assertTrue((limit - (limit / 2)) == fixLimiter.getAvailable());
356
357
358 testEdge.incValue(100);
359
360 assertFalse(avgLimiter.canExecute(limit));
361 assertFalse(fixLimiter.canExecute(limit));
362
363
364 testEdge.incValue(500);
365 assertTrue(avgLimiter.canExecute(limit));
366 assertFalse(fixLimiter.canExecute(limit));
367
368
369 assertTrue(limit == avgLimiter.getAvailable());
370 assertTrue((limit - (limit / 2)) == fixLimiter.getAvailable());
371
372
373 testEdge.incValue(500);
374 assertTrue(avgLimiter.canExecute(limit));
375 assertTrue(fixLimiter.canExecute(limit));
376
377
378 assertTrue(limit == avgLimiter.getAvailable());
379 assertTrue(limit == fixLimiter.getAvailable());
380
381 EnvironmentEdgeManager.reset();
382 }
383
384
385
386
387
388
389
390
391
392 @Test
393 public void testLimiterCompensationOverflow() throws InterruptedException {
394
395 long limit = Long.MAX_VALUE - 1;
396 long guessNumber = 100;
397
398
399 RateLimiter avgLimiter = new AverageIntervalRateLimiter();
400 avgLimiter.set(limit, TimeUnit.SECONDS);
401
402 assertEquals(limit, avgLimiter.getAvailable());
403
404
405 assertTrue(avgLimiter.canExecute(guessNumber));
406 avgLimiter.consume(guessNumber);
407
408
409 assertTrue((limit - guessNumber) == avgLimiter.getAvailable());
410
411
412
413 avgLimiter.consume(-80);
414 assertTrue((limit - guessNumber + 80) == avgLimiter.getAvailable());
415
416
417 avgLimiter.consume(-80);
418 assertTrue(limit == avgLimiter.getAvailable());
419 }
420 }