package org.radargun.stages.lifecycle; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.radargun.DistStageAck; import org.radargun.config.Property; import org.radargun.config.Stage; import org.radargun.stages.helpers.RoleHelper; import org.radargun.utils.TimeConverter; /** * The stage start and kills some nodes concurrently (without waiting for each other). * * @author Radim Vansa <rvansa@redhat.com> */ @Stage(doc = "The stage start and stops some nodes concurrently (without waiting for each other).") public class ParallelStartStopStage extends AbstractServiceStartStage { @Property(doc = "Set of slaves which should be stopped in this stage. Default is empty.") public Collection<Integer> stop = new ArrayList<Integer>(); @Property(converter = TimeConverter.class, doc = "Delay before the slaves are stopped. Default is 0.") public long stopDelay = 0; @Property(doc = "If set to false, the node crash should be simulated. By default node should be shutdown gracefully.") public boolean graceful = true; @Property(doc = "Set of slaves which should be started in this stage. Default is empty.") public Collection<Integer> start = new ArrayList<Integer>(); @Property(doc = "Set of roles which should be stopped in this stage. Default is empty.") public Set<RoleHelper.Role> stopRoles = new HashSet<>(); @Property(converter = TimeConverter.class, doc = "Delay before the slaves are started. Default is 0.") public long startDelay = 0; @Property(doc = "Applicable only for cache wrappers with Partitionable feature. Set of slaves that should be " + "reachable from the new node. Default is all slaves.") public Set<Integer> reachable = null; @Override public DistStageAck executeOnSlave() { if (lifecycle == null) { log.warn("No lifecycle for service " + slaveState.getServiceName()); return successfulResponse(); } boolean stopMe = stop.contains(slaveState.getSlaveIndex()) || RoleHelper.hasAnyRole(slaveState, stopRoles); boolean startMe = start.contains(slaveState.getSlaveIndex()); if (!(stopMe || startMe)) { log.info("Nothing to kill or start..."); } while (stopMe || startMe) { if (startMe) { if (lifecycle.isRunning()) { if (!stopMe) { log.info("Wrapper already set on this slave, not starting it again."); startMe = false; return successfulResponse(); } } else { if (startDelay > 0) { try { Thread.sleep(startDelay); } catch (InterruptedException e) { log.error("Starting delay was interrupted.", e); } } try { LifecycleHelper.start(slaveState, false, null, 0, reachable); } catch (RuntimeException e) { return errorResponse("Issues while instantiating/starting cache wrapper", e); } startMe = false; } } if (stopMe) { if (!lifecycle.isRunning()) { if (!startMe) { log.info("Wrapper is dead, nothing to kill"); stopMe = false; return successfulResponse(); } } else { try { Thread.sleep(stopDelay); } catch (InterruptedException e) { log.error("Killing delay was interrupted.", e); } try { LifecycleHelper.stop(slaveState, graceful, false); } catch (RuntimeException e) { return errorResponse("Failed to kill the service", e); } stopMe = false; } } } return successfulResponse(); } }