package org.infinispan.lock;
import static org.infinispan.context.Flag.FAIL_SILENTLY;
import static org.infinispan.test.TestingUtil.withCacheManager;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import javax.transaction.Status;
import javax.transaction.TransactionManager;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.context.Flag;
import org.infinispan.interceptors.locking.AbstractLockingInterceptor;
import org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.test.CacheManagerCallable;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.CleanupAfterMethod;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.transaction.LockingMode;
import org.infinispan.util.ReplicatedControlledConsistentHashFactory;
import org.infinispan.util.concurrent.TimeoutException;
import org.testng.annotations.Test;
@Test(testName = "lock.APITest", groups = "functional")
@CleanupAfterMethod
public class APITest extends MultipleCacheManagersTest {
private EmbeddedCacheManager cm1, cm2;
@Override
protected void createCacheManagers() throws Throwable {
ConfigurationBuilder cfg = getDefaultClusteredCacheConfig(CacheMode.REPL_SYNC, true);
cfg.clustering().hash().numSegments(1)
.consistentHashFactory(new ReplicatedControlledConsistentHashFactory(0));
cfg.transaction().lockingMode(LockingMode.PESSIMISTIC)
.cacheStopTimeout(0)
.locking().lockAcquisitionTimeout(TestingUtil.shortTimeoutMillis());
cm1 = TestCacheManagerFactory.createClusteredCacheManager(cfg);
cm2 = TestCacheManagerFactory.createClusteredCacheManager(cfg);
registerCacheManager(cm1, cm2);
cm1.getCache();
cm2.getCache();
}
public void testProperties() {
Properties p = new Properties();
Object v = new Object();
p.put("bla", v);
assertEquals(v, p.get("bla"));
System.out.println(p.get("bla"));
}
public void testLockSuccess() throws Exception {
Cache<String, String> cache1 = cache(0);
cache1.put("k", "v");
tm(0).begin();
assert cache1.getAdvancedCache().lock("k");
tm(0).rollback();
}
@Test (expectedExceptions = TimeoutException.class)
public void testLockFailure() throws Exception {
Cache<String, String> cache1 = cache(0), cache2 = cache(1);
cache1.put("k", "v");
tm(1).begin();
cache2.put("k", "v2");
tm(1).suspend();
tm(0).begin();
cache1.getAdvancedCache().lock("k");
tm(0).rollback();
}
public void testSilentLockFailure() throws Exception {
Cache<String, String> cache1 = cache(0), cache2 = cache(1);
cache1.put("k", "v");
tm(1).begin();
cache2.put("k", "v2");
tm(1).suspend();
tm(0).begin();
assert !cache1.getAdvancedCache().withFlags(FAIL_SILENTLY).lock("k");
tm(0).rollback();
}
public void testSilentLockFailureAffectsPostOperations() throws Exception {
final Cache<Integer, String> cache = cache(0);
final TransactionManager tm = cache.getAdvancedCache().getTransactionManager();
final CountDownLatch waitLatch = new CountDownLatch(1);
final CountDownLatch continueLatch = new CountDownLatch(1);
cache.put(1, "v1");
Future<Void> f1 = fork(new Callable<Void>() {
@Override
public Void call() throws Exception {
tm.begin();
try {
cache.put(1, "v2");
waitLatch.countDown();
continueLatch.await();
} catch (Exception e) {
tm.setRollbackOnly();
throw e;
} finally {
if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
else tm.rollback();
}
return null;
}
});
Future<Void> f2 = fork(new Callable<Void>() {
@Override
public Void call() throws Exception {
waitLatch.await();
tm.begin();
try {
AdvancedCache<Integer, String> silentCache = cache.getAdvancedCache().withFlags(
Flag.FAIL_SILENTLY, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
silentCache.put(1, "v3");
assert !silentCache.lock(1);
String object = cache.get(1);
assert "v1".equals(object) : "Expected v1 but got " + object;
cache.get(1);
} catch (Exception e) {
tm.setRollbackOnly();
throw e;
} finally {
if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
else tm.rollback();
continueLatch.countDown();
}
return null;
}
});
f1.get();
f2.get();
}
public void testMultiLockSuccess() throws Exception {
Cache<String, String> cache1 = cache(0);
cache1.put("k1", "v");
cache1.put("k2", "v");
cache1.put("k3", "v");
tm(0).begin();
assert cache1.getAdvancedCache().lock(Arrays.asList("k1", "k2", "k3"));
tm(0).rollback();
}
@Test (expectedExceptions = TimeoutException.class)
public void testMultiLockFailure() throws Exception {
Cache<String, String> cache1 = cache(0), cache2 = cache(1);
cache1.put("k1", "v");
cache1.put("k2", "v");
cache1.put("k3", "v");
tm(1).begin();
cache2.put("k3", "v2");
tm(1).suspend();
tm(0).begin();
cache1.getAdvancedCache().lock(Arrays.asList("k1", "k2", "k3"));
tm(0).rollback();
}
public void testSilentMultiLockFailure() throws Exception {
Cache<String, String> cache1 = cache(0), cache2 = cache(1);
cache1.put("k1", "v");
cache1.put("k2", "v");
cache1.put("k3", "v");
tm(1).begin();
cache2.put("k3", "v2");
tm(1).suspend();
tm(0).begin();
assert !cache1.getAdvancedCache().withFlags(FAIL_SILENTLY).lock(Arrays.asList("k1", "k2", "k3"));
tm(0).rollback();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testLockOnNonTransactionalCache() {
withCacheManager(new CacheManagerCallable(
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
cm.getCache().getAdvancedCache().lock("k");
}
});
}
public void testLockingInterceptorType() {
ConfigurationBuilder builder = new ConfigurationBuilder();
withCacheManager(new CacheManagerCallable(
TestCacheManagerFactory.createCacheManager(builder)) {
@Override
public void call() {
AbstractLockingInterceptor lockingInterceptor = TestingUtil.findInterceptor(
cm.getCache(), AbstractLockingInterceptor.class);
assertTrue(lockingInterceptor instanceof NonTransactionalLockingInterceptor);
}
});
}
}