package org.radargun.service;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.infinispan.remoting.transport.Address;
import org.radargun.logging.Log;
import org.radargun.logging.LogFactory;
import org.radargun.traits.Lifecycle;
/**
* @author Radim Vansa <rvansa@redhat.com>
*/
public class InfinispanLifecycle implements Lifecycle {
enum State {
STOPPED,
STARTING,
STARTED,
STOPPING,
FAILED
}
protected final Log log = LogFactory.getLog(getClass());
protected final boolean trace = log.isTraceEnabled();
protected final InfinispanEmbeddedService service;
protected volatile State state = State.STOPPED;
protected ReentrantLock stateLock = new ReentrantLock();
protected Thread startingThread;
public InfinispanLifecycle(InfinispanEmbeddedService service) {
this.service = service;
}
@Override
public void start() {
log.info("Infinispan version: " + org.infinispan.Version.printVersion());
log.debug("Loading JGroups from: " + org.jgroups.Version.class.getProtectionDomain().getCodeSource().getLocation());
log.info("JGroups version: " + org.jgroups.Version.printDescription());
try {
if (beginStart()) {
service.startCaches();
stateLock.lock();
state = State.STARTED;
startingThread = null;
stateLock.unlock();
postSetUpInternal();
}
} catch (Exception e) {
log.error("Service start failed.", e);
if (!stateLock.isHeldByCurrentThread()) {
stateLock.lock();
}
state = State.FAILED;
startingThread = null;
throw new RuntimeException(e);
} finally {
if (stateLock.isHeldByCurrentThread()) {
stateLock.unlock();
}
}
}
protected void postSetUpInternal() throws Exception {
service.waitForRehash();
}
@Override
public void stop() {
try {
if (beginStop(false)) {
List<Address> addressList = service.cacheManager.getMembers();
service.stopCaches();
log.info("Stopped, previous view is " + addressList);
stateLock.lock();
state = State.STOPPED;
}
} catch (Exception e) {
log.error("Service stop failed.", e);
afterStopFailed();
if (!stateLock.isHeldByCurrentThread()) {
stateLock.lock();
}
state = State.FAILED;
throw new RuntimeException(e);
} finally {
if (stateLock.isHeldByCurrentThread()) {
stateLock.unlock();
}
}
}
protected void afterStopFailed() {
// nothing, hook for inheritors
}
protected boolean beginStart() throws InterruptedException {
try {
stateLock.lock();
while (state == State.STOPPING) {
stateLock.unlock();
log.info("Waiting for the service to stop");
Thread.sleep(1000);
stateLock.lock();
}
if (state == State.FAILED) {
log.info("Cannot start, previous attempt failed");
} else if (state == State.STARTING) {
log.info("Service already starting");
} else if (state == State.STARTED) {
log.info("Service already started");
} else if (state == State.STOPPED) {
state = State.STARTING;
startingThread = Thread.currentThread();
return true;
}
return false;
} finally {
if (stateLock.isHeldByCurrentThread()) {
stateLock.unlock();
}
}
}
protected boolean beginStop(boolean interrupt) throws InterruptedException {
try {
stateLock.lock();
if (interrupt && startingThread != null) {
log.info("Interrupting the starting thread");
startingThread.interrupt();
}
while (state == State.STARTING) {
stateLock.unlock();
log.info("Waiting for the service to start");
Thread.sleep(1000);
stateLock.lock();
}
if (state == State.FAILED) {
log.info("Cannot stop, previous attempt failed.");
} else if (state == State.STOPPING) {
log.warn("Service already stopping");
} else if (state == State.STOPPED) {
log.warn("Service already stopped");
} else if (state == State.STARTED) {
state = State.STOPPING;
return true;
}
return false;
} finally {
if (stateLock.isHeldByCurrentThread()) {
stateLock.unlock();
}
}
}
public boolean isRunning() {
try {
stateLock.lock();
return state == State.STARTED;
} finally {
if (stateLock.isHeldByCurrentThread()) {
stateLock.unlock();
}
}
}
}