Last active
November 18, 2015 01:37
-
-
Save shikhar/9a3bef3b936045e94bab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.Clock; | |
import java.util.concurrent.atomic.AtomicLong; | |
public class ClockedMonotonicCounter { | |
// sign_bit_unused | 42_bits_epochTimeMs | 21_bit_counter | |
private static final int TIME_SHIFT = 21; | |
private static final int COUNTER_MASK = (1 << TIME_SHIFT) - 1; | |
private final Clock clock; | |
private final AtomicLong lastValue; | |
public ClockedMonotonicCounter(final Clock clock) { | |
this(clock, 0); | |
} | |
public ClockedMonotonicCounter(final Clock clock, final long lastValue) { | |
this.clock = clock; | |
this.lastValue = new AtomicLong(lastValue); | |
} | |
// returns negative value if blocking suggested with the magnitude representing how long in ms | |
public long next() { | |
long prev, next; | |
do { | |
prev = lastValue.get(); | |
final long prevMs = epochTimeMs(prev); | |
final long nowMs = clock.millis(); | |
next = nowMs << TIME_SHIFT; | |
if (next < 0) { | |
// On or after: Wed, 15 May 2109 07:35:11 | |
throw new AssertionError("Exceeded maximum supported timestamp with clock.millis() =" + nowMs); | |
} | |
if (prevMs > nowMs) { | |
return nowMs - prevMs; | |
} else if (nowMs == prevMs) { | |
final long prevCount = count(prev); | |
if (prevCount == COUNTER_MASK) { | |
return -1; | |
} else { | |
next |= prevCount + 1; | |
} | |
} | |
} while (!lastValue.compareAndSet(prev, next)); | |
return next; | |
} | |
public static long epochTimeMs(long value) { | |
assert value > 0; | |
return value >> TIME_SHIFT; | |
} | |
public static int count(long value) { | |
assert value > 0; | |
return (int) (value & COUNTER_MASK); | |
} | |
public static void main(String... args) { | |
final ClockedMonotonicCounter cmc = new ClockedMonotonicCounter(Clock.systemUTC()); | |
for (int i = 0; i < 10000; i++) { | |
final long value = cmc.next(); | |
System.out.println(epochTimeMs(value) + " " + count(value)); | |
} | |
} | |
} |
Author
shikhar
commented
Nov 18, 2015
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment