package org.multiverse.stms.gamma; import org.junit.Before; import org.junit.Test; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.LockMode; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.functions.Function; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnRef; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatMonoGammaTxn; import org.multiverse.stms.gamma.transactions.fat.FatVariableLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanFixedLengthGammaTxn; import org.multiverse.stms.gamma.transactions.lean.LeanMonoGammaTxn; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.multiverse.TestUtils.assertInstanceof; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn; public class GammaTxnExecutor_speculativeTest implements GammaConstants { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenTransactionGrowing() { final GammaTxnRef<Long>[] refs = new GammaTxnRef[1000]; for (int k = 0; k < refs.length; k++) { refs[k] = new GammaTxnRef<Long>(stm, 0L); } final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final AtomicInteger attempt = new AtomicInteger(1); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setControlFlowErrorsReused(false) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { System.out.println(tx.getClass()); assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; assertEquals(attempt.get(), tx.getAttempt()); attempt.incrementAndGet(); transactions.add(btx); for (GammaTxnRef<Long> ref : refs) { ref.set(1L); } } }); for (GammaTxnRef ref : refs) { assertEquals(1L, ref.atomicGet()); } assertEquals(4, transactions.size()); assertInstanceof(LeanMonoGammaTxn.class, transactions.get(0)); assertInstanceof(LeanFixedLengthGammaTxn.class, transactions.get(1)); assertInstanceof(FatVariableLengthGammaTxn.class, transactions.get(2)); assertInstanceof(FatVariableLengthGammaTxn.class, transactions.get(3)); } @Test public void whenCommute() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final GammaTxnRef<String> ref = new GammaTxnRef<String>(stm); final Function<String> function = mock(Function.class); TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .setSpeculative(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.commute(btx, function); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenEnsure() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final GammaTxnRef<String> ref = new GammaTxnRef<String>(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setDirtyCheckEnabled(false) .setSpeculative(true) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.get(btx); ref.ensure(btx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenConstructing() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); new GammaTxnRef(btx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenNonRef() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final GammaTxnLong ref = new GammaTxnLong(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.get(tx); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenExplicitLocking() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final GammaTxnRef ref = new GammaTxnRef(stm); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { GammaTxn btx = (GammaTxn) tx; transactions.add(btx); ref.getLock().acquire(LockMode.Read); } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenNormalListenerAdded() { final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); final AtomicBoolean added = new AtomicBoolean(); final TxnListener listener = mock(TxnListener.class); TxnExecutor executor = stm.newTxnFactoryBuilder() .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; transactions.add(btx); if (!added.get()) { btx.register(listener); } } }); assertEquals(2, transactions.size()); assertTrue(transactions.get(0) instanceof LeanMonoGammaTxn); assertTrue(transactions.get(1) instanceof FatMonoGammaTxn); } @Test public void whenTimeoutAvailable_thenCopied() { final GammaTxnLong ref1 = new GammaTxnLong(stm); final GammaTxnLong ref2 = new GammaTxnLong(stm); final List<GammaTxn> transactions = new LinkedList<GammaTxn>(); TxnExecutor executor = stm.newTxnFactoryBuilder() .setTimeoutNs(1000) .setSpeculative(true) .setDirtyCheckEnabled(false) .newTxnExecutor(); executor.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { assertSame(tx, getThreadLocalTxn()); GammaTxn btx = (GammaTxn) tx; transactions.add(btx); if (transactions.size() == 1) { btx.remainingTimeoutNs = 500; } else { assertEquals(500, btx.getRemainingTimeoutNs()); } ref1.openForWrite(btx, LOCKMODE_NONE); ref2.openForWrite(btx, LOCKMODE_NONE); } }); } }