package org.infinispan.stats.topK; import static org.infinispan.test.TestingUtil.k; import static org.testng.AssertJUnit.fail; import java.lang.reflect.Method; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.transaction.RollbackException; import javax.transaction.Transaction; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.interceptors.impl.TxInterceptor; import org.infinispan.stats.AbstractTopKeyTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterTest; import org.infinispan.util.concurrent.IsolationLevel; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * @author Pedro Ruivo * @since 6.0 */ @Test(groups = "functional", testName = "stats.topK.LocalTopKeyTest") @CleanupAfterTest public class LocalTopKeyTest extends AbstractTopKeyTest { @BeforeMethod(alwaysRun = true) public void resetBeforeTest() { getTopKey(cache(0)).resetStatistics(); } public void testPut(Method method) { final String key1 = k(method, 1); final String key2 = k(method, 2); cache(0).put(key1, "value1"); cache(0).put(key2, "value2"); assertTopKeyAccesses(cache(0), key1, 1, false); assertTopKeyAccesses(cache(0), key2, 1, false); assertTopKeyAccesses(cache(0), key1, 0, true); assertTopKeyAccesses(cache(0), key2, 0, true); assertLockInformation(cache(0), key1, 1, 0, 0); assertLockInformation(cache(0), key2, 1, 0, 0); assertWriteSkew(cache(0), key1, 0); assertWriteSkew(cache(0), key2, 0); } public void testGet(Method method) { final String key1 = k(method, 1); final String key2 = k(method, 2); cache(0).get(key1); cache(0).get(key2); assertTopKeyAccesses(cache(0), key1, 0, false); assertTopKeyAccesses(cache(0), key2, 0, false); assertTopKeyAccesses(cache(0), key1, 1, true); assertTopKeyAccesses(cache(0), key2, 1, true); assertLockInformation(cache(0), key1, 0, 0, 0); assertLockInformation(cache(0), key2, 0, 0, 0); assertWriteSkew(cache(0), key1, 0); assertWriteSkew(cache(0), key2, 0); } public void testLockFailed(Method method) throws InterruptedException, TimeoutException, ExecutionException { final String key = k(method, 0); PrepareCommandBlocker blocker = addPrepareBlockerIfAbsent(cache(0)); blocker.reset(); Future<Void> f = fork(() -> { cache(0).put(key, "value"); return null; }); blocker.awaitUntilPrepareBlocked(); //at this point, the key is locked... try { cache(0).put(key, "value"); Assert.fail("The key should be locked!"); } catch (Throwable t) { //expected } blocker.unblock(); f.get(30, TimeUnit.SECONDS); assertTopKeyAccesses(cache(0), key, 2, false); assertTopKeyAccesses(cache(0), key, 0, true); assertLockInformation(cache(0), key, 2, 1, 1); assertWriteSkew(cache(0), key, 0); } public void testWriteSkew(Method method) throws Exception { final String key = k(method, 0); cache(0).put(key, "init"); tm(0).begin(); cache(0).get(key); Transaction transaction = tm(0).suspend(); cache(0).put(key, "value"); try { tm(0).resume(transaction); cache(0).put(key, "value1"); tm(0).commit(); fail("The write skew should be detected"); } catch (RollbackException t) { //expected } assertTopKeyAccesses(cache(0), key, 3, false); assertTopKeyAccesses(cache(0), key, 1, true); //the last put will originate an write skew assertLockInformation(cache(0), key, 3, 0, 0); assertWriteSkew(cache(0), key, 1); } @Override protected void createCacheManagers() throws Throwable { ConfigurationBuilder builder = getDefaultClusteredCacheConfig(CacheMode.LOCAL, true); builder.customInterceptors().addInterceptor() .before(TxInterceptor.class) .interceptor(new CacheUsageInterceptor()); builder.locking().isolationLevel(IsolationLevel.REPEATABLE_READ) .lockAcquisitionTimeout(TestingUtil.shortTimeoutMillis()); addClusterEnabledCacheManager(builder); } }