package org.multiverse.stms.gamma.integration.isolation; import org.junit.Before; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.TestUtils; import org.multiverse.api.TxnExecutor; import org.multiverse.api.Txn; import org.multiverse.api.callables.TxnVoidCallable; 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 class ReadonlyRepeatableReadStressTest { private volatile boolean stop; private GammaTxnLong ref; private int readThreadCount = 5; private int modifyThreadCount = 2; private GammaStm stm; @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); ref = new GammaTxnLong(stm); stop = false; } @Test public void test() { ModifyThread[] modifyThreads = new ModifyThread[modifyThreadCount]; for (int k = 0; k < modifyThreadCount; k++) { modifyThreads[k] = new ModifyThread(k); } ReadThread[] readerThread = new ReadThread[readThreadCount]; for (int k = 0; k < readThreadCount; k++) { readerThread[k] = new ReadThread(k); } startAll(modifyThreads); startAll(readerThread); sleepMs(TestUtils.getStressTestDurationMs(30 * 1000)); stop = true; joinAll(modifyThreads); joinAll(readerThread); } class ModifyThread extends TestThread { public ModifyThread(int id) { super("ModifyThread-" + id); } @Override public void doRun() { TxnExecutor executor = stm.newTxnFactoryBuilder() .newTxnExecutor(); TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; ref.getAndSet(btx, ref.get(btx)); } }; while (!stop) { executor.execute(callable); sleepRandomMs(5); } } } class ReadThread extends TestThread { private final TxnExecutor readTrackingReadonlyBlock = stm.newTxnFactoryBuilder() .setReadonly(true) .setReadTrackingEnabled(true) .newTxnExecutor(); private final TxnExecutor readTrackingUpdateBlock = stm.newTxnFactoryBuilder() .setReadonly(false) .setReadTrackingEnabled(true) .newTxnExecutor(); private final TxnVoidCallable callable = new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; long firstTime = ref.get(btx); sleepRandomMs(2); long secondTime = ref.get(btx); assertEquals(firstTime, secondTime); } }; public ReadThread(int id) { super("ReadThread-" + id); } @Override public void doRun() { int k = 0; while (!stop) { switch (k % 2) { case 0: readTrackingReadonlyBlock.execute(callable); break; case 1: readTrackingUpdateBlock.execute(callable); break; default: throw new IllegalStateException(); } k++; } } } }