+
+ private static class ClockSequenceProvider {
+ private int rangeSize = 256;
+ private volatile int min;
+ private volatile int max;
+ private final AtomicLong counter = new AtomicLong(-1);
+
+ private final SecureRandom secureRandom;
+
+ private final Map<Holder, Long> activeHolders = Collections.synchronizedMap(new WeakHashMap<>());
+
+ ClockSequenceProvider(SecureRandom secureRandom) {
+ this.secureRandom = secureRandom;
+ reset();
+ }
+
+ synchronized void reset() {
+ int min = secureRandom.nextInt(ConcurrentTimeUuidState.MAX_CLOCKSEQUENCE - rangeSize);
+ int max = min + rangeSize;
+ if (min >= max)
+ throw new IllegalArgumentException("Minimum " + min + " is bigger than maximum " + max);
+ if (min < 0 || min > MAX_CLOCKSEQUENCE)
+ throw new IllegalArgumentException("Minimum " + min + " is not valid");
+ if (max < 0 || max > MAX_CLOCKSEQUENCE)
+ throw new IllegalArgumentException("Maximum " + max + " is not valid");
+ this.min = min;
+ this.max = max;
+
+ Set<Holder> active = activeHolders.keySet();
+ int activeCount = active.size();
+ if (activeCount > getRangeSize())
+ throw new IllegalStateException(
+ "There are too many holders for range [" + min + "," + max + "] : " + activeCount);
+ // reset the counter
+ counter.set(min);
+ for (Holder holder : active) {
+ // save old clocksequence?
+ newClockSequence(holder);
+ }
+ }
+
+ private synchronized int getRangeSize() {
+ return rangeSize;
+ }
+
+ private synchronized void newClockSequence(Holder holder) {
+ // Too many holders, we will remove the oldes ones
+ while (activeHolders.size() > rangeSize) {
+ long oldestTimeStamp = -1;
+ Holder holderToRemove = null;
+ holders: for (Holder h : activeHolders.keySet()) {
+ if (h == holder)// skip the caller
+ continue holders;
+
+ if (oldestTimeStamp < 0) {
+ oldestTimeStamp = h.lastTimestamp;
+ holderToRemove = h;
+ }
+ if (h.lastTimestamp <= oldestTimeStamp) {
+ oldestTimeStamp = h.lastTimestamp;
+ holderToRemove = h;
+ }
+
+ }
+ assert holderToRemove != null;
+ long oldClockSequence = holderToRemove.clockSequence;
+ holderToRemove.clockSequence = -1;
+ activeHolders.remove(holderToRemove);
+ if (logger.isLoggable(WARNING))
+ logger.log(WARNING, "Removed " + holderToRemove + ", oldClockSequence=" + oldClockSequence);
+ }
+
+ long newClockSequence = -1;
+ int tryCount = 0;// an explicit exit condition
+ do {
+ tryCount++;
+ if (tryCount >= rangeSize)
+ throw new IllegalStateException("No more clock sequence available");
+
+ newClockSequence = counter.incrementAndGet();
+ assert newClockSequence >= 0 : "Clock sequence cannot be negative";
+ if (newClockSequence > max) {
+ // reset counter
+ newClockSequence = min;
+ counter.set(newClockSequence);
+ }
+ } while (activeHolders.containsValue(newClockSequence));
+ // TODO use an iterator to check the values
+ holder.setClockSequence(newClockSequence);
+ activeHolders.put(holder, newClockSequence);
+ if (logger.isLoggable(DEBUG))
+ logger.log(DEBUG,
+ "New clocksequence " + newClockSequence + " for thread " + Thread.currentThread().getId());
+ }
+
+ }
+