package org.infinispan.lock; import java.util.concurrent.TimeUnit; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.commons.marshall.WrappedByteArray; import org.infinispan.test.SingleCacheManagerTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterTest; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.transaction.TransactionMode; import org.infinispan.util.concurrent.TimeoutException; import org.infinispan.util.concurrent.locks.impl.LockContainer; import org.testng.AssertJUnit; import org.testng.annotations.Test; /** * Tests if the same lock is used for the same key. * * @author Pedro Ruivo * @since 7.0 */ @Test(groups = "unit", testName = "lock.KeyLockTest") @CleanupAfterTest public class KeyLockTest extends SingleCacheManagerTest { private static final int RETRIES = 100; public void testByteArrayStrippedLockTx() throws Exception { doTest(CacheName.STRIPPED_LOCK_TX); } public void testByteArrayStrippedLockNonTx() throws Exception { doTest(CacheName.STRIPPED_LOCK_NON_TX); } public void testByteArrayPerEntryLockTx() throws Exception { doTest(CacheName.PER_ENTRY_LOCK_TX); } public void testByteArrayPerEntryLockNonTx() throws Exception { doTest(CacheName.PER_ENTRY_LOCK_NON_TX); } @Override protected EmbeddedCacheManager createCacheManager() throws Exception { ConfigurationBuilder builder = getDefaultClusteredCacheConfig(CacheMode.LOCAL); builder.locking().lockAcquisitionTimeout(100, TimeUnit.MILLISECONDS); EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(builder); for (CacheName cacheName : CacheName.values()) { cacheName.configure(builder); cacheManager.defineConfiguration(cacheName.name(), builder.build()); } return cacheManager; } private void doTest(CacheName cacheName) throws Exception { final LockContainer lockContainer = TestingUtil.extractComponent(cache(cacheName.name()), LockContainer.class); final Object lockOwner = new Object(); try { lockContainer.acquire(byteArray(), lockOwner, 10, TimeUnit.MILLISECONDS).lock(); } catch (InterruptedException | TimeoutException e) { AssertJUnit.fail(); } AssertJUnit.assertTrue(lockContainer.isLocked(byteArray())); fork(() -> { for (int i = 0; i < RETRIES; ++i) { AssertJUnit.assertTrue(lockContainer.isLocked(byteArray())); try { lockContainer.acquire(byteArray(), new Object(), 10, TimeUnit.MILLISECONDS).lock(); AssertJUnit.fail(); } catch (InterruptedException | TimeoutException e) { //expected } } return null; }).get(10, TimeUnit.SECONDS); } private static WrappedByteArray byteArray() { return new WrappedByteArray(new byte[]{1}); } private enum CacheName { STRIPPED_LOCK_TX { @Override void configure(ConfigurationBuilder builder) { builder.locking().useLockStriping(true); builder.transaction().transactionMode(TransactionMode.TRANSACTIONAL); } }, STRIPPED_LOCK_NON_TX { @Override void configure(ConfigurationBuilder builder) { builder.locking().useLockStriping(true); builder.transaction().transactionMode(TransactionMode.NON_TRANSACTIONAL); } }, PER_ENTRY_LOCK_TX { @Override void configure(ConfigurationBuilder builder) { builder.locking().useLockStriping(false); builder.transaction().transactionMode(TransactionMode.TRANSACTIONAL); } }, PER_ENTRY_LOCK_NON_TX { @Override void configure(ConfigurationBuilder builder) { builder.locking().useLockStriping(false); builder.transaction().transactionMode(TransactionMode.NON_TRANSACTIONAL); } }; abstract void configure(ConfigurationBuilder builder); } }