package voldemort.store.slop;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import org.apache.log4j.Logger;
import voldemort.VoldemortTestConstants;
import voldemort.client.ClientConfig;
import voldemort.client.SocketStoreClientFactory;
import voldemort.client.protocol.admin.StreamingClient;
import voldemort.client.protocol.admin.StreamingClientConfig;
import voldemort.store.Store;
import voldemort.store.memory.InMemoryPutAssertionStorageEngine;
import voldemort.utils.ByteArray;
import voldemort.utils.Props;
public class SlopStreamingTestEnvironment extends HintedHandoffTestEnvironment {
private final Logger logger = Logger.getLogger(SlopStreamingTestEnvironment.class);
String bootstrapUrl;
int numFailedNodes;
boolean throwIntermittentException = false;
protected final CountDownLatch waitForFaultyNodeLatch = new CountDownLatch(1);
public SlopStreamingTestEnvironment(int numFailedNodes, boolean throwIntermittentException) {
super();
this.numFailedNodes = numFailedNodes;
this.throwIntermittentException = throwIntermittentException;
}
public StreamingClient makeSlopStreamingClient() throws InterruptedException {
return makeSlopStreamingClient(false);
}
public StreamingClient makeSlopStreamingClient(boolean wrapException)
throws InterruptedException {
startFinishLatch.await();
if(throwIntermittentException)
waitForFaultyNodeLatch.await();
Props property = new Props();
property.put("streaming.platform.bootstrapURL", bootstrapUrl);
property.put("streaming.platform.max.failed.nodes", numFailedNodes);
StreamingClientConfig config = new StreamingClientConfig(property);
StreamingClient streamer = new StreamingClient(config);
Callable<Integer> cpCallable = new CheckpointCallable();
Callable<Integer> rbCallable = new RollbackCallable();
List<String> stores = new ArrayList();
stores.add(STORE_NAME);
List<Integer> failedNodes = new ArrayList<Integer>();
for(int i = 0; i < numFailedNodes; i++)
failedNodes.add(i + 1);
if(!wrapException) {
streamer.initStreamingSessions(stores, cpCallable, rbCallable, true, failedNodes);
}
else {
try {
streamer.initStreamingSessions(stores, cpCallable, rbCallable, true, failedNodes);
} catch(Exception e) {
logger.error(e);
}
}
return streamer;
}
@Override
public void run() {
Random random = new Random(System.currentTimeMillis());
cluster = VoldemortTestConstants.getEightNodeClusterWithZones();
bootstrapUrl = cluster.getNodeById(0).getSocketUrl().toString();
storeDef = storeDefBuilder.build();
// setup store engines
for(Integer nodeId = 0; nodeId < NUM_NODES_TOTAL; nodeId++) {
createInnerStore(nodeId); // do only once
}
for(Integer nodeId = 0; nodeId < NUM_NODES_TOTAL; nodeId++) {
try {
startServer(nodeId);
} catch(IOException e) {
logger.error("Server " + nodeId + "failed to start", e);
}
}
factory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(bootstrapUrl));
// wait for start of servers
startFinishLatch.countDown();
try {
Set<Integer> nodesToFail = new HashSet<Integer>();
nodesToFail.add(1);
boolean wrapUpSignal = false;
if(logger.isInfoEnabled()) {
if(wrapUpSignal) {
logger.info("Wake Up and wrap up. Make all servers NORMAL");
} else {
logger.info("Wake Up and decide new failure statuses");
}
for(Map.Entry<Integer, Store<ByteArray, byte[], byte[]>> entry: realStores.entrySet()) {
InMemoryPutAssertionStorageEngine<ByteArray, byte[], byte[]> engine = (InMemoryPutAssertionStorageEngine<ByteArray, byte[], byte[]>) entry.getValue();
logger.info("Outstanding Put Assertions of node [" + entry.getKey() + "]: "
+ engine.getFailedAssertions().size());
}
}
if(logger.isInfoEnabled()) {
logger.info("Setting nodes to Fail: " + nodesToFail.toString());
}
for(Integer nodeId = 0; nodeId < NUM_NODES_TOTAL; nodeId++) {
makeNodeNormal(nodeId);
}
for(Integer nodeId = 0; nodeId < NUM_NODES_TOTAL; nodeId++) {
if(nodesToFail.contains(nodeId)) {
// fail a node if it's normal
if(nodesStatus.get(nodeId) == NodeStatus.NORMAL) {
makeNodeDown(nodeId);
}
} else {
// make node normal if not normal
if(nodesStatus.get(nodeId) != NodeStatus.NORMAL) {
makeNodeNormal(nodeId);
}
}
}
if(throwIntermittentException)
waitForFaultyNodeLatch.countDown();
if(!throwIntermittentException) {
for(Integer nodeId = 0; nodeId < NUM_NODES_TOTAL; nodeId++) {
makeNodeNormal(nodeId);
}
}
} catch(Exception e) {} finally {
wrapUpFinishLatch.countDown();
}
}
class CheckpointCallable implements Callable {
public Integer call() {
logger.debug("checkpoint!");
return 1;
}
}
class RollbackCallable implements Callable {
public Integer call() {
logger.debug("rollback!");
return 1;
}
}
}