/** * Acquires a single permit from this {@code RateLimiter}, blocking until the request can be * granted. Tells the amount of time slept, if any. * * <p>This method is equivalent to {@code acquire(1)}. * * @return time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited * @since 16.0 (present in 13.0 with {@code void} return type}) */ @CanIgnoreReturnValue public double acquire() { return acquire(1); }
public void testSimpleWeights() { RateLimiter rateLimiter = RateLimiter.create(1.0, stopwatch); rateLimiter.acquire(1); // no wait rateLimiter.acquire(1); // R1.00, to repay previous rateLimiter.acquire(2); // R1.00, to repay previous rateLimiter.acquire(4); // R2.00, to repay previous rateLimiter.acquire(8); // R4.00, to repay previous rateLimiter.acquire(1); // R8.00, to repay previous assertEvents("R0.00", "R1.00", "R1.00", "R2.00", "R4.00", "R8.00"); }
private long measureTotalTimeMillis(RateLimiter rateLimiter, int permits, Random random) { long startTime = stopwatch.instant; while (permits > 0) { int nextPermitsToAcquire = Math.max(1, random.nextInt(permits)); permits -= nextPermitsToAcquire; rateLimiter.acquire(nextPermitsToAcquire); } rateLimiter.acquire(1); // to repay for any pending debt return NANOSECONDS.toMillis(stopwatch.instant - startTime); }
/** * Acquires a single permit from this {@code RateLimiter}, blocking until the request can be * granted. Tells the amount of time slept, if any. * * <p>This method is equivalent to {@code acquire(1)}. * * @return time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited * @since 16.0 (present in 13.0 with {@code void} return type}) */ @CanIgnoreReturnValue public double acquire() { return acquire(1); }
public void testBurstyAndUpdate() { RateLimiter rateLimiter = RateLimiter.create(1.0, stopwatch); rateLimiter.acquire(1); // no wait rateLimiter.acquire(1); // R1.00, to repay previous rateLimiter.setRate(2.0); // update the rate! rateLimiter.acquire(1); // R1.00, to repay previous (the previous was under the old rate!) rateLimiter.acquire(2); // R0.50, to repay previous (now the rate takes effect) rateLimiter.acquire(4); // R1.00, to repay previous rateLimiter.acquire(1); // R2.00, to repay previous assertEvents("R0.00", "R1.00", "R1.00", "R0.50", "R1.00", "R2.00"); }
public void testOneSecondBurst() { RateLimiter limiter = RateLimiter.create(5.0, stopwatch); stopwatch.sleepMillis(1000); // max capacity reached stopwatch.sleepMillis(1000); // this makes no difference limiter.acquire(1); // R0.00, since it's the first request limiter.acquire(1); // R0.00, from capacity limiter.acquire(3); // R0.00, from capacity limiter.acquire(1); // R0.00, concluding a burst of 5 permits limiter.acquire(); // R0.20, capacity exhausted assertEvents( "U1.00", "U1.00", "R0.00", "R0.00", "R0.00", "R0.00", // first request and burst "R0.20"); }
public void testInfinity_WarmUp() { RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, 10, SECONDS, 3.0, stopwatch); limiter.acquire(Integer.MAX_VALUE / 4); limiter.acquire(Integer.MAX_VALUE / 2); limiter.acquire(Integer.MAX_VALUE); assertEvents("R0.00", "R0.00", "R0.00"); limiter.setRate(1.0); limiter.acquire(); limiter.acquire(); limiter.acquire(); assertEvents("R0.00", "R1.00", "R1.00"); limiter.setRate(Double.POSITIVE_INFINITY); limiter.acquire(); limiter.acquire(); limiter.acquire(); assertEvents("R1.00", "R0.00", "R0.00"); }
public void testSimpleWithWait() { RateLimiter limiter = RateLimiter.create(5.0, stopwatch); limiter.acquire(); // R0.00 stopwatch.sleepMillis(200); // U0.20, we are ready for the next request... limiter.acquire(); // R0.00, ...which is granted immediately limiter.acquire(); // R0.20 assertEvents("R0.00", "U0.20", "R0.00", "R0.20"); }
public void testInfinity_Bursty() { RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, stopwatch); limiter.acquire(Integer.MAX_VALUE / 4); limiter.acquire(Integer.MAX_VALUE / 2); limiter.acquire(Integer.MAX_VALUE); assertEvents("R0.00", "R0.00", "R0.00"); // no wait, infinite rate! limiter.setRate(2.0); limiter.acquire(); limiter.acquire(); limiter.acquire(); limiter.acquire(); limiter.acquire(); assertEvents( "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests). "R0.00", "R0.00", // Now comes the free request. "R0.50", // Now it's 0.5 seconds per request. "R0.50"); limiter.setRate(Double.POSITIVE_INFINITY); limiter.acquire(); limiter.acquire(); limiter.acquire(); assertEvents("R0.50", "R0.00", "R0.00"); // we repay the last request (.5sec), then back to +oo }
public void testSimpleAcquireEarliestAvailableIsInPast() { RateLimiter limiter = RateLimiter.create(5.0, stopwatch); assertEquals(0.0, limiter.acquire(), EPSILON); stopwatch.sleepMillis(400); assertEquals(0.0, limiter.acquire(), EPSILON); assertEquals(0.0, limiter.acquire(), EPSILON); assertEquals(0.2, limiter.acquire(), EPSILON); }
public void testWarmUpWithColdFactor1() { RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 1.0, stopwatch); for (int i = 0; i < 8; i++) { limiter.acquire(); // #1 } stopwatch.sleepMillis(340); // #2 for (int i = 0; i < 8; i++) { limiter.acquire(); // #3 } assertEvents( "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20", // #1 "U0.34", // #2 "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20"); // #3 }
public void testWarmUpAndUpdateWithColdFactor() { RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 10.0, stopwatch); for (int i = 0; i < 8; i++) { limiter.acquire(); // #1 } stopwatch.sleepMillis(4200); // #2: back to cold state (warmup period + repay last acquire) for (int i = 0; i < 3; i++) { // only three steps, we're somewhere in the warmup period limiter.acquire(); // #3 } limiter.setRate(10.0); // double the rate! limiter.acquire(); // #4, we repay the debt of the last acquire (imposed by the old rate) for (int i = 0; i < 4; i++) { limiter.acquire(); // #5 } stopwatch.sleepMillis(4100); // #6, back to cold state (warmup period + repay last acquire) for (int i = 0; i < 11; i++) { limiter.acquire(); // #7, showing off the warmup starting from totally cold } // make sure the areas (times) remain the same, while permits are different assertEvents( "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #1 "U4.20", // #2 "R0.00, R1.75, R1.26", // #3, after that the rate changes "R0.76", // #4, this is what the throttling would be with the old rate "R0.20, R0.10, R0.10, R0.10", // #5 "U4.10", // #6 "R0.00, R0.94, R0.81, R0.69, R0.57, R0.44, R0.32", // #7 "R0.20, R0.10, R0.10, R0.10"); // #7 (cont.), note, this matches #5 }
public void testSimpleAcquireReturnValues() { RateLimiter limiter = RateLimiter.create(5.0, stopwatch); assertEquals(0.0, limiter.acquire(), EPSILON); // R0.00 stopwatch.sleepMillis(200); // U0.20, we are ready for the next request... assertEquals(0.0, limiter.acquire(), EPSILON); // R0.00, ...which is granted immediately assertEquals(0.2, limiter.acquire(), EPSILON); // R0.20 assertEvents("R0.00", "U0.20", "R0.00", "R0.20"); }
@AndroidIncompatible // difference in String.format rounding? public void testWarmUpAndUpdate() { RateLimiter limiter = RateLimiter.create(2.0, 4000, MILLISECONDS, 3.0, stopwatch); for (int i = 0; i < 8; i++) { limiter.acquire(); // // #1 } stopwatch.sleepMillis(4500); // #2: back to cold state (warmup period + repay last acquire) for (int i = 0; i < 3; i++) { // only three steps, we're somewhere in the warmup period limiter.acquire(); // #3 } limiter.setRate(4.0); // double the rate! limiter.acquire(); // #4, we repay the debt of the last acquire (imposed by the old rate) for (int i = 0; i < 4; i++) { limiter.acquire(); // #5 } stopwatch.sleepMillis(4250); // #6, back to cold state (warmup period + repay last acquire) for (int i = 0; i < 11; i++) { limiter.acquire(); // #7, showing off the warmup starting from totally cold } // make sure the areas (times) remain the same, while permits are different assertEvents( "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #1 "U4.50", // #2 "R0.00, R1.38, R1.13", // #3, after that the rate changes "R0.88", // #4, this is what the throttling would be with the old rate "R0.34, R0.28, R0.25, R0.25", // #5 "U4.25", // #6 "R0.00, R0.72, R0.66, R0.59, R0.53, R0.47, R0.41", // #7 "R0.34, R0.28, R0.25, R0.25"); // #7 (cont.), note, this matches #5 }
public void testInfinity_WarmUpTimeElapsed() { RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, 10, SECONDS, 3.0, stopwatch); stopwatch.instant += 1000000; limiter.setRate(1.0); for (int i = 0; i < 5; i++) { limiter.acquire(); } assertEvents("R0.00", "R1.00", "R1.00", "R1.00", "R1.00"); }
public void testWarmUpWithColdFactor() { RateLimiter limiter = RateLimiter.create(5.0, 4000, MILLISECONDS, 10.0, stopwatch); for (int i = 0; i < 8; i++) { limiter.acquire(); // #1 } stopwatch.sleepMillis(200); // #2: to repay for the last acquire stopwatch.sleepMillis(4000); // #3: becomes cold again for (int i = 0; i < 8; i++) { limiter.acquire(); // // #4 } stopwatch.sleepMillis(200); // #5: to repay for the last acquire stopwatch.sleepMillis(1000); // #6: still warm! It would take another 3 seconds to go cold for (int i = 0; i < 8; i++) { limiter.acquire(); // #7 } assertEvents( "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #1 "U0.20", // #2 "U4.00", // #3 "R0.00, R1.75, R1.26, R0.76, R0.30, R0.20, R0.20, R0.20", // #4 "U0.20", // #5 "U1.00", // #6 "R0.00, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20, R0.20"); // #7 }
/** https://code.google.com/p/guava-libraries/issues/detail?id=1791 */ public void testInfinity_BustyTimeElapsed() { RateLimiter limiter = RateLimiter.create(Double.POSITIVE_INFINITY, stopwatch); stopwatch.instant += 1000000; limiter.setRate(2.0); for (int i = 0; i < 5; i++) { limiter.acquire(); } assertEvents( "R0.00", // First comes the saved-up burst, which defaults to a 1-second burst (2 requests). "R0.00", "R0.00", // Now comes the free request. "R0.50", // Now it's 0.5 seconds per request. "R0.50"); }
@AndroidIncompatible // difference in String.format rounding? public void testWarmUp() { RateLimiter limiter = RateLimiter.create(2.0, 4000, MILLISECONDS, 3.0, stopwatch); for (int i = 0; i < 8; i++) { limiter.acquire(); // #1 } stopwatch.sleepMillis(500); // #2: to repay for the last acquire stopwatch.sleepMillis(4000); // #3: becomes cold again for (int i = 0; i < 8; i++) { limiter.acquire(); // // #4 } stopwatch.sleepMillis(500); // #5: to repay for the last acquire stopwatch.sleepMillis(2000); // #6: didn't get cold! It would take another 2 seconds to go cold for (int i = 0; i < 8; i++) { limiter.acquire(); // #7 } assertEvents( "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #1 "U0.50", // #2 "U4.00", // #3 "R0.00, R1.38, R1.13, R0.88, R0.63, R0.50, R0.50, R0.50", // #4 "U0.50", // #5 "U2.00", // #6 "R0.00, R0.50, R0.50, R0.50, R0.50, R0.50, R0.50, R0.50"); // #7 }