package org.radargun.stages.cache;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.radargun.DistStageAck;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.AbstractDistStage;
import org.radargun.traits.BasicOperations;
import org.radargun.traits.CacheInformation;
import org.radargun.traits.InjectTrait;
/**
* Paired with SingleTXLoadStage. Checks that the previous stage had the expected result.
*/
@Stage(doc = "Paired with SingleTXLoadStage. Checks that the previous stage had the expected result")
public class SingleTXCheckStage extends AbstractDistStage {
private static final Pattern TX_VALUE = Pattern.compile("txValue(\\d*)@(\\d*-\\d*)");
@Property(doc = "Indices of slaves which should have committed the transaction (others rolled back). Default is all committed.")
public Set<Integer> commitSlave;
@Property(doc = "Indices of threads which should have committed the transaction (others rolled back). Default is all committed.")
public Set<Integer> commitThread;
@Property(doc = "Expected size of the transcation.")
public int transactionSize = 20;
@Property(doc = "If this is set to true, REMOVE operation should have been executed. Default is false.")
public boolean deleted = false;
@InjectTrait(dependency = InjectTrait.Dependency.MANDATORY)
private BasicOperations basicOperations;
@InjectTrait
private CacheInformation cacheInformation;
@Override
public DistStageAck executeOnSlave() {
if (!shouldExecute()) {
return successfulResponse();
}
List<String> caches = new ArrayList<String>();
if (cacheInformation == null) {
caches.add(null);
} else {
caches.addAll(cacheInformation.getCacheNames());
}
for (String cacheName : caches) {
if (cacheName != null) {
log.info("Checking cache " + cacheName);
}
BasicOperations.Cache cache = basicOperations.getCache(cacheName);
String committer = null;
for (int i = 0; i < transactionSize; ++i) {
try {
Object value = cache.get("txKey" + i);
if (!deleted) {
Matcher m;
if (value != null && value instanceof String && (m = TX_VALUE.matcher((String) value)).matches()) {
if (Integer.parseInt(m.group(1)) != i) {
return errorResponse("Unexpected value for txKey" + i + " = " + value);
}
if (committer == null) {
committer = m.group(2);
if (commitSlave != null) {
boolean found = false;
for (int slave : commitSlave) {
if (committer.startsWith(String.valueOf(slave))) {
found = true;
break;
}
}
if (!found) {
return errorResponse("The transaction should be committed by slave " + commitSlave + " but commiter is " + committer);
}
}
if (commitThread != null) {
boolean found = false;
for (int slave : commitThread) {
if (committer.endsWith(String.valueOf(slave))) {
found = true;
break;
}
}
if (!found) {
return errorResponse("The transaction should be committed by thread " + commitThread + " but commiter is " + committer);
}
}
} else if (!committer.equals(m.group(2))) {
return errorResponse("Inconsistency: previous committer was " + committer + ", this is " + m.group(2));
}
} else {
return errorResponse("Unexpected value for txKey" + i + " = " + value);
}
} else {
if (value != null) {
return errorResponse("The value for txKey" + i + " should have been deleted, is " + value);
}
}
} catch (Exception e) {
return errorResponse("Failed to get key txKey" + i, e);
}
}
}
return successfulResponse();
}
}