Skip to content

Commit

Permalink
feat(core): Avoid time going backwards for CacheClock (#616)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahoo-Wang authored Aug 15, 2024
1 parent b9729c3 commit 89ffd7a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
15 changes: 11 additions & 4 deletions cosid-core/src/main/java/me/ahoo/cosid/util/Clock.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
* @author ahoo wang
*/
@ThreadSafe
@FunctionalInterface
public interface Clock {

Clock CACHE = new CacheClock();
Clock SYSTEM = new SystemClock();
Clock CACHE = new CacheClock(SYSTEM);

long secondTime();

Expand Down Expand Up @@ -58,11 +59,13 @@ class CacheClock implements Clock, Runnable {
* Tolerate a one-second time limit.
*/
public static final long ONE_SECOND_PERIOD = Duration.ofSeconds(1).toNanos();
private final Clock clock;
private final Thread thread;
private volatile long lastTime;

public CacheClock() {
this.lastTime = getSystemSecondTime();
public CacheClock(Clock clock) {
this.clock = clock;
this.lastTime = clock.secondTime();
this.thread = new Thread(this);
this.thread.setName("CosId-CacheClock");
this.thread.setDaemon(true);
Expand All @@ -77,7 +80,11 @@ public long secondTime() {
@Override
public void run() {
while (!thread.isInterrupted()) {
this.lastTime = getSystemSecondTime();
long currentTime = clock.secondTime();
// Avoid time going backwards
if (currentTime > lastTime) {
this.lastTime = currentTime;
}
LockSupport.parkNanos(this, ONE_SECOND_PERIOD);
}
}
Expand Down
26 changes: 26 additions & 0 deletions cosid-core/src/test/java/me/ahoo/cosid/util/CacheClockTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@

package me.ahoo.cosid.util;

import static me.ahoo.cosid.util.Clock.CacheClock.ONE_SECOND_PERIOD;
import static org.junit.jupiter.api.Assertions.assertTrue;

import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;


/**
Expand All @@ -45,4 +47,28 @@ void secondTimeWhenSleep() {
long tolerance = 1L;
assertTrue(diff <= tolerance);
}

@Test
void secondTimeIfBackwards() {
Clock backwardsClock = new BackwardsClock();
Clock cacheClock = new Clock.CacheClock(backwardsClock);
long lastTime = cacheClock.secondTime();
for (int i = 0; i < 6; i++) {
LockSupport.parkNanos(this, ONE_SECOND_PERIOD);
long currentTime = cacheClock.secondTime();
assertTrue(currentTime >= lastTime);
lastTime = currentTime;
}
}

static class BackwardsClock implements Clock {
private final long[] timeline = new long[]{1, 2, 3, 4, 5};
private int index = 0;

@Override
public long secondTime() {
int idx = Math.floorMod(index++, timeline.length);
return timeline[idx];
}
}
}

0 comments on commit 89ffd7a

Please sign in to comment.