package ibis.ipl.registry.central.client;
import ibis.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Heartbeat implements Runnable {
private static final Logger logger = LoggerFactory
.getLogger(Heartbeat.class);
private final Pool pool;
private final CommunicationHandler commHandler;
private final long heartbeatInterval;
private final boolean exitOnServerFailure;
private long heartbeatDeadline;
private long serverFailureDeadline;
Heartbeat(CommunicationHandler commHandler, Pool pool,
long heartbeatInterval, boolean exitOnServerFailure) {
this.commHandler = commHandler;
this.pool = pool;
this.heartbeatInterval = heartbeatInterval;
this.exitOnServerFailure = exitOnServerFailure;
ThreadPool.createNew(this, "heartbeat thread");
}
synchronized void resetServerDeadline() {
serverFailureDeadline = System.currentTimeMillis()
+ (heartbeatInterval * 5);
}
synchronized void resetHeartbeadDeadline() {
heartbeatDeadline = System.currentTimeMillis()
+ (long) (heartbeatInterval * 0.9 * Math.random());
}
synchronized void resetDeadlines() {
resetHeartbeadDeadline();
resetServerDeadline();
logger.debug("deadlines reset");
// no need to wake up heartbeat thread, deadline will only be later
}
synchronized boolean serverDeadlineExpired() {
return System.currentTimeMillis() > serverFailureDeadline;
}
synchronized void nudge() {
notifyAll();
}
synchronized void waitForHeartbeatDeadline() {
while (true) {
int timeout = (int) (heartbeatDeadline - System.currentTimeMillis());
if (timeout <= 0) {
return;
}
try {
logger.debug("waiting " + timeout + " for heartbeat");
wait(timeout);
} catch (InterruptedException e) {
// IGNORE
}
}
}
public void run() {
while (!pool.isStopped()) {
waitForHeartbeatDeadline();
boolean success = commHandler.sendHeartBeat();
if (success) {
resetServerDeadline();
resetHeartbeadDeadline();
} else {
resetHeartbeadDeadline();
}
if (serverDeadlineExpired()) {
if (exitOnServerFailure) {
logger.error("Registry: contact with server lost, terminating JVM");
System.exit(1);
} else {
logger.warn("Registry: contact with server lost");
}
}
}
}
}