package org.radargun.stages.topology;
import java.util.List;
import org.radargun.DistStageAck;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.AbstractDistStage;
import org.radargun.traits.InjectTrait;
import org.radargun.traits.TopologyHistory;
import org.radargun.utils.TimeConverter;
import org.radargun.utils.TimeService;
import static org.radargun.traits.TopologyHistory.Event.EventType;
import static org.radargun.traits.TopologyHistory.HistoryType;
/**
* @author Radim Vansa <rvansa@redhat.com>
*/
@Stage(doc = "Waits until some event occurs. Note that the initial rehash is not recorded in this manner, " +
"therefore waiting for that will result in timeout.")
public class WaitForTopologyEventStage extends AbstractDistStage {
@Property(doc = "Name of the cache where we detect the events. Default is the default cache.")
public String cacheName;
@Property(doc = "Wait for the event to happen. Default is true.")
public boolean wait = true;
@Property(doc = "Set last state before finishing. Default is true.")
public boolean set = true;
@Property(doc = "Type of event we are detecting. Default is REHASH (see org.radargun.traits.TopologyHistory.HistoryType).")
public TopologyHistory.HistoryType type = HistoryType.REHASH;
@Property(doc = "Condition we are waiting for. Default is END (see org.radargun.traits.TopologyHistory.Event.EventType).")
public EventType condition = EventType.END;
@Property(doc = "How long should we wait until we give up with error, 0 means indefinitely. Default is 10 minutes.", converter = TimeConverter.class)
public long timeout = 600000;
@Property(doc = "The minimum number of slaves that participated in this event. Default is 0.")
public int minMembers = 0;
@Property(doc = "The maximum number of slaves that participated in this event. Default is indefinite.")
public int maxMembers = Integer.MAX_VALUE;
@InjectTrait(dependency = InjectTrait.Dependency.MANDATORY)
private TopologyHistory topologyHistory;
@Override
public DistStageAck executeOnSlave() {
if (!isServiceRunning()) {
return successfulResponse();
}
List<TopologyHistory.Event> history = getEventHistory(topologyHistory);
if (wait) {
TopologyHistory.Event setEvent = (TopologyHistory.Event) slaveState.get(String.valueOf(type));
long startWaiting = TimeService.currentTimeMillis();
wait_loop:
while (timeout <= 0 || TimeService.currentTimeMillis() < startWaiting + timeout) {
log.trace("setEvent=" + setEvent + ", history=" + history);
if (history.size() > 0) {
if (condition == EventType.END) {
for (int i = history.size() - 1; i >= 0; --i) {
TopologyHistory.Event e = history.get(i);
if (setEvent != null && setEvent.getType() == EventType.END && !e.getTime().after(setEvent.getTime()))
break;
if (e.getType() == EventType.END && e.getMembersAtEnd() >= minMembers && e.getMembersAtEnd() <= maxMembers) {
break wait_loop;
}
}
} else if (condition == EventType.START) {
for (int i = history.size() - 1; i >= 0; --i) {
TopologyHistory.Event e = history.get(i);
if (setEvent != null && setEvent.getType() == EventType.START && !e.getTime().after(setEvent.getTime()))
break;
if (e.getType() == EventType.START && e.getMembersAtEnd() >= minMembers && e.getMembersAtEnd() <= maxMembers) {
break wait_loop;
}
}
} else if (condition == EventType.SINGLE) {
for (int i = history.size() - 1; i >= 0; --i) {
TopologyHistory.Event e = history.get(i);
if (setEvent != null && setEvent.getType() == EventType.SINGLE && !e.getTime().after(setEvent.getTime()))
break;
if (e.getType() == EventType.SINGLE && e.getMembersAtEnd() >= minMembers && e.getMembersAtEnd() <= maxMembers) {
break wait_loop;
}
}
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return errorResponse("Waiting was interrupted", e);
}
history = getEventHistory(topologyHistory);
}
/* end of wait_loop */
if (timeout > 0 && TimeService.currentTimeMillis() > startWaiting + timeout) {
return errorResponse("Waiting has timed out");
}
}
if (set) {
slaveState.put(String.valueOf(type), history.isEmpty() ? null : history.get(history.size() - 1));
}
return successfulResponse();
}
private List<TopologyHistory.Event> getEventHistory(TopologyHistory wrapper) {
switch (type) {
case TOPOLOGY:
return wrapper.getTopologyChangeHistory(cacheName);
case REHASH:
return wrapper.getRehashHistory(cacheName);
case CACHE_STATUS:
return wrapper.getCacheStatusChangeHistory(cacheName);
}
throw new IllegalStateException("Unexpected event type " + type);
}
}