/*
* Copyright (C) 2012, 2016 higherfrequencytrading.com
* Copyright (C) 2016 Roman Leventov
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.chronicle.hash.replication;
import net.openhft.chronicle.hash.ChronicleHash;
import net.openhft.chronicle.hash.ChronicleHashBuilder;
import net.openhft.chronicle.hash.ChronicleHashBuilderPrivateAPI;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
/**
* {@code TimeProvider} encapsulates time measurement for {@link ChronicleHash} replication needs.
* It is used to obtain timestamps of entry updates, and to determine, when deleted entries become
* eligible for complete purge from the Chronicle Hash data store.
*
* @see ReplicableEntry#originTimestamp()
* @see RemoteOperationContext#remoteTimestamp()
* @see ChronicleHashBuilderPrivateAPI#removedEntryCleanupTimeout(long, TimeUnit)
*/
public final class TimeProvider {
private TimeProvider() {}
private static final AtomicLong lastTimeHolder = new AtomicLong();
/**
* Returns a non-decreasing number, assumed to be used as a "timestamp".
*
* <p>Approximate system time interval between two calls of this method is retrievable via
* {@link #systemTimeIntervalBetween(long, long, TimeUnit)}, applied to the returned values
* from those {@code currentTime()} calls.
*
* <p>Safe and scalable for concurrent use from multiple threads.
*
* @return the current timestamp
*/
public static long currentTime() {
long now = MILLISECONDS.toNanos(System.currentTimeMillis());
while (true) {
long lastTime = lastTimeHolder.get();
if (now <= lastTime)
return lastTime;
if (lastTimeHolder.compareAndSet(lastTime, now))
return now;
}
}
/**
* Returns system time interval (i. e. wall time interval) between two time values, taken using
* {@link #currentTime()} method, with the highest possible precision, in the given time units.
*
* @param earlierTime {@link #currentTime()} result, taken at some moment in the past (earlier)
* @param laterTime {@link #currentTime()} result, taken at some moment in the past, but later
* than {@code earlierTime} was taken ("later" means there is a happens-before relationship
* between the two subject {@code currentTime()} calls)
* @param systemTimeIntervalUnit the time units to return system time interval in
* @return wall time interval between the specified moments in the given time unit
*/
public static long systemTimeIntervalBetween(
long earlierTime, long laterTime, TimeUnit systemTimeIntervalUnit) {
long intervalNanos = laterTime - earlierTime;
return systemTimeIntervalUnit.convert(intervalNanos, NANOSECONDS);
}
}