package org.radargun.service;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import javax.transaction.Status;
import javax.transaction.TransactionManager;
import org.infinispan.AdvancedCache;
import org.radargun.logging.Log;
import org.radargun.logging.LogFactory;
import org.radargun.traits.BulkOperations;
/**
* @author Radim Vansa <rvansa@redhat.com>
*/
public class InfinispanBulkOperations implements BulkOperations {
protected final Log log = LogFactory.getLog(InfinispanBulkOperations.class);
protected final boolean trace = log.isTraceEnabled();
protected final Infinispan51EmbeddedService service;
public InfinispanBulkOperations(Infinispan51EmbeddedService service) {
this.service = service;
}
@Override
public <K, V> Cache<K, V> getCache(String cacheName, boolean preferAsync) {
return new Cache<K, V>((AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache(), preferAsync);
}
protected class Cache<K, V> implements BulkOperations.Cache<K, V>, AdvancedCacheHolder {
protected final AdvancedCache<K, V> impl;
protected final TransactionManager tm;
protected final boolean preferAsync;
public Cache(AdvancedCache<K, V> cache, boolean preferAsync) {
this.impl = cache;
this.preferAsync = preferAsync;
this.tm = cache.getTransactionManager();
}
@Override
public Map<K, V> getAll(Set<K> keys) {
if (trace) {
StringBuilder sb = new StringBuilder("GET_ALL ");
for (K key : keys) {
sb.append(key).append(", ");
}
log.trace(sb.toString());
}
Map<K, Future<V>> futures = new HashMap<K, Future<V>>(keys.size());
Map<K, V> values = new HashMap<K, V>(keys.size());
for (K key : keys) {
futures.put(key, impl.getAsync(key));
}
for (Map.Entry<K, Future<V>> entry : futures.entrySet()) {
try {
V value = entry.getValue().get();
if (value != null) {
values.put(entry.getKey(), value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return values;
}
@Override
public void putAll(Map<K, V> entries) {
if (trace) {
StringBuilder sb = new StringBuilder("PUT_ALL ");
for (Object key : entries.keySet()) {
sb.append(key).append(", ");
}
log.trace(sb.toString());
}
boolean startedTx = startTxAndLock(entries.keySet());
if (preferAsync) {
Map<K, Future<V>> futures = new HashMap<K, Future<V>>(entries.size());
for (Map.Entry<K, V> entry : entries.entrySet()) {
futures.put(entry.getKey(), impl.putAsync(entry.getKey(), entry.getValue()));
}
for (Map.Entry<K, Future<V>> entry : futures.entrySet()) {
try {
entry.getValue().get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} else {
impl.putAll(entries);
}
stopTx(startedTx);
}
@Override
public void removeAll(Set<K> keys) {
if (trace) {
StringBuilder sb = new StringBuilder("REMOVE_ALL ");
for (Object key : keys) {
sb.append(key).append(", ");
}
log.trace(sb.toString());
}
boolean startedTx = startTxAndLock(keys);
Map<K, Future<V>> futures = new HashMap<K, Future<V>>(keys.size());
for (K key : keys) {
futures.put(key, impl.removeAsync(key));
}
for (Map.Entry<K, Future<V>> entry : futures.entrySet()) {
try {
entry.getValue().get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
stopTx(startedTx);
}
private boolean startTxAndLock(Set<K> keys) {
boolean shouldStopTransactionHere = false;
try {
if (service.isExplicitLocking(impl)) {
if (tm.getStatus() == Status.STATUS_NO_TRANSACTION) {
shouldStopTransactionHere = true;
tm.begin();
}
impl.lock(keys);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return shouldStopTransactionHere;
}
private void stopTx(boolean startedTx) {
if (startedTx) {
try {
tm.commit();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public AdvancedCache getAdvancedCache() {
return impl;
}
}
}