Skip to content

Commit

Permalink
[Java] Small improvements and consistency to timer wheel.
Browse files Browse the repository at this point in the history
  • Loading branch information
mjpt777 committed Jul 31, 2019
1 parent 08448ec commit 86e47e8
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 39 deletions.
71 changes: 33 additions & 38 deletions agrona/src/main/java/org/agrona/DeadlineTimerWheel.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,6 @@ public long startTime()
return startTime;
}

/**
* Time of current tick of the wheel in {@link #timeUnit()}s.
*
* @return time of the current tick of the wheel in {@link #timeUnit()}s.
*/
public long currentTickTime()
{
return ((currentTick + 1L) << resolutionBitsToShift) + startTime;
}

/**
* Number of active timers.
*
Expand Down Expand Up @@ -221,6 +211,31 @@ public void resetStartTime(final long startTime)
this.pollIndex = 0;
}

/**
* Time of current tick of the wheel in {@link #timeUnit()}s.
*
* @return time of the current tick of the wheel in {@link #timeUnit()}s.
*/
public long currentTickTime()
{
return ((currentTick + 1L) << resolutionBitsToShift) + startTime;
}

/**
* Set the current tick of the wheel to examine on the next {@link #poll}.
*
* If the time passed in is less than the current time, nothing is changed.
* No timers will be expired when winding forward and thus are still in the wheel and will be expired as
* encountered in the wheel during {@link #poll} operations. No guarantee of order for expired timers is
* assumed when later polled.
*
* @param now current time to advance to or stay at current time.
*/
public void currentTickTime(final long now)
{
currentTick = (int)Math.max((now - startTime) >> resolutionBitsToShift, currentTick);
}

/**
* Clear out all active timers in the wheel.
*/
Expand All @@ -232,7 +247,7 @@ public void clear()
return;
}

for (int i = 0; i < wheel.length; i++)
for (int i = 0, length = wheel.length; i < length; i++)
{
if (NULL_DEADLINE != wheel[i])
{
Expand Down Expand Up @@ -274,30 +289,25 @@ public long scheduleTimer(final long deadline)
}

final int newTickAllocation = this.tickAllocation << 1;
final int newAllcationBitsToShift = Integer.numberOfTrailingZeros(newTickAllocation);
final int newAllocationBitsToShift = Integer.numberOfTrailingZeros(newTickAllocation);
final long[] newWheel = new long[ticksPerWheel * newTickAllocation];
Arrays.fill(newWheel, NULL_DEADLINE);

for (int j = 0; j < ticksPerWheel; j++)
{
final int oldTickStartIndex = j << allocationBitsToShift;
final int newTickStartIndex = j << newAllcationBitsToShift;
final int newTickStartIndex = j << newAllocationBitsToShift;

System.arraycopy(wheel, oldTickStartIndex, newWheel, newTickStartIndex, tickAllocation);

Arrays.fill(
newWheel,
newTickStartIndex + tickAllocation,
newTickStartIndex + newTickAllocation,
NULL_DEADLINE);
}

newWheel[(spokeIndex << newAllcationBitsToShift) + tickAllocation] = deadline;
newWheel[(spokeIndex << newAllocationBitsToShift) + tickAllocation] = deadline;
timerCount++;

final long timerId = timerIdForSlot(spokeIndex, tickAllocation);

this.tickAllocation = newTickAllocation;
this.allocationBitsToShift = newAllcationBitsToShift;
this.allocationBitsToShift = newAllocationBitsToShift;
this.wheel = newWheel;

return timerId;
Expand Down Expand Up @@ -361,7 +371,7 @@ public int poll(final long now, final TimerHandler handler, final int expiryLimi
wheel[wheelIndex] = deadline;
timerCount++;

return timersExpired;
return --timersExpired;
}
}

Expand Down Expand Up @@ -396,7 +406,7 @@ public void forEach(final TimerConsumer consumer)
{
long timersRemaining = timerCount;

for (int i = 0; i < wheel.length; i++)
for (int i = 0, length = wheel.length; i < length; i++)
{
final long deadline = wheel[i];

Expand Down Expand Up @@ -435,21 +445,6 @@ public long deadline(final long timerId)
return NULL_DEADLINE;
}

/**
* Wind the wheel forward by setting the current tick of the wheel to examine on the next {@link #poll}.
*
* If the time passed in is less than the current time, nothing is changed.
* No timers will be expired when winding forward and thus are still in the wheel and will be expired as
* encountered in the wheel during {@link #poll} operations. No guarantee of order for past timers is assumed when
* expired later.
*
* @param now current time to wind forward to or stay at current time if now in the past.
*/
public void windForward(final long now)
{
currentTick = (int)Math.max((now - startTime) >> resolutionBitsToShift, currentTick);
}

private static long timerIdForSlot(final int tickOnWheel, final int tickArrayIndex)
{
return ((long)tickOnWheel << 32) | tickArrayIndex;
Expand Down
16 changes: 15 additions & 1 deletion agrona/src/test/java/org/agrona/DeadlineTimerWheelTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ else if (timerId == id2)

assertThat(firedTimestamp1.value, is(17 * wheel.tickResolution()));
assertThat(firedTimestamp2.value, is(17 * wheel.tickResolution()));
assertThat(numExpired, is(3));
assertThat(numExpired, is(2));
}

@Test(timeout = 1000)
Expand Down Expand Up @@ -571,6 +571,20 @@ public void shouldNotAllowResetWhenTimersActive()
wheel.resetStartTime(controlTimestamp + 1);
}

@Test
public void shouldAdvanceWheelToLaterTime()
{
final long startTime = 0;
final DeadlineTimerWheel wheel = new DeadlineTimerWheel(TIME_UNIT, startTime, RESOLUTION, 8);

wheel.scheduleTimer(startTime + 100000);

final long currentTickTime = wheel.currentTickTime();
wheel.currentTickTime(currentTickTime * 5);

assertThat(wheel.currentTickTime(), is(currentTickTime * 6));
}

@Test(timeout = 1000)
public void shouldScheduleDeadlineInThePast()
{
Expand Down

0 comments on commit 86e47e8

Please sign in to comment.