package org.multiverse.stms.gamma.integration.locks;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.api.LockMode;
import org.multiverse.api.exceptions.ReadWriteConflict;
import org.multiverse.stms.gamma.GammaStm;
import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong;
import org.multiverse.stms.gamma.transactions.GammaTxn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.multiverse.TestUtils.*;
import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance;
import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn;
import static org.multiverse.stms.gamma.GammaTestUtils.*;
public class ReadLockTest {
private GammaStm stm;
@Before
public void setUp() {
stm = (GammaStm) getGlobalStmInstance();
clearThreadLocalTxn();
}
@Test
public void whenUnlocked() {
GammaTxnLong ref = new GammaTxnLong(stm, 10);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
assertIsActive(tx);
assertRefHasReadLock(ref, tx);
assertReadLockCount(ref, 1);
}
@Test
public void whenReadLockAlreadyAcquiredByOther_thenReadLockSuccess() {
GammaTxnLong ref = new GammaTxnLong(stm);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Read);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
assertIsActive(tx);
assertRefHasReadLock(ref, otherTx);
assertRefHasReadLock(ref, tx);
assertReadLockCount(ref, 2);
}
@Test
public void whenWriteLockAlreadyAcquiredByOther_thenReadLockNotPossible() {
GammaTxnLong ref = new GammaTxnLong(stm);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Write);
GammaTxn tx = stm.newDefaultTxn();
try {
ref.getLock().acquire(tx, LockMode.Read);
fail();
} catch (ReadWriteConflict expected) {
}
assertIsAborted(tx);
assertRefHasWriteLock(ref, otherTx);
}
@Test
public void whenExclusiveLockAlreadyAcquiredByOther_thenReadLockNotPossible() {
GammaTxnLong ref = new GammaTxnLong(stm);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Exclusive);
GammaTxn tx = stm.newDefaultTxn();
try {
ref.getLock().acquire(tx, LockMode.Read);
fail();
} catch (ReadWriteConflict expected) {
}
assertIsAborted(tx);
assertRefHasExclusiveLock(ref, otherTx);
}
@Test
public void whenReadLockAcquiredByOther_thenReadPossible() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Read);
GammaTxn tx = stm.newDefaultTxn();
long result = ref.get(tx);
assertIsActive(tx);
assertEquals(initialValue, result);
assertRefHasReadLock(ref, otherTx);
assertReadLockCount(ref, 1);
}
@Test
public void whenReadLockAcquiredByOther_thenWritePossible() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Read);
GammaTxn tx = stm.newDefaultTxn();
ref.set(tx, initialValue + 1);
assertEquals(initialValue + 1, ref.get(tx));
assertIsActive(tx);
assertRefHasReadLock(ref, otherTx);
assertReadLockCount(ref, 1);
}
@Test
public void whenReadLockAcquiredByOtherAndDirtyTransaction_thenReadFails() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Read);
GammaTxn tx = stm.newDefaultTxn();
ref.set(tx, initialValue + 1);
try {
tx.commit();
fail();
} catch (ReadWriteConflict expected) {
}
assertIsAborted(tx);
assertRefHasReadLock(ref, otherTx);
assertReadLockCount(ref, 1);
}
@Test
public void whenReadLockAcquiredByOtherAndDirtyTransaction_thenPrepareFails() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
GammaTxn otherTx = stm.newDefaultTxn();
ref.getLock().acquire(otherTx, LockMode.Read);
GammaTxn tx = stm.newDefaultTxn();
ref.set(tx, initialValue + 1);
try {
tx.prepare();
fail();
} catch (ReadWriteConflict expected) {
}
assertIsAborted(tx);
assertRefHasReadLock(ref, otherTx);
assertReadLockCount(ref, 1);
}
@Test
public void whenPreviouslyReadByOtherThread_thenNoProblems() {
GammaTxnLong ref = new GammaTxnLong(stm, 10);
GammaTxn otherTx = stm.newDefaultTxn();
ref.get(otherTx);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
long result = ref.get(otherTx);
assertEquals(10, result);
}
@Test
public void whenReadLockAcquiredAcquired_thenAcquireReadLockSuccess() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
ref.getLock().acquire(tx, LockMode.Read);
assertIsActive(tx);
assertRefHasReadLock(ref, tx);
assertReadLockCount(ref, 1);
}
@Test
public void whenWriteLockAcquired_thenUpgradableToReadLockIgnored() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Write);
ref.getLock().acquire(tx, LockMode.Read);
assertIsActive(tx);
assertRefHasWriteLock(ref, tx);
}
@Test
public void whenExclusiveLockAcquired_thenUpgradableToReadLockIgnored() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Exclusive);
ref.getLock().acquire(tx, LockMode.Read);
assertIsActive(tx);
assertRefHasExclusiveLock(ref, tx);
}
@Test
public void whenTransactionCommits_thenReadLockReleased() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
tx.commit();
assertIsCommitted(tx);
assertRefHasNoLocks(ref);
}
@Test
public void whenTransactionIsPrepared_thenReadLockRemains() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
tx.prepare();
assertIsPrepared(tx);
assertRefHasReadLock(ref, tx);
}
@Test
public void whenTransactionAborts_thenReadLockIsReleased() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.getLock().acquire(tx, LockMode.Read);
tx.abort();
assertIsAborted(tx);
assertRefHasNoLocks(ref);
}
@Test
public void whenReadWriteConflictAfterInitialRead_thenReadWriteLockFails() {
GammaTxnLong ref = new GammaTxnLong(stm, 5);
GammaTxn tx = stm.newDefaultTxn();
ref.get(tx);
ref.atomicIncrementAndGet(1);
try {
ref.getLock().acquire(tx, LockMode.Read);
fail();
} catch (ReadWriteConflict expected) {
}
assertRefHasNoLocks(ref);
assertIsAborted(tx);
}
}