From 7ef06f4ce7a1eef91d650e54a538b83417647596 Mon Sep 17 00:00:00 2001 From: "vladimir.bukhtoyarov" Date: Sun, 10 May 2015 15:54:55 +0300 Subject: [PATCH] completing javadocs --- .../com/github/bucket4j/AbstractBucket.java | 12 +-- .../github/bucket4j/BandwidthAdjuster.java | 10 ++ src/main/java/com/github/bucket4j/Bucket.java | 70 +++++++++----- .../com/github/bucket4j/BucketBuilder.java | 93 +++++++++++++++++-- .../java/com/github/bucket4j/TimeMeter.java | 20 ++++ 5 files changed, 172 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/github/bucket4j/AbstractBucket.java b/src/main/java/com/github/bucket4j/AbstractBucket.java index e2d20516..220d8989 100644 --- a/src/main/java/com/github/bucket4j/AbstractBucket.java +++ b/src/main/java/com/github/bucket4j/AbstractBucket.java @@ -60,21 +60,21 @@ public void consume(long tokensToConsume) throws InterruptedException { } @Override - public boolean tryConsumeSingleToken(long maxWaitNanos) throws InterruptedException { - return tryConsume(1, maxWaitNanos); + public boolean tryConsumeSingleToken(long maxWaitTime) throws InterruptedException { + return tryConsume(1, maxWaitTime); } @Override - public boolean tryConsume(long tokensToConsume, long maxWaitNanos) throws InterruptedException { + public boolean tryConsume(long tokensToConsume, long maxWaitTime) throws InterruptedException { if (tokensToConsume <= 0) { throw nonPositiveTokensToConsume(tokensToConsume); } - if (maxWaitNanos <= 0) { - throw nonPositiveNanosToWait(maxWaitNanos); + if (maxWaitTime <= 0) { + throw nonPositiveNanosToWait(maxWaitTime); } - return consumeOrAwaitImpl(tokensToConsume, maxWaitNanos); + return consumeOrAwaitImpl(tokensToConsume, maxWaitTime); } @Override diff --git a/src/main/java/com/github/bucket4j/BandwidthAdjuster.java b/src/main/java/com/github/bucket4j/BandwidthAdjuster.java index 0bdb3f0f..f0eb290e 100644 --- a/src/main/java/com/github/bucket4j/BandwidthAdjuster.java +++ b/src/main/java/com/github/bucket4j/BandwidthAdjuster.java @@ -18,8 +18,18 @@ import java.io.Serializable; +/** + * Provider of bandwidth capacity. + */ public interface BandwidthAdjuster extends Serializable { + /** + * Return capacity of bandwidth which can depends from current time if needs. + * + * @param currentTime Cuurent time which returned by timeMeter {@link TimeMeter} + * + * @return + */ long getCapacity(long currentTime); public static class ImmutableCapacity implements BandwidthAdjuster { diff --git a/src/main/java/com/github/bucket4j/Bucket.java b/src/main/java/com/github/bucket4j/Bucket.java index 4851adf7..6b00b47a 100644 --- a/src/main/java/com/github/bucket4j/Bucket.java +++ b/src/main/java/com/github/bucket4j/Bucket.java @@ -16,21 +16,15 @@ package com.github.bucket4j; /** - * A token bucket implementation that is of a leaky bucket in the sense that it has a finite capacity and any added - * tokens that would exceed this capacity will "overflow" out of the bucket and are lost forever. - *

- * In this implementation the rules for refilling the bucket are encapsulated in a provided {@code RefillStrategy} - * instance. Prior to attempting to consumeSingleToken any tokens the refill strategy will be consulted to see how many tokens - * should be added to the bucket. - *

- * In addition in this implementation the method of yielding CPU control is encapsulated in the provided - * {@code SleepStrategy} instance. For high performance applications where tokens are being refilled incredibly quickly - * and an accurate bucket implementation is required, it may be useful to never yield control of the CPU and to instead - * busy wait. This strategy allows the caller to make this decision for themselves instead of the library forcing a - * decision. + * The continuous-state leaky bucket can be viewed as a finite capacity bucket + * whose real-valued content drains out at a continuous rate of 1 unit of content per time unit + * and whose content is increased by the increment T for each conforming cell... + * If at a cell arrival the content of the bucket is less than or equal to the limit value τ, then the cell is conforming; + * otherwise, the cell is non-conforming. * - * @see Token Bucket on Wikipedia - * @see Leaky Bucket on Wikipedia + * @see Token Bucket + * @see Leaky Bucket + * @see Generic cell rate algorithm */ public interface Bucket { @@ -46,26 +40,37 @@ public interface Bucket { * Attempt to consume a specified number of tokens from the bucket. If the tokens were consumed then {@code true} * is returned, otherwise {@code false} is returned. * - * @param numTokens The number of tokens to consumeSingleToken from the bucket, must be a positive number. + * @param numTokens The number of tokens to consume from the bucket, must be a positive number. * @return {@code true} if the tokens were consumed, {@code false} otherwise. */ boolean tryConsume(long numTokens); + /** + * Consumes as much tokens from bucket as available in the bucket in moment of invocation. + * + * @return number of tokens which has been consumed, or zero if was consumed nothing. + */ long consumeAsMuchAsPossible(); + /** + * Consumes as much tokens from bucket as available in the bucket in moment of invocation, + * but tokens which should be consumed is limited by than not more than {@code limit}. + * + * @return number of tokens which has been consumed, or zero if was consumed nothing. + */ long consumeAsMuchAsPossible(long limit); /** - * Consume a single token from the bucket. If no token is currently available then this method will block until a - * token becomes available. + * Consumes a single token from the bucket. If no token is currently available then this method will block until a + * token becomes available or current thread is interrupted. This is equivalent for {@code consume(1)} * * @throws InterruptedException */ void consumeSingleToken() throws InterruptedException; /** - * Consumes multiple tokens from the bucket. If enough tokens are not currently available then this method will block - * until + * Consumes a single token from the bucket. If enough tokens are not currently available then this method will block + * until required number of tokens will be available or current thread is interrupted. * * @param numTokens The number of tokens to consumeSingleToken from teh bucket, must be a positive number. * @@ -73,9 +78,32 @@ public interface Bucket { */ void consume(long numTokens) throws InterruptedException; - boolean tryConsumeSingleToken(long maxWaitNanos) throws InterruptedException; + /** + * Consumes a single token from the bucket. If no token is currently available then this method will block + * until required number of tokens will be available or current thread is interrupted, or {@code maxWaitTime} has elapsed. + * + * This is equivalent for {@code tryConsume(1, maxWaitTime)} + * + * @param maxWaitTime limit of time which thread can wait. + * + * @return true if token has been consumed or false when token has not been consumed + * + * @throws InterruptedException + */ + boolean tryConsumeSingleToken(long maxWaitTime) throws InterruptedException; - boolean tryConsume(long numTokens, long maxWaitNanos) throws InterruptedException; + /** + * Consumes a specified number of tokens from the bucket. If required count of tokens is not currently available then this method will block + * until required number of tokens will be available or current thread is interrupted, or {@code maxWaitTime} has elapsed. + * + * @param numTokens The number of tokens to consume from the bucket. + * @param maxWaitTime limit of time which thread can wait. + * + * @return true if {@code numTokens} has been consumed or false when {@code numTokens} has not been consumed + * + * @throws InterruptedException + */ + boolean tryConsume(long numTokens, long maxWaitTime) throws InterruptedException; BucketState createSnapshot(); diff --git a/src/main/java/com/github/bucket4j/BucketBuilder.java b/src/main/java/com/github/bucket4j/BucketBuilder.java index 6b6bf252..b2e9ed80 100644 --- a/src/main/java/com/github/bucket4j/BucketBuilder.java +++ b/src/main/java/com/github/bucket4j/BucketBuilder.java @@ -141,7 +141,7 @@ public Bucket buildCustomGrid(GridProxy gridProxy) { * {@code * // Adds bandwidth which guarantees, that client of bucket will be able to consume 1 tokens per 10 minutes, * // regardless of limitations. - * withGuaranteedBandwidth(1, TimeUnit.MINUTES, 10); + * builder.withGuaranteedBandwidth(1, TimeUnit.MINUTES, 10); * } * * @@ -169,7 +169,7 @@ public BucketBuilder withGuaranteedBandwidth(long maxCapacity, TimeUnit timeUnit * {@code * // Adds bandwidth which guarantees, that client of bucket will be able to consume 1 tokens per 10 minutes, * // regardless of limitations. Size of bandwidth is 0 after construction - * withGuaranteedBandwidth(2, TimeUnit.MINUTES, 1, 0); + * builder.withGuaranteedBandwidth(2, TimeUnit.MINUTES, 1, 0); * } * * @@ -186,6 +186,26 @@ public BucketBuilder withGuaranteedBandwidth(long maxCapacity, TimeUnit timeUnit return this; } + /** + * Adds guaranteed bandwidth for all buckets which will be constructed by this builder instance. + *

+ * Guaranteed bandwidth provides following feature: if tokens can be consumed from guaranteed bandwidth, + * then bucket4j do not perform checking of any limited bandwidths. + *

+ * Unlike limited bandwidths, you can use only one guaranteed bandwidth per single bucket. + *

+ * + * In opposite to method {@link #withGuaranteedBandwidth(long, TimeUnit, long)}, + * this method does not perform checking of limitation + * which disallow to have greater rate of guaranteed than rate of limited bandwidth, + * because rate is dynamic and depends from bandwidthAdjuster. + * + * @param bandwidthAdjuster provider of bandwidth capacity + * @param timeUnit Unit for period. + * @param period Period of bandwidth. + * @param initialCapacity initial capacity of bandwidth. + * + */ public BucketBuilder withGuaranteedBandwidth(BandwidthAdjuster bandwidthAdjuster, TimeUnit timeUnit, long period, long initialCapacity) { final long bandwidthPeriod = timeMeter.toBandwidthPeriod(timeUnit, period); final BandwidthDefinition bandwidth = new BandwidthDefinition(bandwidthAdjuster, initialCapacity, bandwidthPeriod, true); @@ -193,10 +213,51 @@ public BucketBuilder withGuaranteedBandwidth(BandwidthAdjuster bandwidthAdjuster return this; } + /** + * Adds limited bandwidth for all buckets which will be constructed by this builder instance. + *

+ * You can specify as many limited bandwidth as needed, but with following limitation: each limited bandwidth should has unique period, + * and when period of bandwidth X is greater than bandwidth Y, + * then capacity of bandwidth X should be greater capacity of bandwidth Y, + * except cases when capacity of bandwidth X or Y is dynamic(provided by {@link com.github.bucket4j.BandwidthAdjuster}). + *

+ *

+     * {@code
+     * // Adds bandwidth that restricts to consume not often 1 tokens per 10 minutes,
+     * builder.withLimitedBandwidth(1, TimeUnit.MINUTES, 10);
+     * }
+     * 
+ * + * @param maxCapacity the maximum capacity of bandwidth + * @param timeUnit Unit for period. + * @param period Period of bandwidth. + * + */ public BucketBuilder withLimitedBandwidth(long maxCapacity, TimeUnit timeUnit, long period) { return withLimitedBandwidth(maxCapacity, timeUnit, period, maxCapacity); } + /** + * Adds limited bandwidth for all buckets which will be constructed by this builder instance. + *

+ * You can specify as many limited bandwidth as needed, but with following limitation: each limited bandwidth should has unique period, + * and when period of bandwidth X is greater than bandwidth Y, + * then capacity of bandwidth X should be greater capacity of bandwidth Y, + * except cases when capacity of bandwidth X or Y is dynamic(provided by {@link com.github.bucket4j.BandwidthAdjuster}). + *

+ *

+     * {@code
+     * // Adds bandwidth that restricts to consume not often 1 tokens per 10 minutes, and initial capacity 0.
+     * builder.withLimitedBandwidth(1, TimeUnit.MINUTES, 10, 0);
+     * }
+     * 
+ * + * @param maxCapacity the maximum capacity of bandwidth + * @param timeUnit Unit for period. + * @param period Period of bandwidth. + * @param initialCapacity initial capacity + * + */ public BucketBuilder withLimitedBandwidth(long maxCapacity, TimeUnit timeUnit, long period, long initialCapacity) { final long bandwidthPeriod = timeMeter.toBandwidthPeriod(timeUnit, period); final BandwidthDefinition bandwidth = new BandwidthDefinition(maxCapacity, initialCapacity, bandwidthPeriod, false); @@ -204,6 +265,20 @@ public BucketBuilder withLimitedBandwidth(long maxCapacity, TimeUnit timeUnit, l return this; } + /** + * Adds limited bandwidth for all buckets which will be constructed by this builder instance. + *

+ * You can specify as many limited bandwidth as needed, but with following limitation: each limited bandwidth should has unique period, + * and when period of bandwidth X is greater than bandwidth Y, + * then capacity of bandwidth X should be greater capacity of bandwidth Y, + * except cases when capacity of bandwidth X or Y is dynamic(provided by {@link com.github.bucket4j.BandwidthAdjuster}). + * + * @param bandwidthAdjuster provider of bandwidth capacity + * @param timeUnit Unit for period. + * @param period Period of bandwidth. + * @param initialCapacity initial capacity + * + */ public BucketBuilder withLimitedBandwidth(BandwidthAdjuster bandwidthAdjuster, TimeUnit timeUnit, long period, long initialCapacity) { final long bandwidthPeriod = timeMeter.toBandwidthPeriod(timeUnit, period); final BandwidthDefinition bandwidth = new BandwidthDefinition(bandwidthAdjuster, initialCapacity, bandwidthPeriod, false); @@ -211,14 +286,16 @@ public BucketBuilder withLimitedBandwidth(BandwidthAdjuster bandwidthAdjuster, T return this; } - public BandwidthDefinition getBandwidthDefinition(int index) { - return bandwidths.get(index); - } - + /** + * @return Time meter used for time measuring. + */ public TimeMeter getTimeMeter() { return timeMeter; } + /** + * @return configuration which used for bucket construction. + */ public BucketConfiguration createConfiguration() { return new BucketConfiguration(this.bandwidths, timeMeter); } @@ -231,4 +308,8 @@ public String toString() { '}'; } + BandwidthDefinition getBandwidthDefinition(int index) { + return bandwidths.get(index); + } + } diff --git a/src/main/java/com/github/bucket4j/TimeMeter.java b/src/main/java/com/github/bucket4j/TimeMeter.java index a20605f1..0b239c0c 100644 --- a/src/main/java/com/github/bucket4j/TimeMeter.java +++ b/src/main/java/com/github/bucket4j/TimeMeter.java @@ -21,14 +21,31 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; +/** + * An abstraction over time measurement. + * + * @see com.github.bucket4j.TimeMeter#SYSTEM_NANOTIME + * @see com.github.bucket4j.TimeMeter#SYSTEM_MILLISECONDS + */ public interface TimeMeter extends Serializable { + /** + * @return current time, which can be a milliseconds, nanoseconds, or something else in case of custom implementation. + */ long currentTime(); + /** + * Sleep required amount of time. + * @param units time to sleep + * @throws InterruptedException if current tread is interrupted. + */ void sleep(long units) throws InterruptedException; long toBandwidthPeriod(TimeUnit timeUnit, long period); + /** + * The implementation of {@link TimeMeter} which works arround {@link java.lang.System#nanoTime} + */ public static final TimeMeter SYSTEM_NANOTIME = new TimeMeter() { @Override public long currentTime() { @@ -54,6 +71,9 @@ public String toString() { } }; + /** + * The implementation of {@link TimeMeter} which works around {@link java.lang.System#currentTimeMillis} + */ public static final TimeMeter SYSTEM_MILLISECONDS = new TimeMeter() { @Override public long currentTime() {