Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.ehcache.util;
import net.sf.ehcache.util.lang.VicariousThreadLocal;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* SlewClock will return the current time in millis, but will never go back in time.
* If it detects that a back movement in time, it will slew the results while keeping them incrementing until time has caught up
*
* @author Chris Denis
* @author Alex Snaps
*/
final class SlewClock {
private static final Logger LOG = LoggerFactory.getLogger(SlewClock.class);
private static final TimeProvider PROVIDER = TimeProviderLoader.getTimeProvider();
private static final long DRIFT_MAXIMAL = Integer.getInteger("net.sf.ehcache.util.Timestamper.drift.max", 50);
private static final long SLEEP_MAXIMAL = Integer.getInteger("net.sf.ehcache.util.Timestamper.sleep.max", 50);
private static final int SLEEP_BASE = Integer.getInteger("net.sf.ehcache.util.Timestamper.sleep.min", 25);
private static final AtomicLong CURRENT = new AtomicLong(Long.MIN_VALUE);
private static final VicariousThreadLocal OFFSET = new VicariousThreadLocal();
private SlewClock() {
// You shall not instantiate me!
}
/**
* For testing purposes, you probably never want to use this.
* This method will resync, basically resetting any on going slewing, its internal clock tracking with whatever value
* the provider seeds it with.
*
* @deprecated
*/
@Deprecated
static void realignWithTimeProvider() {
CURRENT.set(getCurrentTime());
}
/**
* Will return the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
* But without ever going back. If a movement back in time is detected, the method will slew until time caught up
* @return The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
*/
static long timeMillis() {
boolean interrupted = false;
try {
while (true) {
long mono = CURRENT.get();
long wall = getCurrentTime();
if (wall == mono) {
OFFSET.remove();
return wall;
} else if (wall > mono) {
if (CURRENT.compareAndSet(mono, wall)) {
OFFSET.remove();
return wall;
}
} else {
long delta = mono - wall;
if (delta < DRIFT_MAXIMAL) {
OFFSET.remove();
return mono;
} else {
Long lastDelta = OFFSET.get();
if (lastDelta == null || delta < lastDelta) {
if (CURRENT.compareAndSet(mono, mono + 1)) {
OFFSET.set(Long.valueOf(delta));
return mono + 1;
}
} else {
OFFSET.set(Long.valueOf(Math.max(delta, lastDelta)));
try {
long sleep = sleepTime(delta, lastDelta);
LOG.trace("{} sleeping for {}ms to adjust for wall-clock drift.", Thread.currentThread(), sleep);
Thread.sleep(sleep);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
/**
* Verifies whether the current thread is currently catching up on time.
* To be meaning full, this method has to be called after the thread has called {@link #timeMillis()} at least once
* @return true if the thread is being marked as catching up on time
*/
static boolean isThreadCatchingUp() {
return OFFSET.get() != null;
}
/**
* The method will check how much behind is the current thread compared to the wall clock since the last {@link #timeMillis()} call.
* To be meaning full, this method has to be called after the thread has called {@link #timeMillis()} at least once
* @return the amount of milliseconds the thread is behind the wall clock, 0 if none.
*/
static long behind() {
Long offset = OFFSET.get();
return offset == null ? 0 : offset;
}
private static long sleepTime(final long current, final long previous) {
long target = SLEEP_BASE + (current - previous) * 2;
return Math.min(target > 0 ? target : SLEEP_BASE, SLEEP_MAXIMAL);
}
private static long getCurrentTime() {
return PROVIDER.currentTimeMillis();
}
/**
* Defines how the {@link SlewClock} utility class will get to the wall clock
*/
interface TimeProvider {
/**
* @return the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
*/
long currentTimeMillis();
}
}