package org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.IsolationLevel; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.*; import org.multiverse.api.functions.Functions; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.junit.Assume.assumeTrue; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.TestUtils.assertIsActive; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_openForReadTest<T extends GammaTxn> implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract int getMaxCapacity(); protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); @Test public void whenArrive() { //the mono transaction doesn't support (or need) the richmans conflict assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref = new GammaTxnLong(stm); GammaTxnConfig config = new GammaTxnConfig(stm) .setMaximumPoorMansConflictScanLength(0); T tx = newTransaction(config); ref.openForRead(tx, LOCKMODE_NONE); assertSurplus(ref, 1); } @Test public void whenStmMismatch() { GammaStm otherStm = new GammaStm(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(otherStm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (StmMismatchException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAbortOnly_thenReadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = stm.newDefaultTxn(); tx.setAbortOnly(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenTransactionAbortOnly_thenRereadStillPossible() { GammaTxnLong ref = new GammaTxnLong(stm, 0); GammaTxn tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); tx.setAbortOnly(); Tranlocal reread = ref.openForRead(tx, LOCKMODE_NONE); assertSame(read, reread); assertTrue(tx.isAbortOnly()); assertIsActive(tx); } @Test public void whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem() { whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.None); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Read); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Write); whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode.Exclusive); } public void whenReadFirstAndExclusivelyLockedByOtherAndThenReread_thenNoProblem(LockMode lockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal read = ref.openForRead(tx, LOCKMODE_NONE); GammaTxn otherTx = newTransaction(); ref.getLock().acquire(otherTx, lockMode); Tranlocal read2 = ref.openForRead(tx, LOCKMODE_NONE); assertIsActive(tx); assertSame(read, read2); assertRefHasLockMode(ref, otherTx, lockMode.asInt()); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForConstruction() { T tx = newTransaction(); GammaTxnLong ref = new GammaTxnLong(tx, 0); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_CONSTRUCTING, tranlocal.getMode()); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); } @Test public void whenAlreadyOpenedForCommute() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertEquals(TRANLOCAL_WRITE, tranlocal.getMode()); assertIsActive(tx); assertEquals(11, tranlocal.long_value); assertEquals(10, tranlocal.long_oldValue); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenAlreadyOpenedForCommuteAndLockingConflicts() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); ref.commute(tx, Functions.incLongFunction()); Tranlocal tranlocal = tx.locate(ref); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); try{ ref.openForRead(tx, LOCKMODE_NONE); fail(); }catch(ReadWriteConflict expected){ } assertNotNull(tranlocal); assertNull(tranlocal.owner); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsAborted(tx); assertRefHasExclusiveLock(ref, otherTx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenOverflowing() { int maxCapacity = getMaxCapacity(); assumeTrue(maxCapacity < Integer.MAX_VALUE); GammaTxn tx = newTransaction(); for (int k = 0; k < maxCapacity; k++) { GammaTxnLong ref = new GammaTxnLong(stm, 0); ref.openForRead(tx, LOCKMODE_NONE); } GammaTxnLong ref = new GammaTxnLong(stm, 0); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (SpeculativeConfigurationError expected) { } assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(maxCapacity + 1, tx.getConfig().getSpeculativeConfiguration().minimalLength); } @Test public void whenReadonly() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm); config.readonly = true; GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertTrue(tranlocal.isRead()); assertFalse(tx.hasWrites()); } @Test public void whenNotOpenedBefore() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertNotNull(tranlocal); assertSame(ref, tranlocal.owner); assertEquals(initialVersion, tranlocal.version); assertEquals(initialValue, tranlocal.long_value); assertEquals(initialValue, tranlocal.long_oldValue); assertTrue(tranlocal.isRead()); assertFalse(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForRead() { whenRefAlreadyOpenedForRead(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForRead(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForRead(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForRead(LockMode firstReadLockMode, LockMode secondReadLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, firstReadLockMode.asInt()); Tranlocal second = ref.openForRead(tx, secondReadLockMode.asInt()); assertSame(first, second); assertNotNull(second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void whenRefAlreadyOpenedForWrite() { whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.None, LockMode.None); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.None, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Read, LockMode.Read); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.None, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Read, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Write, LockMode.Write); whenRefAlreadyOpenedForWrite(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.None, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Read, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Write, LockMode.Exclusive); whenRefAlreadyOpenedForWrite(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void whenRefAlreadyOpenedForWrite(LockMode writeLockMode, LockMode readLockMode, LockMode expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); Tranlocal first = ref.openForWrite(tx, writeLockMode.asInt()); Tranlocal second = ref.openForRead(tx, readLockMode.asInt()); assertSame(first, second); assertSame(ref, second.owner); assertEquals(initialVersion, second.version); assertEquals(initialValue, second.long_value); assertEquals(initialValue, second.long_oldValue); assertLockMode(ref, expectedLockMode); assertTrue(second.isWrite()); assertTrue(tx.hasWrites()); } @Test public void readConsistency_whenNotConsistent() { assumeTrue(getMaxCapacity() > 1); GammaTxnLong ref1 = new GammaTxnLong(stm, 0); GammaTxnLong ref2 = new GammaTxnLong(stm, 0); GammaTxn tx = newTransaction(); ref1.openForRead(tx, LOCKMODE_NONE); ref1.atomicIncrementAndGet(1); try { ref2.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); } // ====================== lock level ======================================== @Test public void lockLevel() { lockLevel(LockMode.None, LockMode.None, LockMode.None); lockLevel(LockMode.None, LockMode.Read, LockMode.Read); lockLevel(LockMode.None, LockMode.Write, LockMode.Write); lockLevel(LockMode.None, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Read, LockMode.Read, LockMode.Read); lockLevel(LockMode.Read, LockMode.Write, LockMode.Write); lockLevel(LockMode.Read, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Write, LockMode.Write, LockMode.Write); lockLevel(LockMode.Write, LockMode.Exclusive, LockMode.Exclusive); lockLevel(LockMode.Exclusive, LockMode.Exclusive, LockMode.Exclusive); } public void lockLevel(LockMode transactionReadLockMode, LockMode readLockMode, LockMode expectedReadLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxnConfig config = new GammaTxnConfig(stm) .setReadLockMode(transactionReadLockMode) .setWriteLockMode(transactionReadLockMode); GammaTxn tx = newTransaction(config); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); assertEquals(expectedReadLockMode.asInt(), tranlocal.getLockMode()); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedReadLockMode.asInt()); } // ===================== lock upgrade ====================================== @Test public void lockUpgrade() { lockUpgrade(LOCKMODE_NONE, LOCKMODE_NONE, LOCKMODE_NONE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_NONE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_NONE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_READ, LOCKMODE_NONE, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_READ, LOCKMODE_READ); lockUpgrade(LOCKMODE_READ, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_READ, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_NONE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_READ, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_WRITE, LOCKMODE_WRITE); lockUpgrade(LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_NONE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_READ, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_WRITE, LOCKMODE_EXCLUSIVE); lockUpgrade(LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE, LOCKMODE_EXCLUSIVE); } public void lockUpgrade(int firstMode, int secondLockMode, int expectedLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = newTransaction(); ref.openForRead(tx, firstMode); Tranlocal tranlocal = ref.openForRead(tx, secondLockMode); assertEquals(expectedLockMode, tranlocal.getLockMode()); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasLockMode(ref, tx, expectedLockMode); } // ===================== locking ============================================ @Test public void locking_noLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_noLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_NONE); assertEquals(LOCKMODE_NONE, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_noLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_readLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_READ); assertEquals(LOCKMODE_READ, tranlocal.getLockMode()); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 2); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_readLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_readLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_READ); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_WRITE); assertEquals(LOCKMODE_WRITE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_writeLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); } @Test public void locking_writeLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_writeLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_WRITE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } @Test public void locking_exclusiveLockRequired_whenFree() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, LOCKMODE_EXCLUSIVE); assertEquals(LOCKMODE_EXCLUSIVE, tranlocal.getLockMode()); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, tx); assertEquals(ref, tranlocal.owner); assertEquals(TRANLOCAL_READ, tranlocal.getMode()); } @Test public void locking_exclusiveLockRequired_whenLockedForReadByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Read); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasReadLock(ref, otherTx); assertReadLockCount(ref, 1); } @Test public void locking_exclusiveLockRequired_whenLockedForWriteByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Write); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasWriteLock(ref, otherTx); } @Test public void locking_exclusiveLockReqyired_whenLockedForCommitByOther() { long intitialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, intitialValue); long initialVersion = ref.getVersion(); T otherTx = newTransaction(); ref.getLock().acquire(otherTx, LockMode.Exclusive); T tx = newTransaction(); try { ref.openForRead(tx, LOCKMODE_EXCLUSIVE); fail(); } catch (ReadWriteConflict expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, intitialValue); assertRefHasExclusiveLock(ref, otherTx); } // =================== while commuting ============================ @Test public void commuting_whenCommuting_thenFailure() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); tx.evaluatingCommute = true; try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (IllegalCommuteException expected) { } assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); assertRefHasNoLocks(ref); } // ================================================================ @Test public void whenRepeatableReadIsolationLevel(){ assumeTrue(getMaxCapacity()>1); long initialValue = 1; GammaTxnLong ref1 = new GammaTxnLong(stm, initialValue); GammaTxnLong ref2 = new GammaTxnLong(stm, initialValue); GammaTxnConfig config = new GammaTxnConfig(stm) .setIsolationLevel(IsolationLevel.RepeatableRead); T tx = newTransaction(config); ref1.get(tx); ref1.atomicIncrementAndGet(1); long value = ref2.get(tx); assertIsActive(tx); assertEquals(1, value); } // ================================================================ @Test public void whenTransactionPrepared_thenPreparedTxnException() { GammaTxn tx = newTransaction(); tx.prepare(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void state_whenTransactionAlreadyAborted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.abort(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } @Test public void state_whenTransactionAlreadyCommitted_thenDeadTxnException() { GammaTxn tx = newTransaction(); tx.commit(); long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); try { ref.openForRead(tx, LOCKMODE_NONE); fail(); } catch (DeadTxnException expected) { } assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.version); } }