package org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeError; import org.multiverse.SomeUncheckedException; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.AbortOnlyException; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.ReadWriteConflict; import org.multiverse.api.exceptions.RetryError; import org.multiverse.api.functions.Functions; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.*; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_commitTest<T extends GammaTxn> implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); protected abstract void assertCleaned(T transaction); @Test public void listener_whenNormalListenerAvailable() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.commit(); assertIsCommitted(tx); verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostCommit); } @Test public void listener_whenPermanentListenerAvailable() { TxnListener listener = mock(TxnListener.class); GammaTxnConfig config = new GammaTxnConfig(stm) .addPermanentListener(listener); T tx = newTransaction(config); tx.commit(); assertIsCommitted(tx); verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostCommit); } @Test public void retryListeners_whenDirtyWrite_thenListenersNotified() { retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.None); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Read); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.None, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Read); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Read, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Write, LockMode.Write); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Write, LockMode.Exclusive); retryListeners_whenDirtyWrite_thenListenersNotified(LockMode.Exclusive, LockMode.Exclusive); } public void retryListeners_whenDirtyWrite_thenListenersNotified(LockMode readLockMode, LockMode writeLockMode) { String oldValue = "oldvalue"; GammaTxnRef<String> ref = new GammaTxnRef<String>(stm, oldValue); long initialVersion = ref.getVersion(); GammaTxn waitingTx = newTransaction(); ref.get(waitingTx); try { waitingTx.retry(); fail(); } catch (RetryError expected) { } GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(readLockMode) .setWriteLockMode(writeLockMode); GammaTxn tx = newTransaction(config); String newValue = "newvalue"; ref.set(tx, newValue); tx.commit(); assertTrue(waitingTx.retryListener.isOpen()); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void conflict_whenArriveByOther() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); long newValue = 1; ref.set(tx, newValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); FatVariableLengthGammaTxn otherTx = new FatVariableLengthGammaTxn(config); ref.get(otherTx); long globalConflictCount = stm.globalConflictCounter.count(); tx.commit(); assertGlobalConflictCount(stm, globalConflictCount + 1); assertVersionAndValue(ref, initialVersion + 1, newValue); } @Test public void whenContainsConstructedIntRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedBooleanRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); boolean initialValue = true; GammaTxnBoolean ref = new GammaTxnBoolean(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedTxnDouble() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); String initialValue = "foo"; GammaTxnRef<String> ref = new GammaTxnRef<String>(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsConstructedLongRef() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(tx, initialValue); tx.commit(); assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, VERSION_UNCOMMITTED + 1, initialValue); assertSurplus(ref, 0); assertReadonlyCount(ref, 0); assertWriteBiased(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommuteThrowsRuntimeException() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); when(function.call(initialValue)).thenThrow(new SomeUncheckedException()); ref.commute(tx, function); try { tx.commit(); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommuteThrowsError() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); when(function.call(initialValue)).thenThrow(new SomeError()); ref.commute(tx, function); try { tx.commit(); fail(); } catch (SomeError expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsCommute() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); tx.commit(); assertIsCommitted(tx); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void abortOnly_whenUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.setAbortOnly(); try { tx.commit(); fail(); } catch (AbortOnlyException expected) { } assertIsAborted(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void abortOnly_whenDirty() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.setAbortOnly(); try { ref.set(tx, initialValue + 1); tx.commit(); fail(); } catch (AbortOnlyException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenBooleanRef() { long globalConflictCount = stm.globalConflictCounter.count(); boolean initialValue = false; GammaTxnBoolean ref = new GammaTxnBoolean(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, true); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, true); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenIntRef() { long globalConflictCount = stm.globalConflictCounter.count(); int initialValue = 10; GammaTxnInteger ref = new GammaTxnInteger(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenLongRef() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenTxnDouble() { long globalConflictCount = stm.globalConflictCounter.count(); double initialValue = 10; GammaTxnDouble ref = new GammaTxnDouble(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.set(tx, initialValue + 1); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenRef() { long globalConflictCount = stm.globalConflictCounter.count(); String initialValue = "foo"; GammaTxnRef<String> ref = new GammaTxnRef<String>(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); String newValue = "bar"; ref.set(tx, newValue); tx.commit(); assertVersionAndValue(ref, initialVersion + 1, "bar"); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenContainsListener() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn listeningTx = newTransaction(); ref.openForRead(listeningTx, LOCKMODE_NONE); try { listeningTx.retry(); fail(); } catch (RetryError retry) { } GammaTxn tx = newTransaction(); ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); assertTrue(listeningTx.retryListener.isOpen()); assertNull(getField(ref, "listeners")); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 1, initialValue + 1); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenUnused() { long globalConflictCount = stm.globalConflictCounter.count(); GammaTxn tx = newTransaction(); tx.commit(); assertEquals(TxnStatus.Committed, tx.getStatus()); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenConflict() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; //a conflicting write. T otherTx = newTransaction(); ref.openForWrite(otherTx, LOCKMODE_NONE).long_value++; otherTx.commit(); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } //todo: dirty checking //todo: lock releasing @Test public void whenContainsDirtyWrite() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleCommitsUsingNewTransaction() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int txCount = 10; for (int k = 0; k < txCount; k++) { T tx = newTransaction(); ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); } assertEquals(initialValue + txCount, ref.long_value); assertEquals(initialVersion + txCount, ref.version); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenMultipleCommitsUsingSame() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); int txCount = 10; T tx = newTransaction(); for (int k = 0; k < txCount; k++) { ref.openForWrite(tx, LOCKMODE_NONE).long_value++; tx.commit(); tx.hardReset(); } assertEquals(initialValue + txCount, ref.long_value); assertEquals(initialVersion + txCount, ref.version); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenPreparedAndContainsRead() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); tx.prepare(); tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenPreparedAndContainsWrite() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; tx.prepare(); tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ dirty check ================================ @Test public void whenContainsRead() { whenContainsRead(true, LockMode.None); whenContainsRead(true, LockMode.Read); whenContainsRead(true, LockMode.Write); whenContainsRead(true, LockMode.Exclusive); whenContainsRead(false, LockMode.None); whenContainsRead(false, LockMode.Read); whenContainsRead(false, LockMode.Write); whenContainsRead(false, LockMode.Exclusive); } public void whenContainsRead(boolean prepareFirst, LockMode readLockMode) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); if (prepareFirst) { tx.prepare(); } tx.commit(); assertIsCommitted(tx); assertLockMode(ref, LockMode.None); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertVersionAndValue(ref, initialVersion, initialValue); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } // ================================ dirty check ================================ @Test public void dirty_whenNoDirtyCheckAndNoDirtyWrite() { dirty_whenNoDirtyCheckAndNoDirtyWrite(true); dirty_whenNoDirtyCheckAndNoDirtyWrite(false); } public void dirty_whenNoDirtyCheckAndNoDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = false; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenNoDirtyCheckAndDirtyWrite() { dirty_whenNoDirtyCheckAndDirtyWrite(true); dirty_whenNoDirtyCheckAndDirtyWrite(false); } public void dirty_whenNoDirtyCheckAndDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = false; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenDirtyCheckAndNoDirtyWrite() { dirty_whenDirtyCheckAndNoDirtyWrite(true); dirty_whenDirtyCheckAndNoDirtyWrite(false); } public void dirty_whenDirtyCheckAndNoDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = true; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void dirty_whenDirtyCheckAndDirtyWrite() { dirty_whenDirtyCheckAndDirtyWrite(true); dirty_whenDirtyCheckAndDirtyWrite(false); } public void dirty_whenDirtyCheckAndDirtyWrite(boolean prepareFirst) { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.dirtyCheck = true; T tx = newTransaction(config); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; if (prepareFirst) { tx.prepare(); } tx.commit(); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertEquals(TxnStatus.Committed, tx.getStatus()); assertEquals(initialValue + 1, ref.long_value); assertEquals(initialVersion + 1, ref.version); assertCleaned(tx); assertRefHasNoLocks(ref); assertGlobalConflictCount(stm, globalConflictCount); } // =============================== locked by other ============================= @Test public void conflict_dirty_whenReadLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_READ); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenWriteLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_WRITE); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasWriteLock(ref, otherTx); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void conflict_dirty_whenExclusiveLockedByOther() { long globalConflictCount = stm.globalConflictCounter.count(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, LOCKMODE_NONE); tranlocal.long_value++; T otherTx = newTransaction(); ref.openForRead(otherTx, LOCKMODE_EXCLUSIVE); try { tx.commit(); fail(); } catch (ReadWriteConflict expected) { } assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasExclusiveLock(ref, otherTx); assertGlobalConflictCount(stm, globalConflictCount); } // ========================= states ================================== @Test public void whenPreparedAndUnused() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.prepare(); tx.commit(); assertIsCommitted(tx); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenAborted_thenDeadTxnException() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.abort(); try { tx.commit(); fail(); } catch (DeadTxnException expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } @Test public void whenCommitted_thenIgnored() { long globalConflictCount = stm.globalConflictCounter.count(); T tx = newTransaction(); tx.commit(); tx.commit(); assertEquals(TxnStatus.Committed, tx.getStatus()); assertCleaned(tx); assertGlobalConflictCount(stm, globalConflictCount); } }