package org.multiverse.stms.gamma.integration.blocking; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.LeanGammaTxnExecutor; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import org.multiverse.stms.gamma.transactions.fat.FatFixedLengthGammaTxnFactory; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxnFactory; import static org.junit.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class MultipleReadsRetryStressTest implements GammaConstants { private GammaStm stm; private GammaTxnLong[] refs; private GammaTxnLong stopRef; private volatile boolean stop; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; stopRef = new GammaTxnLong(stm, 0); } @Test public void withMapTransactionAnd2Threads() throws InterruptedException { FatVariableLengthGammaTxnFactory txFactory = new FatVariableLengthGammaTxnFactory(stm); test(new LeanGammaTxnExecutor(txFactory), 10, 2); } @Test public void withArrayTransactionAnd2Threads() throws InterruptedException { int refCount = 10; GammaTxnConfig config = new GammaTxnConfig(stm, refCount + 1); FatFixedLengthGammaTxnFactory txFactory = new FatFixedLengthGammaTxnFactory(config); test(new LeanGammaTxnExecutor(txFactory), refCount, 2); } @Test public void withMapTransactionAnd5Threads() throws InterruptedException { FatVariableLengthGammaTxnFactory txFactory = new FatVariableLengthGammaTxnFactory(stm); test(new LeanGammaTxnExecutor(txFactory), 10, 5); } @Test public void withArrayTransactionAnd5Threads() throws InterruptedException { int refCount = 10; GammaTxnConfig config = new GammaTxnConfig(stm, refCount + 1); FatFixedLengthGammaTxnFactory txFactory = new FatFixedLengthGammaTxnFactory(config); test(new LeanGammaTxnExecutor(txFactory), refCount, 5); } public void test(TxnExecutor txnExecutor, int refCount, int threadCount) throws InterruptedException { refs = new GammaTxnLong[refCount]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnLong(stm); } UpdateThread[] threads = new UpdateThread[threadCount]; for (int k = 0; k < threads.length; k++) { threads[k] = new UpdateThread(k, txnExecutor, threadCount); } startAll(threads); sleepMs(30 * 1000); stop = true; stopRef.atomicSet(-1); System.out.println("Waiting for joining threads"); joinAll(threads); assertEquals(sumCount(threads), sumRefs()); } private long sumRefs() { long result = 0; for (GammaTxnLong ref : refs) { result += ref.atomicGet(); } return result; } private long sumCount(UpdateThread[] threads) { long result = 0; for (UpdateThread thread : threads) { result += thread.count; } return result; } private class UpdateThread extends TestThread { private final TxnExecutor txnExecutor; private final int id; private final int threadCount; private long count; public UpdateThread(int id, TxnExecutor txnExecutor, int threadCount) { super("UpdateThread-" + id); this.txnExecutor = txnExecutor; this.id = id; this.threadCount = threadCount; } @Override public void doRun() { TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) { if (stopRef.get() < 0) { throw new StopException(); } long sum = 0; for (GammaTxnLong ref : refs) { sum += ref.get(); } if (sum % threadCount != id) { retry(); } GammaTxnLong ref = refs[TestUtils.randomInt(refs.length)]; ref.incrementAndGet(1); } }; while (!stop) { if (count % (10000) == 0) { System.out.println(getName() + " " + count); } try { txnExecutor.execute(callable); } catch (StopException e) { break; } count++; } } } class StopException extends RuntimeException { } }