package org.radargun.service; import java.util.concurrent.TimeUnit; import javax.transaction.Status; import javax.transaction.TransactionManager; import org.infinispan.AdvancedCache; import org.infinispan.context.Flag; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; import org.radargun.traits.InMemoryBasicOperations; public final class Infinispan52Operations extends InfinispanOperations implements InMemoryBasicOperations { protected final Infinispan52EmbeddedService service52; public Infinispan52Operations(Infinispan52EmbeddedService service) { super(service); this.service52 = service; } @Override public <K, V> Infinispan52Cache<K, V> getCache(String cacheName) { AdvancedCache<K, V> impl = (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache(); Infinispan52Cache<K, V> cache = new Infinispan52CacheImpl<>(service, impl); return service52.isExplicitLocking(impl) ? new ExplicitLockingCache52<K, V>(cache, impl) : cache; } @Override public <K, V> Infinispan52Cache<K, V> getMemoryOnlyCache(String cacheName) { AdvancedCache<K, V> cache = (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD, Flag.SKIP_CACHE_STORE); return new Infinispan52CacheImpl<K, V>(service, cache); } @Override public <K, V> Infinispan52Cache<K, V> getLocalCache(String cacheName) { return new Infinispan52CacheImpl<K, V>(service, (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL)); } private interface Infinispan52Cache<K, V> extends InfinispanCache<K, V> {} private static final class Infinispan52CacheImpl<K, V> implements Infinispan52Cache<K, V> { protected final Log log = LogFactory.getLog(getClass()); protected final boolean trace = log.isTraceEnabled(); protected final InfinispanEmbeddedService service; protected final org.infinispan.AdvancedCache<K, V> impl; protected final org.infinispan.Cache<K, V> ignoreReturnValueImpl; public Infinispan52CacheImpl(InfinispanEmbeddedService service, org.infinispan.AdvancedCache<K, V> impl) { this.service = service; this.impl = impl; this.ignoreReturnValueImpl = impl.withFlags(Flag.IGNORE_RETURN_VALUES); } public void put(K key, V value) { if (trace) log.tracef("PUT cache=%s key=%s value=%s", impl.getName(), key, value); ignoreReturnValueImpl.put(key, value); } @Override public V getAndPut(K key, V value) { if (trace) log.tracef("GET_AND_PUT cache=%s key=%s value=%s", impl.getName(), key, value); return impl.put(key, value); } public V get(K key) { if (trace) log.tracef("GET cache=%s key=%s", impl.getName(), key); return impl.get(key); } @Override public boolean containsKey(K key) { if (trace) log.tracef("CONTAINS cache=%s key=%s", impl.getName(), key); return impl.containsKey(key); } public boolean remove(K key) { if (trace) log.tracef("REMOVE cache=%s key=%s", impl.getName(), key); return impl.remove(key) != null; } @Override public V getAndRemove(K key) { if (trace) log.tracef("GET_AND_REMOVE cache=%s key=%s", impl.getName(), key); return impl.remove(key); } @Override public boolean replace(K key, V value) { if (trace) log.tracef("REPLACE cache=%s key=%s value=%s", impl.getName(), key, value); return impl.replace(key, value) != null; } @Override public V getAndReplace(K key, V value) { if (trace) log.tracef("GET_AND_REPLACE cache=%s key=%s value=%s", impl.getName(), key, value); return impl.replace(key, value); } @Override public void clear() { if (trace) log.trace("CLEAR " + impl.getName()); impl.clear(); } @Override public boolean replace(K key, V oldValue, V newValue) { if (trace) log.tracef("REPLACE cache=%s key=%s old=%s, new=%s", impl.getName(), key, oldValue, newValue); return impl.replace(key, oldValue, newValue); } @Override public boolean putIfAbsent(K key, V value) { if (trace) log.tracef("PUT_IF_ABSENT cache=%s key=%s value=%s", impl.getName(), key, value); return impl.putIfAbsent(key, value) == null; } @Override public boolean remove(K key, V oldValue) { if (trace) log.tracef("REMOVE cache=%s key=%s value=%s", impl.getName(), key, oldValue); return impl.remove(key, oldValue); } @Override public AdvancedCache getAdvancedCache() { return impl; } @Override public void put(K key, V value, long lifespan) { if (trace) log.tracef("PUT_WITH_LIFESPAN cache=%s key=%s value=%s lifespan=%s", impl.getName(), key, value, lifespan); ignoreReturnValueImpl.put(key, value, lifespan, TimeUnit.MILLISECONDS); } @Override public V getAndPut(K key, V value, long lifespan) { if (trace) log.tracef("GET_AND_PUT_WITH_LIFESPAN cache=%s key=%s value=%s lifespan=%s", impl.getName(), key, value, lifespan); return impl.put(key, value, lifespan, TimeUnit.MILLISECONDS); } @Override public boolean putIfAbsent(K key, V value, long lifespan) { if (trace) log.tracef("PUT_IF_ABSENT_WITH_LIFESPAN cache=%s key=%s value=%s, lifespan=%s", impl.getName(), key, value, lifespan); return impl.putIfAbsent(key, value, lifespan, TimeUnit.MILLISECONDS) == null; } @Override public void put(K key, V value, long lifespan, long maxIdleTime) { if (trace) log.tracef("PUT_WITH_LIFESPAN_AND_MAXIDLE cache=%s key=%s value=%s lifespan=%s maxIdle=%s", impl.getName(), key, value, lifespan, maxIdleTime); ignoreReturnValueImpl.put(key, value, lifespan, TimeUnit.MILLISECONDS, maxIdleTime, TimeUnit.MILLISECONDS); } @Override public V getAndPut(K key, V value, long lifespan, long maxIdleTime) { if (trace) log.tracef("GET_AND_PUT_WITH_LIFESPAN_AND_MAXIDLE cache=%s key=%s value=%s lifespan=%s maxIdle=%s", impl.getName(), key, value, lifespan, maxIdleTime); return impl.put(key, value, lifespan, TimeUnit.MILLISECONDS, maxIdleTime, TimeUnit.MILLISECONDS); } @Override public boolean putIfAbsent(K key, V value, long lifespan, long maxIdleTime) { if (trace) log.tracef("PUT_IF_ABSENT_WITH_LIFESPAN cache=%s key=%s value=%s lifespan=%s maxIdle=%s", impl.getName(), key, value, lifespan, maxIdleTime); return impl.putIfAbsent(key, value, lifespan, TimeUnit.MILLISECONDS, maxIdleTime, TimeUnit.MILLISECONDS) == null; } } private static final class ExplicitLockingCache52<K, V> implements Infinispan52Cache<K, V> { static final Log log = LogFactory.getLog(ExplicitLockingCache52.class); final Infinispan52Cache<K, V> delegate; final TransactionManager tm; final AdvancedCache<K, V> impl; public ExplicitLockingCache52(Infinispan52Cache<K, V> delegate, AdvancedCache<K, V> cache) { this.delegate = delegate; this.impl = cache; this.tm = cache.getTransactionManager(); } /** * If transactions and explicit locking are enabled and the locking mode is pessimistic then * explicit locking is performed! i.e. before any put the key is explicitly locked by call * cache.lock(key). Doesn't lock the key if the request was made by ClusterValidationStage. */ @Override public void put(K key, V value) { boolean startedTx = false; try { startedTx = startTxAndLock(key); delegate.put(key, value); } finally { stopTx(startedTx); } } @Override public V getAndPut(K key, V value) { boolean startedTx = false; V prev = null; try { startedTx = startTxAndLock(key); prev = delegate.getAndPut(key, value); } finally { stopTx(startedTx); } return prev; } @Override public boolean remove(K key) { boolean startedTx = false; boolean retval = false; try { startedTx = startTxAndLock(key); retval = delegate.remove(key); } finally { stopTx(startedTx); } return retval; } @Override public V getAndRemove(K key) { boolean startedTx = false; V prev = null; try { startedTx = startTxAndLock(key); prev = delegate.getAndRemove(key); } finally { stopTx(startedTx); } return prev; } @Override public boolean replace(K key, V value) { boolean startedTx = false; boolean retval = false; try { startedTx = startTxAndLock(key); retval = delegate.replace(key, value); } finally { stopTx(startedTx); } return retval; } @Override public V getAndReplace(K key, V value) { boolean startedTx = false; V prev = null; try { startedTx = startTxAndLock(key); prev = delegate.getAndReplace(key, value); } finally { stopTx(startedTx); } return prev; } @Override public boolean replace(K key, V oldValue, V newValue) { boolean startedTx = false; boolean retval = false; try { startedTx = startTxAndLock(key); retval = delegate.replace(key, oldValue, newValue); } finally { stopTx(startedTx); } return retval; } @Override public boolean putIfAbsent(K key, V value) { boolean startedTx = false; boolean retval = false; try { startedTx = startTxAndLock(key); retval = delegate.putIfAbsent(key, value); } finally { stopTx(startedTx); } return retval; } @Override public boolean remove(K key, V oldValue) { boolean startedTx = false; boolean retval = false; try { startedTx = startTxAndLock(key); retval = delegate.remove(key, oldValue); } finally { stopTx(startedTx); } return retval; } private boolean startTxAndLock(K key) { boolean startedTx = false; try { if (tm.getStatus() == Status.STATUS_NO_TRANSACTION) { startedTx = true; tm.begin(); } impl.lock(key); } catch (Exception e) { log.error("Failed to begin transaction and lock", e); throw new RuntimeException(e); } return startedTx; } private void stopTx(boolean startedTx) { if (startedTx) { try { tm.commit(); } catch (Exception e) { log.error("Failed to commit transaction", e); } } } @Override public AdvancedCache getAdvancedCache() { return impl; } @Override public V get(K key) { return delegate.get(key); } @Override public boolean containsKey(K key) { return delegate.containsKey(key); } @Override public void put(K key, V value, long lifespan) { delegate.put(key, value, lifespan); } @Override public V getAndPut(K key, V value, long lifespan) { return delegate.getAndPut(key, value, lifespan); } @Override public boolean putIfAbsent(K key, V value, long lifespan) { return delegate.putIfAbsent(key, value, lifespan); } @Override public void put(K key, V value, long lifespan, long maxIdleTime) { delegate.put(key, value, lifespan, maxIdleTime); } @Override public V getAndPut(K key, V value, long lifespan, long maxIdleTime) { return delegate.getAndPut(key, value, lifespan, maxIdleTime); } @Override public boolean putIfAbsent(K key, V value, long lifespan, long maxIdleTime) { return delegate.putIfAbsent(key, value, lifespan, maxIdleTime); } @Override public void clear() { delegate.clear(); } } }