Class AtomicRateLimiter
- All Implemented Interfaces:
RateLimiter
AtomicRateLimiter splits all nanoseconds from the start of epoch into cycles.
Each cycle has duration of RateLimiterConfig.getLimitRefreshPeriod() in nanoseconds.
By contract on start of each cycle AtomicRateLimiter should
set AtomicRateLimiter.State.activePermissions to RateLimiterConfig.getLimitForPeriod(). For the AtomicRateLimiter callers it is really looks so, but under the hood there is some optimisations
that will skip this refresh if AtomicRateLimiter is not used actively.
All AtomicRateLimiter updates are atomic and state is encapsulated in AtomicReference to AtomicRateLimiter.State
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionclassEnhancedRateLimiter.Metricswith some implementation specific detailsprivate static classAtomicRateLimiter.Staterepresents immutable state ofAtomicRateLimiterwhere: activeCycle -AtomicRateLimitercycle number that was used by the lastRateLimiter.acquirePermission()call.Nested classes/interfaces inherited from interface RateLimiter
RateLimiter.EventPublisher, RateLimiter.Metrics -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final RateLimiterEventProcessorprivate final Stringprivate final longprivate final AtomicReference<AtomicRateLimiter.State> private final AtomicInteger -
Constructor Summary
ConstructorsConstructorDescriptionAtomicRateLimiter(String name, RateLimiterConfig rateLimiterConfig) AtomicRateLimiter(String name, RateLimiterConfig rateLimiterConfig, Map<String, String> tags) -
Method Summary
Modifier and TypeMethodDescriptionbooleanacquirePermission(int permits) Acquires the given number of permits from this rate limiter, blocking until one is available, or the thread is interrupted.private AtomicRateLimiter.StatecalculateNextState(int permits, long timeoutInNanos, AtomicRateLimiter.State activeState) A side-effect-free function that can calculate nextAtomicRateLimiter.Statefrom current.voidchangeLimitForPeriod(int limitForPeriod) Dynamic rate limiter configuration change.voidchangeTimeoutDuration(Duration timeoutDuration) Dynamic rate limiter configuration change.private booleancompareAndSet(AtomicRateLimiter.State current, AtomicRateLimiter.State next) Atomically sets the value to the given updated value if the current value==the expected value.private longCalculates time elapsed from the class loading.private static intdivCeil(int x, int y) Divide two integers and round result to the bigger near mathematical integer.voidDrains all the permits left in the current period.Get the enhanced Metrics with some implementation specific details.Returns an EventPublisher which can be used to register event consumers.Get the Metrics of this RateLimiter.getName()Get the name of this RateLimiter(package private) longGet the RateLimiterConfig of this RateLimiter.getTags()Returns an unmodifiable map with tags assigned to this RateLimiter.private longnanosToWaitForPermission(int permits, long cyclePeriodInNanos, int permissionsPerCycle, int availablePermissions, long currentNanos, long currentCycle) Calculates time to wait for the required permits of permissions to get accumulatedprivate voidpublishRateLimiterAcquisitionEvent(boolean permissionAcquired, int permits) longreservePermission(int permits) Reserves the given number permits from this rate limiter and returns nanoseconds you should wait for it.private AtomicRateLimiter.StatereservePermissions(RateLimiterConfig config, int permits, long timeoutInNanos, long cycle, int permissions, long nanosToWait) Determines whether caller can acquire permission before timeout or not and then creates correspondingAtomicRateLimiter.State.toString()private AtomicRateLimiter.StateupdateStateWithBackOff(int permits, long timeoutInNanos) Atomically updates the currentAtomicRateLimiter.Statewith the results of applying thecalculateNextState(int, long, AtomicRateLimiter.State), returning the updatedAtomicRateLimiter.State.private booleanwaitForPermission(long nanosToWait) ParksThreadfor nanosToWait.private booleanwaitForPermissionIfNecessary(long timeoutInNanos, long nanosToWait) If nanosToWait is bigger than 0 it tries to parkThreadfor nanosToWait but not longer then timeoutInNanos.Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface RateLimiter
acquirePermission, drainIfNeeded, executeCallable, executeCallable, executeCheckedSupplier, executeCheckedSupplier, executeCompletionStage, executeRunnable, executeRunnable, executeSupplier, executeSupplier, onError, onResult, onSuccess, reservePermission
-
Field Details
-
nanoTimeStart
private final long nanoTimeStart -
name
-
waitingThreads
-
state
-
tags
-
eventProcessor
-
-
Constructor Details
-
AtomicRateLimiter
-
AtomicRateLimiter
-
-
Method Details
-
changeTimeoutDuration
Dynamic rate limiter configuration change. This method allows to change timeout duration of current limiter. NOTE! New timeout duration won't affect threads that are currently waiting for permission.- Specified by:
changeTimeoutDurationin interfaceRateLimiter- Parameters:
timeoutDuration- new timeout duration
-
changeLimitForPeriod
public void changeLimitForPeriod(int limitForPeriod) Dynamic rate limiter configuration change. This method allows to change count of permissions available during refresh period. NOTE! New limit won't affect current period permissions and will apply only from next one.- Specified by:
changeLimitForPeriodin interfaceRateLimiter- Parameters:
limitForPeriod- new permissions limit
-
currentNanoTime
private long currentNanoTime()Calculates time elapsed from the class loading. -
getNanoTimeStart
long getNanoTimeStart() -
acquirePermission
public boolean acquirePermission(int permits) Acquires the given number of permits from this rate limiter, blocking until one is available, or the thread is interrupted. Maximum wait time isRateLimiterConfig.getTimeoutDuration()If the current thread is interrupted while waiting for a permit then it won't throw InterruptedException, but its interrupt status will be set.
- Specified by:
acquirePermissionin interfaceRateLimiter- Parameters:
permits- number of permits - use for systems where 1 call != 1 permit- Returns:
trueif a permit was acquired andfalseif waiting timeoutDuration elapsed before a permit was acquired
-
reservePermission
public long reservePermission(int permits) Reserves the given number permits from this rate limiter and returns nanoseconds you should wait for it. If returned long is negative, it means that you failed to reserve permission, possibly yourRateLimiterConfig.getTimeoutDuration()is less then time to wait for permission.- Specified by:
reservePermissionin interfaceRateLimiter- Parameters:
permits- number of permits - use for systems where 1 call != 1 permit- Returns:
longamount of nanoseconds you should wait for reserved permissions. if negative, it means you failed to reserve.
-
drainPermissions
public void drainPermissions()Description copied from interface:RateLimiterDrains all the permits left in the current period.- Specified by:
drainPermissionsin interfaceRateLimiter
-
updateStateWithBackOff
Atomically updates the currentAtomicRateLimiter.Statewith the results of applying thecalculateNextState(int, long, AtomicRateLimiter.State), returning the updatedAtomicRateLimiter.State. It differs fromAtomicReference.updateAndGet(UnaryOperator)by constant back off. It means that after one try toAtomicReference.compareAndSet(Object, Object)this method will wait for a while before try one more time. This technique was originally described in this paper and showed great results withAtomicRateLimiterin benchmark tests.- Parameters:
timeoutInNanos- a side-effect-free function- Returns:
- the updated value
-
compareAndSet
Atomically sets the value to the given updated value if the current value==the expected value. It differs fromAtomicReference.updateAndGet(UnaryOperator)by constant back off. It means that after one try toAtomicReference.compareAndSet(Object, Object)this method will wait for a while before try one more time. This technique was originally described in this paper and showed great results withAtomicRateLimiterin benchmark tests.- Parameters:
current- the expected valuenext- the new value- Returns:
trueif successful. False return indicates that the actual value was not equal to the expected value.
-
calculateNextState
private AtomicRateLimiter.State calculateNextState(int permits, long timeoutInNanos, AtomicRateLimiter.State activeState) A side-effect-free function that can calculate nextAtomicRateLimiter.Statefrom current. It determines time duration that you should wait for the given number of permits and reserves it for you, if you'll be able to wait long enough.- Parameters:
permits- number of permitstimeoutInNanos- max time that caller can wait for permission in nanosecondsactiveState- current state ofAtomicRateLimiter- Returns:
- next
AtomicRateLimiter.State
-
nanosToWaitForPermission
private long nanosToWaitForPermission(int permits, long cyclePeriodInNanos, int permissionsPerCycle, int availablePermissions, long currentNanos, long currentCycle) Calculates time to wait for the required permits of permissions to get accumulated- Parameters:
permits- permits of required permissionscyclePeriodInNanos- current configuration valuespermissionsPerCycle- current configuration valuesavailablePermissions- currently available permissions, can be negative if some permissions have been reservedcurrentNanos- current time in nanosecondscurrentCycle- currentAtomicRateLimitercycle @return nanoseconds to wait for the next permission
-
divCeil
private static int divCeil(int x, int y) Divide two integers and round result to the bigger near mathematical integer.- Parameters:
x- - should be > 0y- - should be > 0
-
reservePermissions
private AtomicRateLimiter.State reservePermissions(RateLimiterConfig config, int permits, long timeoutInNanos, long cycle, int permissions, long nanosToWait) Determines whether caller can acquire permission before timeout or not and then creates correspondingAtomicRateLimiter.State. Reserves permissions only if caller can successfully wait for permission.- Parameters:
config-permits- permits of permissionstimeoutInNanos- max time that caller can wait for permission in nanosecondscycle- cycle for newAtomicRateLimiter.Statepermissions- permissions for newAtomicRateLimiter.StatenanosToWait- nanoseconds to wait for the next permission- Returns:
- new
AtomicRateLimiter.Statewith possibly reserved permissions and time to wait
-
waitForPermissionIfNecessary
private boolean waitForPermissionIfNecessary(long timeoutInNanos, long nanosToWait) If nanosToWait is bigger than 0 it tries to parkThreadfor nanosToWait but not longer then timeoutInNanos.- Parameters:
timeoutInNanos- max time that caller can waitnanosToWait- nanoseconds caller need to wait- Returns:
- true if caller was able to wait for nanosToWait without
Thread.interrupt()and not exceed timeout
-
waitForPermission
private boolean waitForPermission(long nanosToWait) ParksThreadfor nanosToWait.If the current thread is Thread.interrupted while waiting for a permit then it won't throw InterruptedException, but its interrupt status will be set.
- Parameters:
nanosToWait- nanoseconds caller need to wait- Returns:
- true if caller was not
Thread.interruptedwhile waiting
-
getName
Get the name of this RateLimiter- Specified by:
getNamein interfaceRateLimiter- Returns:
- the name of this RateLimiter
-
getRateLimiterConfig
Get the RateLimiterConfig of this RateLimiter.- Specified by:
getRateLimiterConfigin interfaceRateLimiter- Returns:
- the RateLimiterConfig of this RateLimiter
-
getTags
Returns an unmodifiable map with tags assigned to this RateLimiter.- Specified by:
getTagsin interfaceRateLimiter- Returns:
- the tags assigned to this Retry in an unmodifiable map
-
getMetrics
Get the Metrics of this RateLimiter.- Specified by:
getMetricsin interfaceRateLimiter- Returns:
- the Metrics of this RateLimiter
-
getEventPublisher
Description copied from interface:RateLimiterReturns an EventPublisher which can be used to register event consumers.- Specified by:
getEventPublisherin interfaceRateLimiter- Returns:
- an EventPublisher
-
toString
-
getDetailedMetrics
Get the enhanced Metrics with some implementation specific details.- Returns:
- the detailed metrics
-
publishRateLimiterAcquisitionEvent
private void publishRateLimiterAcquisitionEvent(boolean permissionAcquired, int permits)
-