package org.radargun.stages.cache.test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import org.radargun.Operation;
import org.radargun.config.Namespace;
import org.radargun.config.Property;
import org.radargun.config.Stage;
import org.radargun.stages.test.Invocation;
import org.radargun.stages.test.OperationLogic;
import org.radargun.stages.test.OperationSelector;
import org.radargun.stages.test.RatioOperationSelector;
import org.radargun.stages.test.Stressor;
import org.radargun.stages.test.TestStage;
import org.radargun.traits.BasicOperations;
import org.radargun.traits.InjectTrait;
import org.radargun.traits.TemporalOperations;
/**
* @author Martin Gencur <mgencur@redhat.com>
*
* This stage allows for testing operations that have lifespan or maxIdle attributes set.
*
*/
@Namespace(name = TestStage.NAMESPACE, deprecatedName = TestStage.DEPRECATED_NAMESPACE)
@Stage(doc = "Test using TemporalOperations")
public class TemporalOperationsTestStage extends CacheOperationsTestStage {
@Property(doc = "Lifespan to be used for all temporal operations. Default is 1000 ms.")
protected int lifespan = 1000;
@Property(doc = "MaxIdle time to be used for all temporal operations. Default is -1 (no MaxIdle time set)")
protected int maxIdle = -1;
@Property(doc = "Ratio of GET requests. Default is 4.")
protected int getRatio = 4;
@Property(doc = "Ratio of PUT_WITH_LIFESPAN requests. Default is 1.")
protected int putWithLifespanRatio = 1;
@Property(doc = "Ratio of PUT_WITH_LIFESPAN_AND_MAXIDLE requests. Default is 0.")
protected int putWithLifespanAndMaxIdleRatio = 0;
@Property(doc = "Ratio of GET_AND_PUT_WITH_LIFESPAN requests. Default is 0.")
protected int getAndPutWithLifespanRatio = 0;
@Property(doc = "Ratio of GET_AND_PUT_WITH_LIFESPAN_AND_MAXIDLE requests. Default is 0.")
protected int getAndPutWithLifespanAndMaxIdleRatio = 0;
@Property(doc = "Ratio of PUT_IF_ABSENT_WITH_LIFESPAN requests. Default is 0.")
protected int putIfAbsentWithLifespanRatio = 0;
@Property(doc = "Ratio of PUT_IF_ABSENT_WITH_LIFESPAN_AND_MAXIDLE requests. Default is 0.")
protected int putIfAbsentWithLifespanAndMaxIdleRatio = 0;
@InjectTrait(dependency = InjectTrait.Dependency.MANDATORY)
protected BasicOperations basicOperations;
@InjectTrait(dependency = InjectTrait.Dependency.MANDATORY)
protected TemporalOperations temporalOperations;
@Override
protected OperationSelector createOperationSelector() {
statisticsPrototype.registerOperationsGroup(TemporalOperations.class.getSimpleName() + ".Total",
new HashSet<>(Arrays.asList(
BasicOperations.GET,
TemporalOperations.PUT_WITH_LIFESPAN,
TemporalOperations.GET_AND_PUT_WITH_LIFESPAN,
TemporalOperations.PUT_WITH_LIFESPAN_AND_MAXIDLE,
TemporalOperations.GET_AND_PUT_WITH_LIFESPAN_AND_MAXIDLE,
TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN,
TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN_AND_MAXIDLE)));
return new RatioOperationSelector.Builder()
.add(BasicOperations.GET, getRatio)
.add(TemporalOperations.PUT_WITH_LIFESPAN, putWithLifespanRatio)
.add(TemporalOperations.GET_AND_PUT_WITH_LIFESPAN, getAndPutWithLifespanRatio)
.add(TemporalOperations.PUT_WITH_LIFESPAN_AND_MAXIDLE, putWithLifespanAndMaxIdleRatio)
.add(TemporalOperations.GET_AND_PUT_WITH_LIFESPAN_AND_MAXIDLE, getAndPutWithLifespanAndMaxIdleRatio)
.add(TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN, putIfAbsentWithLifespanRatio)
.add(TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN_AND_MAXIDLE, putIfAbsentWithLifespanAndMaxIdleRatio)
.build();
}
@Override
public OperationLogic getLogic() {
return new Logic();
}
protected class Logic extends OperationLogic {
protected TemporalOperations.Cache nonTxTemporalCache, temporalCache;
protected BasicOperations.Cache nonTxBasicCache, basicCache;
protected KeySelector keySelector;
@Override
public void init(Stressor stressor) {
super.init(stressor);
String cacheName = cacheSelector.getCacheName(stressor.getGlobalThreadIndex());
this.nonTxTemporalCache = temporalOperations.getCache(cacheName);
this.nonTxBasicCache = basicOperations.getCache(cacheName);
if (useTransactions(cacheName)) {
temporalCache = new Delegates.TemporalOperationsCache();
basicCache = new Delegates.BasicOperationsCache();
} else {
temporalCache = nonTxTemporalCache;
basicCache = nonTxBasicCache;
}
stressor.setUseTransactions(useTransactions(cacheName));
keySelector = getKeySelector(stressor);
}
@Override
public void transactionStarted() {
((Delegates.BasicOperationsCache) basicCache).setDelegate(stressor.wrap(nonTxBasicCache));
((Delegates.TemporalOperationsCache) temporalCache).setDelegate(stressor.wrap(nonTxTemporalCache));
}
@Override
public void transactionEnded() {
((Delegates.BasicOperationsCache) basicCache).setDelegate(null);
((Delegates.TemporalOperationsCache) temporalCache).setDelegate(null);
}
@Override
public void run(Operation operation) throws RequestException {
Object key = keyGenerator.generateKey(keySelector.next());
Random random = stressor.getRandom();
Invocation invocation;
if (operation == BasicOperations.GET) {
invocation = new CacheInvocations.Get(basicCache, key);
} else if (operation == TemporalOperations.PUT_WITH_LIFESPAN) {
invocation = new CacheInvocations.PutWithLifespan(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan);
} else if (operation == TemporalOperations.PUT_WITH_LIFESPAN_AND_MAXIDLE) {
invocation = new CacheInvocations.PutWithLifespanAndMaxIdle(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan, maxIdle);
} else if (operation == TemporalOperations.GET_AND_PUT_WITH_LIFESPAN) {
invocation = new CacheInvocations.GetAndPutWithLifespan(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan);
} else if (operation == TemporalOperations.GET_AND_PUT_WITH_LIFESPAN_AND_MAXIDLE) {
invocation = new CacheInvocations.GetAndPutWithLifespanAndMaxIdle(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan, maxIdle);
} else if (operation == TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN) {
invocation = new CacheInvocations.PutIfAbsentWithLifespan(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan);
} else if (operation == TemporalOperations.PUT_IF_ABSENT_WITH_LIFESPAN_AND_MAXIDLE) {
invocation = new CacheInvocations.PutIfAbsentWithLifespanAndMaxIdle(temporalCache, key, valueGenerator.generateValue(key, entrySize.next(random), random), lifespan, maxIdle);
} else throw new IllegalArgumentException(operation.name);
stressor.makeRequest(invocation);
}
}
}