package org.multiverse.commitbarriers;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.multiverse.TestThread;
import org.multiverse.api.Txn;
import org.multiverse.api.TxnFactory;
import org.multiverse.api.callables.TxnVoidCallable;
import org.multiverse.api.exceptions.DeadTxnException;
import org.multiverse.api.exceptions.TooManyRetriesException;
import org.multiverse.stms.gamma.GammaStm;
import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger;
import static org.junit.Assert.*;
import static org.multiverse.TestUtils.*;
import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn;
public class VetoCommitBarrier_joinCommitTest {
private GammaStm stm;
private TxnFactory txFactory;
@Before
public void setUp() {
stm = new GammaStm();
txFactory = stm.newTxnFactoryBuilder()
.setSpeculative(false)
.newTransactionFactory();
clearThreadLocalTxn();
clearCurrentThreadInterruptedStatus();
}
@After
public void tearDown() {
clearCurrentThreadInterruptedStatus();
}
@Test
public void whenTransactionNull_thenNullPointerException() throws InterruptedException {
VetoCommitBarrier barrier = new VetoCommitBarrier();
try {
barrier.joinCommit(null);
fail();
} catch (NullPointerException expected) {
}
assertTrue(barrier.isClosed());
assertEquals(0, barrier.getNumberWaiting());
}
@Test
@Ignore
public void whenTransactionPreparable_thenAdded() {
VetoCommitBarrier barrier = new VetoCommitBarrier();
GammaTxnInteger ref = new GammaTxnInteger(stm);
IncThread thread = new IncThread(ref, barrier);
thread.start();
sleepMs(1000);
assertAlive(thread);
assertTrue(barrier.isClosed());
assertEquals(1, barrier.getNumberWaiting());
}
@Test
@Ignore
public void whenTransactionPrepared_thenAdded() {
VetoCommitBarrier barrier = new VetoCommitBarrier();
GammaTxnInteger ref = new GammaTxnInteger(stm);
IncThread thread = new IncThread(ref, barrier, true);
thread.start();
sleepMs(1000);
assertAlive(thread);
assertTrue(barrier.isClosed());
assertEquals(1, barrier.getNumberWaiting());
}
@Test
@Ignore
public void whenPrepareFails() throws InterruptedException {
final VetoCommitBarrier group = new VetoCommitBarrier();
final GammaTxnInteger ref = new GammaTxnInteger(stm);
FailToPrepareThread thread = new FailToPrepareThread(group, ref);
thread.start();
sleepMs(1000);
stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.incrementAndGet(tx, 1);
}
});
thread.join();
thread.assertFailedWithException(TooManyRetriesException.class);
assertEquals(0, group.getNumberWaiting());
}
class FailToPrepareThread extends TestThread {
final VetoCommitBarrier group;
final GammaTxnInteger ref;
FailToPrepareThread(VetoCommitBarrier group, GammaTxnInteger ref) {
super("FailedToPrepareThread");
this.group = group;
this.ref = ref;
setPrintStackTrace(false);
}
@Override
public void doRun() throws Exception {
stm.newTxnFactoryBuilder()
.setSpeculative(false)
.setMaxRetries(0)
.newTxnExecutor()
.execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
//we need to load it to cause a conflict
ref.get(tx);
sleepMs(2000);
ref.incrementAndGet(tx, 1);
group.joinCommit(tx);
}
});
}
}
@Test
public void whenTransactionAborted_thenDeadTxnException() throws InterruptedException {
Txn tx = txFactory.newTxn();
tx.abort();
VetoCommitBarrier group = new VetoCommitBarrier();
try {
group.joinCommit(tx);
fail();
} catch (DeadTxnException expected) {
}
assertTrue(group.isClosed());
assertIsAborted(tx);
assertEquals(0, group.getNumberWaiting());
}
@Test
public void whenTransactionCommitted_thenDeadTxnException() throws InterruptedException {
Txn tx = txFactory.newTxn();
tx.commit();
VetoCommitBarrier group = new VetoCommitBarrier();
try {
group.joinCommit(tx);
fail();
} catch (DeadTxnException expected) {
}
assertTrue(group.isClosed());
assertIsCommitted(tx);
assertEquals(0, group.getNumberWaiting());
}
@Test
public void whenBarrierAborted_thenCommitBarrierOpenException() throws InterruptedException {
VetoCommitBarrier barrier = new VetoCommitBarrier();
barrier.abort();
Txn tx = txFactory.newTxn();
try {
barrier.joinCommit(tx);
fail();
} catch (CommitBarrierOpenException expected) {
}
assertIsActive(tx);
assertTrue(barrier.isAborted());
assertEquals(0, barrier.getNumberWaiting());
}
@Test
public void whenCommitted_thenCommitBarrierOpenException() throws InterruptedException {
VetoCommitBarrier barrier = new VetoCommitBarrier();
barrier.atomicVetoCommit();
System.out.println("barrier.state: " + barrier);
Txn tx = txFactory.newTxn();
try {
barrier.joinCommit(tx);
fail();
} catch (CommitBarrierOpenException expected) {
}
assertIsActive(tx);
assertTrue(barrier.isCommitted());
assertEquals(0, barrier.getNumberWaiting());
}
public class IncThread extends TestThread {
private final GammaTxnInteger ref;
private final VetoCommitBarrier barrier;
private boolean prepare;
public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier) {
this(ref, barrier, false);
}
public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier, boolean prepare) {
super("IncThread");
this.barrier = barrier;
this.ref = ref;
this.prepare = prepare;
}
@Override
public void doRun() throws Exception {
stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.incrementAndGet(tx, 1);
if (prepare) {
tx.prepare();
}
barrier.joinCommit(tx);
}
});
}
}
}