Author: jukka
Date: Wed Mar 26 05:22:42 2014
New Revision: 1581695
URL: http://svn.apache.org/r1581695
Log:
OAK-1535: ClockTest.testClockDrift failures
Some further Clock.ACCURATE improvements
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/stats/Clock.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/stats/Clock.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/stats/Clock.java?rev=1581695&r1=1581694&r2=1581695&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/stats/Clock.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/stats/Clock.java
Wed Mar 26 05:22:42 2014
@@ -188,7 +188,6 @@ public abstract class Clock {
*/
public static Clock ACCURATE = new Clock() {
private static final long NS_IN_MS = 1000000;
- private static final long SYNC_INTERVAL = 1000; // ms
private long ms = SIMPLE.getTime();
private long ns = System.nanoTime();
@Override
@@ -196,40 +195,67 @@ public abstract class Clock {
long nowns = System.nanoTime();
long nsIncrease = Math.max(nowns - ns, 0); // >= 0
- long msIncrease = nsIncrease / NS_IN_MS;
+ long msIncrease = (nsIncrease + NS_IN_MS/2) / NS_IN_MS; // round up
if (ACCURATE_CLOCK_GRANULARITY > 1) {
msIncrease -= msIncrease % ACCURATE_CLOCK_GRANULARITY;
}
- if (msIncrease < SYNC_INTERVAL) {
+ // If last clock sync was less than one second ago, the nanosecond
+ // timer drift will be insignificant and there's no need to
re-sync.
+ if (msIncrease < 1000) {
return ms + msIncrease;
- } else {
- long nowms = SIMPLE.getTime();
- // Check whether the system time jumped ahead or back
- // from what we'd expect based on the nanosecond interval.
- // If the jump was small, it was probably caused by low
- // granularity of the system time. In that case we reduce
- // the jump to just 0.5ms to smoothen the reported time.
- // This should still keep clock drift in check as long as
- // the nanosecond timings drift on average less than 0.5ms
- // per second.
- long jump = nowms - (ms + msIncrease);
- if (0 < jump && jump < 1000) {
- ms += msIncrease;
- ns += msIncrease * NS_IN_MS - NS_IN_MS / 2;
- } else if (0 > jump && jump > -1000) {
- // Note that the Math.max(..., 0) above will cause the
- // reported time to stay constant for a while instead
- // of going backwards because of this.
- ms += msIncrease;
- ns += msIncrease * NS_IN_MS + NS_IN_MS / 2;
- } else {
- ms = nowms;
- ns = nowns;
+ }
+
+ // Last clock sync was up to ten seconds ago, so we synchronize
+ // smoothly to avoid both drift and sudden jumps.
+ long nowms = SIMPLE.getTime();
+ if (msIncrease < 10000) {
+ // 1) increase the ms and ns timestamps as if the estimated
+ // ms increase was entirely correct
+ ms += msIncrease;
+ ns += msIncrease * NS_IN_MS;
+ // 2) compare the resulting time with the wall clock to see
+ // if we're out of sync and to adjust accordingly
+ long jump = nowms - ms;
+ if (jump == 0) {
+ // 2a) No deviation from wall clock.
+ return ms;
+ } else if (0 < jump && jump < 100) {
+ // 2b) The wall clock is up to 100ms ahead of us, probably
+ // because of its low granularity. Adjust the ns timestamp
+ // 0.1ms backward for future clock readings to jump that
+ // much ahead to eventually catch up with the wall clock.
+ ns -= NS_IN_MS / 10;
+ return ms;
+ } else if (0 > jump && jump > -100) {
+ // 2c) The wall clock is up to 100ms behind us, probably
+ // because of its low granularity. Adjust the ns timestamp
+ // 0.1ms forward for future clock readings to stay constant
+ // (because of the Math.max(..., 0) above) for that long
+ // to eventually catch up with the wall clock.
+ ns += NS_IN_MS / 10;
+ return ms;
}
- return ms;
}
+
+ // Last clock sync was over 10s ago or the nanosecond timer has
+ // drifted more than 100ms from the wall clock, so it's best to
+ // to a hard sync with no smoothing.
+ if (nowms >= ms + 1000) {
+ ms = nowms;
+ ns = nowns;
+ } else {
+ // Prevent the clock from moving backwards by setting the
+ // ms timestamp to exactly 1s ahead of the last sync time
+ // (to account for the time between clock syncs), and
+ // adjusting the ns timestamp ahead so that the reported time
+ // will stall until the clock would again move ahead.
+ ms = ms + 1000; // the 1s clock sync interval from above
+ ns = nowns + (ms - nowms) * NS_IN_MS;
+ }
+ return ms;
}
+
@Override
public String toString() {
return "Clock.ACCURATE";