Skip to content

Commit

Permalink
Merge pull request ReactiveX#66 from resilience4j/negative_nanotime_h…
Browse files Browse the repository at this point in the history
…andling

nano time handling in AtomicRateLimiter adapted for negative values
  • Loading branch information
storozhukBM authored Mar 25, 2017
2 parents 92f7603 + 35e7a57 commit 752af8b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public void testDecoratorBuilderWithRateLimiter(){
.withRateLimiter(rateLimiter)
.decorate();

alignTime();
alignTime(rateLimiter);
Try<String> firstTry = Try.of(restrictedSupplier);
assertThat(firstTry.isSuccess()).isTrue();
Try<String> secondTry = Try.of(restrictedSupplier);
Expand All @@ -223,9 +223,13 @@ public void testDecoratorBuilderWithRateLimiter(){
BDDMockito.then(helloWorldService).should(times(1)).returnHelloWorld();
}

private void alignTime() {
// Wait to the start of the next second in spin loop
while (System.nanoTime() % 1_000_000_000L > 10_000L) {
private void alignTime(RateLimiter rateLimiter) {
RateLimiter.Metrics metrics = rateLimiter.getMetrics();
while (rateLimiter.getPermission(Duration.ZERO)) {
state = !state;
}
// Wait to the start of the next cycle in spin loop
while (metrics.getAvailablePermissions() == 0) {
state = !state;
}
System.out.println(state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
* {@link AtomicRateLimiter.State}
*/
public class AtomicRateLimiter implements RateLimiter {
private static final long nanoTimeStart = nanoTime();

private final String name;
private final RateLimiterConfig rateLimiterConfig;
Expand All @@ -72,6 +73,13 @@ public AtomicRateLimiter(String name, RateLimiterConfig rateLimiterConfig) {
this.eventPublisher = publisher.toSerialized();
}

/**
* Calculates time elapsed from the class loading.
*/
private long currentNanoTime() {
return nanoTime() - nanoTimeStart;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -156,7 +164,6 @@ private State calculateNextState(final long timeoutInNanos, final State activeSt
return nextState;
}


/**
* Calculates time to wait for next permission as
* [time to the next cycle] + [duration of full cycles until reserved permissions expire]
Expand Down Expand Up @@ -282,13 +289,6 @@ public AtomicRateLimiterMetrics getDetailedMetrics() {
return new AtomicRateLimiterMetrics();
}

/**
* Created only for test purposes. Simply calls {@link System#nanoTime()}
*/
private long currentNanoTime() {
return nanoTime();
}

private void publishRateLimiterEvent(boolean permissionAcquired) {
if (!eventPublisher.hasSubscribers()) {
return;
Expand Down Expand Up @@ -317,6 +317,7 @@ private void publishRateLimiterEvent(boolean permissionAcquired) {
private static class State {

private final long activeCycle;

private final int activePermissions;
private final long nanosToWait;

Expand Down Expand Up @@ -371,5 +372,6 @@ public long getCycle() {
State estimatedState = calculateNextState(-1, currentState);
return estimatedState.activeCycle;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,31 @@ public void setup() {
eventStream = rateLimiter.getEventStream();
}

@Test
public void notSpyRawTest() {
AtomicRateLimiter rawLimiter = new AtomicRateLimiter("rawLimiter", rateLimiterConfig);
AtomicRateLimiter.AtomicRateLimiterMetrics rawDetailedMetrics = rawLimiter.getDetailedMetrics();

long firstCycle = rawDetailedMetrics.getCycle();
while (firstCycle == rawDetailedMetrics.getCycle()) {
System.out.print('.'); // wait for current cycle to pass
}

boolean firstPermission = rawLimiter.getPermission(Duration.ZERO);
long nanosToWait = rawDetailedMetrics.getNanosToWait();
long startTime = System.nanoTime();
while(System.nanoTime() - startTime < nanosToWait) {
System.out.print('*'); // wait for permission renewal
}

boolean secondPermission = rawLimiter.getPermission(Duration.ZERO);
long secondCycle = rawDetailedMetrics.getCycle();

then(secondCycle - firstCycle).isEqualTo(2);
then(firstPermission).isTrue();
then(secondPermission).isTrue();
}

@Test
public void permissionsInFirstCycle() throws Exception {
setTimeOnNanos(CYCLE_IN_NANOS - 10);
Expand Down

0 comments on commit 752af8b

Please sign in to comment.