package org.multiverse.stms.gamma.integration.commute;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.TestThread;
import org.multiverse.api.Txn;
import org.multiverse.api.TxnExecutor;
import org.multiverse.api.callables.TxnLongCallable;
import org.multiverse.api.functions.Functions;
import org.multiverse.stms.gamma.GammaStm;
import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong;
import org.multiverse.stms.gamma.transactions.GammaTxn;
import static org.junit.Assert.assertEquals;
import static org.multiverse.TestUtils.*;
import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance;
import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn;
public abstract class Commute_AbstractTest {
protected GammaStm stm;
private volatile boolean stop;
private GammaTxnLong[] refs;
private int refCount = 10;
private int workerCount = 2;
@Before
public void setUp() {
clearThreadLocalTxn();
stm = (GammaStm) getGlobalStmInstance();
stop = false;
}
protected abstract TxnExecutor newBlock();
@Test
public void test() {
refs = new GammaTxnLong[refCount];
for (int k = 0; k < refCount; k++) {
refs[k] = new GammaTxnLong(stm);
}
WorkerThread[] workers = new WorkerThread[workerCount];
for (int k = 0; k < workers.length; k++) {
workers[k] = new WorkerThread(k);
}
startAll(workers);
sleepMs(getStressTestDurationMs(30 * 1000));
stop = true;
joinAll(workers);
assertEquals(count(workers), count(refs));
}
public long count(GammaTxnLong[] refs) {
long result = 0;
for (GammaTxnLong ref : refs) {
result += ref.atomicGet();
}
return result;
}
public long count(WorkerThread[] threads) {
long result = 0;
for (WorkerThread thread : threads) {
result += thread.count;
}
return result;
}
public class WorkerThread extends TestThread {
private long count;
public WorkerThread(int id) {
super("CommuteThread-" + id);
}
@Override
public void doRun() throws Exception {
TxnExecutor executor = newBlock();
TxnLongCallable commutingCallable = new TxnLongCallable() {
@Override
public long call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
for (int k = 0; k < refs.length; k++) {
refs[k].commute(btx, Functions.incLongFunction(1));
}
return refs.length;
}
};
TxnLongCallable nonCommutingCallable = new TxnLongCallable() {
@Override
public long call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
for (int k = 0; k < refs.length; k++) {
refs[k].openForWrite(btx, LOCKMODE_NONE).long_value++;
}
return refs.length;
}
};
int k = 0;
while (!stop) {
TxnLongCallable callable = randomOneOf(10) ? nonCommutingCallable : commutingCallable;
count += executor.execute(callable);
k++;
if (k % 100000 == 0) {
System.out.printf("%s is at %s\n", getName(), k);
}
}
System.out.printf("%s completed %s\n", getName(), k);
}
}
}