package org.infinispan.distribution;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.fail;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.transaction.TransactionManager;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.infinispan.test.TestingUtil;
import org.infinispan.transaction.LockingMode;
import org.testng.annotations.Test;
@Test(groups = "functional", testName = "distribution.DistSyncL1PessimisticFuncTest")
public class DistSyncL1PessimisticFuncTest extends BaseDistFunctionalTest {
public DistSyncL1PessimisticFuncTest() {
transactional = true;
testRetVals = true;
lockingMode = LockingMode.PESSIMISTIC;
}
public void testWriteLockBlockingForceWriteL1Update() throws Exception {
final String key = "some-key";
String value = "some-value";
final String otherValue = "some-new-value";
final Cache<Object, String> nonOwner = getFirstNonOwner(key);
final Cache<Object, String> owner = getFirstOwner(key);
owner.put(key, value);
// Get put in L1
nonOwner.get(key);
assertIsInL1(nonOwner, key);
try {
// Owner now does a write
TransactionManager ownerManger = TestingUtil.getTransactionManager(owner);
ownerManger.begin();
// This should lock the key
owner.put(key, otherValue);
// Now non owner tries to lock the key, but should get blocked
Future<String> futureGet = fork(new Callable<String>() {
@Override
public String call() throws Exception {
TransactionManager mgr = TestingUtil.getTransactionManager(nonOwner);
mgr.begin();
try {
return nonOwner.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK).get(key);
} finally {
mgr.commit();
}
}
});
// Get should not be able to complete
try {
futureGet.get(1, TimeUnit.SECONDS);
fail("Get command should have blocked waiting");
} catch (TimeoutException e) {
}
ownerManger.commit();
assertEquals(otherValue, futureGet.get(1, TimeUnit.SECONDS));
assertIsInL1(nonOwner, key);
} finally {
nonOwner.getAdvancedCache().getAsyncInterceptorChain().removeInterceptor(BlockingInterceptor.class);
}
}
public void testForceWriteLockWithL1Invalidation() throws Exception {
final String key = "some-key";
String value = "some-value";
final String otherValue = "some-new-value";
final Cache<Object, String> nonOwner = getFirstNonOwner(key);
final Cache<Object, String> owner = getFirstOwner(key);
owner.put(key, value);
// Get put in L1
nonOwner.get(key);
assertIsInL1(nonOwner, key);
try {
// Owner now does a write
TransactionManager ownerManger = TestingUtil.getTransactionManager(owner);
ownerManger.begin();
// This should lock the key
assertEquals(value, nonOwner.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK).get(key));
// Now non owner tries to lock the key, but should get blocked
Future<String> futurePut = fork(new Callable<String>() {
@Override
public String call() throws Exception {
TransactionManager mgr = TestingUtil.getTransactionManager(nonOwner);
mgr.begin();
try {
return owner.put(key, otherValue);
} finally {
mgr.commit();
}
}
});
// Put should not be able to complete
try {
futurePut.get(1, TimeUnit.SECONDS);
fail("Get command should have blocked waiting");
} catch (TimeoutException e) {
}
ownerManger.commit();
assertEquals(value, futurePut.get(1, TimeUnit.SECONDS));
eventually(new Condition() {
@Override
public boolean isSatisfied() throws Exception {
// Value should be removed from L1 eventually
return !isInL1(nonOwner, key);
}
});
assertIsNotInL1(nonOwner, key);
} finally {
nonOwner.getAdvancedCache().getAsyncInterceptorChain().removeInterceptor(BlockingInterceptor.class);
}
}
}