package org.multiverse.stms.gamma.transactionalobjects.lock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.multiverse.api.LockMode; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import java.util.Collection; import static java.util.Arrays.asList; import static org.junit.Assert.fail; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.stms.gamma.GammaTestUtils.*; @RunWith(Parameterized.class) public class Lock_acquire0Test { private GammaStm stm; private boolean readBiased; public Lock_acquire0Test(boolean readBiased) { this.readBiased = readBiased; } @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Parameterized.Parameters public static Collection<Boolean[]> configs() { return asList(new Boolean[]{true}, new Boolean[]{false}); } public GammaTxnLong newTxnLong(long initialValue) { if (readBiased) { return makeReadBiased(new GammaTxnLong(stm, initialValue)); } else { return new GammaTxnLong(stm, initialValue); } } //todo: conflict detection. @Test public void whenNullLock() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullTransaction() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (TxnMandatoryException expected) { } assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); assertIsActive(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); assertIsActive(tx); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); assertIsActive(tx); assertRefHasWriteLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void free_whenLockModeCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); assertIsActive(tx); assertRefHasExclusiveLock(ref, tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.None); assertRefHasReadLock(ref, tx); assertReadLockCount(ref, 1); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenReadLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.None); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Read); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Write); assertRefHasWriteLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenWriteLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Write); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToNone() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.None); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToRead() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Read); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToWrite() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Write); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void selfLocked_whenExclusiveLockedAndUpgradeToCommit() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Exclusive); ref.getLock().acquire(LockMode.Exclusive); assertRefHasExclusiveLock(ref, tx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } //todo: other locks. // =========================== locked by other ========================== @Test public void otherLocked_whenOtherHasReadLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); //todo: check state of tx with regard to lock assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.Read); assertRefHasReadLock(ref, tx); assertRefHasReadLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherReadLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Read); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasReadLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); ref.getLock().acquire(LockMode.None); //todo: check state of tx and locking assertRefHasWriteLock(ref, otherTx); assertIsActive(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherWriteLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Write); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasWriteLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndNoLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.None); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndReadLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndWriteLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Write); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void otherLocked_whenOtherExclusiveLockedAndExclusiveLockAcquired() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn otherTx = stm.newDefaultTxn(); ref.getLock().acquire(otherTx, LockMode.Exclusive); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.getLock().acquire(LockMode.Exclusive); fail(); } catch (ReadWriteConflict expected) { } assertRefHasExclusiveLock(ref, otherTx); assertIsAborted(tx); assertVersionAndValue(ref, initialVersion, initialValue); } // ========================== states ==================================== @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.prepare(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.abort(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = newTxnLong(initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.commit(); try { ref.getLock().acquire(LockMode.Read); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } }