package org.radargun.service; import javax.transaction.Status; import javax.transaction.TransactionManager; import org.infinispan.AdvancedCache; import org.infinispan.context.Flag; import org.radargun.traits.BasicOperations; import org.radargun.traits.InMemoryBasicOperations; /** * @author Radim Vansa <rvansa@redhat.com> */ public class Infinispan51Operations extends InfinispanOperations implements InMemoryBasicOperations { protected final Infinispan51EmbeddedService service; public Infinispan51Operations(Infinispan51EmbeddedService service) { super(service); this.service = service; } @Override public <K, V> InfinispanCache<K, V> getCache(String cacheName) { AdvancedCache<K, V> cache = (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache(); if (service.isExplicitLocking(cache)) { return new ExplicitLockingCache<K, V>(service, cache); } else { return new Cache<K, V>(service, cache); } } @Override public <K, V> BasicOperations.Cache<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 Cache<K, V>(service, cache); } protected static class ExplicitLockingCache<K, V> extends InfinispanOperations.Cache<K, V> { protected final TransactionManager tm; public ExplicitLockingCache(Infinispan51EmbeddedService service, AdvancedCache<K, V> cache) { super(service, 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); super.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 = super.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 = super.remove(key); } finally { stopTx(startedTx); } return retval; } @Override public V getAndRemove(K key) { boolean startedTx = false; V prev = null; try { startedTx = startTxAndLock(key); prev = super.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 = super.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 = super.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 = super.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 = super.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 = super.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); } } } } }