package org.radargun.service;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.infinispan.client.hotrod.RemoteCache;
import org.infinispan.client.hotrod.VersionedValue;
import org.radargun.logging.Log;
import org.radargun.logging.LogFactory;
import org.radargun.traits.BasicOperations;
import org.radargun.traits.BulkOperations;
import org.radargun.traits.ConditionalOperations;
import org.radargun.traits.TemporalOperations;
/**
* Implementation of the {@link BasicOperations} and {@link ConditionalOperations}
* through the HotRod protocol.
*
* @author Radim Vansa <rvansa@redhat.com>
*/
public class HotRodOperations implements BasicOperations, BulkOperations, ConditionalOperations, TemporalOperations {
protected static final Log log = LogFactory.getLog(HotRodOperations.class);
protected static final boolean trace = log.isTraceEnabled();
protected final InfinispanHotrodService service;
public HotRodOperations(InfinispanHotrodService service) {
this.service = service;
}
@Override
public <K, V> HotRodCache<K, V> getCache(String cacheName) {
if (cacheName == null) {
cacheName = service.cacheName;
}
if (cacheName == null) {
return new HotRodCache<>((RemoteCache<K, V>) service.managerNoReturn.getCache(false), (RemoteCache<K, V>) service.managerForceReturn.getCache(true));
} else {
return new HotRodCache<>((RemoteCache<K, V>) service.managerNoReturn.getCache(cacheName, false), (RemoteCache<K, V>) service.managerForceReturn.getCache(cacheName, true));
}
}
@Override
public <K, V> BulkOperations.Cache<K, V> getCache(String cacheName, boolean preferAsync) {
if (cacheName == null) {
cacheName = service.cacheName;
}
if (cacheName == null) {
return new HotRodBulkOperationsCache<>((RemoteCache<K,V>) service.managerNoReturn.getCache(false), (RemoteCache<K,V>) service.managerForceReturn.getCache(true), preferAsync);
} else {
return new HotRodBulkOperationsCache<>((RemoteCache<K,V>) service.managerNoReturn.getCache(cacheName, false), (RemoteCache<K,V>) service.managerForceReturn.getCache(cacheName, true), preferAsync);
}
}
protected class HotRodCache<K, V> implements BasicOperations.Cache<K, V>, ConditionalOperations.Cache<K, V>, TemporalOperations.Cache<K, V> {
protected final RemoteCache<K, V> noReturn;
protected final RemoteCache<K, V> forceReturn;
public HotRodCache(RemoteCache<K, V> noReturn, RemoteCache<K, V> forceReturn) {
this.noReturn = noReturn;
this.forceReturn = forceReturn;
}
@Override
public V get(K key) {
if (trace) log.tracef("GET cache=%s key=%s", noReturn.getName(), key);
// causes a warning on server, and Get always returns the value
return noReturn.get(key);
}
@Override
public boolean containsKey(K key) {
if (trace) log.tracef("CONTAINS cache=%s key=%s", forceReturn.getName(), key);
return forceReturn.containsKey(key);
}
@Override
public void put(K key, V value) {
if (trace) log.tracef("PUT cache=%s key=%s value=%s", noReturn.getName(), key, value);
noReturn.put(key, value);
}
@Override
public V getAndPut(K key, V value) {
if (trace) log.tracef("GET_AND_PUT cache=%s key=%s value=%s", forceReturn.getName(), key, value);
return forceReturn.put(key, value);
}
@Override
public boolean remove(K key) {
if (trace) log.tracef("REMOVE cache=%s key=%s", forceReturn.getName(), key);
return forceReturn.remove(key) != null;
}
@Override
public V getAndRemove(K key) {
if (trace) log.tracef("GET_AND_REMOVE cache=%s key=%s", forceReturn.getName(), key);
return forceReturn.remove(key);
}
@Override
public void clear() {
if (trace) log.trace("CLEAR " + noReturn.getName());
noReturn.clear();
}
@Override
public boolean putIfAbsent(K key, V value) {
if (trace) log.tracef("PUT_IF_ABSENT cache=%s key=%s value=%s", forceReturn.getName(), key, value);
return forceReturn.putIfAbsent(key, value) == null;
}
@Override
public boolean remove(K key, V oldValue) {
if (trace) log.tracef("REMOVE cache=%s key=%s value=%s", forceReturn.getName(), key, oldValue);
for (; ; ) {
VersionedValue<V> versioned = forceReturn.getVersioned(key);
if (oldValue == null || versioned == null) {
return false;
}
if (oldValue.equals(versioned.getValue())) {
if (forceReturn.removeWithVersion(key, versioned.getVersion())) {
return true;
}
if (trace) log.tracef("Remove with version %d failed", versioned.getVersion());
} else {
return false;
}
}
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
if (trace)
log.tracef("REPLACE cache=%s key=%s old=%s, new=%s", forceReturn.getName(), key, oldValue, newValue);
for (; ; ) {
VersionedValue<V> versioned = forceReturn.getVersioned(key);
if (oldValue == null || versioned == null) {
return false;
}
if (oldValue.equals(versioned.getValue())) {
if (forceReturn.replaceWithVersion(key, newValue, versioned.getVersion())) {
return true;
}
if (trace) log.tracef("Replace with version %d failed", versioned.getVersion());
} else {
return false;
}
}
}
@Override
public boolean replace(K key, V value) {
if (trace) log.tracef("REPLACE cache=%s key=%s value=%s", forceReturn.getName(), key, value);
return forceReturn.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", forceReturn.getName(), key, value);
return forceReturn.replace(key, value);
}
@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", noReturn.getName(), key, value, lifespan);
noReturn.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", forceReturn.getName(), key, value, lifespan);
return forceReturn.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", forceReturn.getName(), key, value, lifespan);
return forceReturn.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", noReturn.getName(), key, value, lifespan, maxIdleTime);
noReturn.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", forceReturn.getName(), key, value, lifespan, maxIdleTime);
return forceReturn.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_AND_MAXIDLE cache=%s key=%s value=%s lifespan=%s maxIdle=%s", forceReturn.getName(), key, value, lifespan, maxIdleTime);
return forceReturn.putIfAbsent(key, value, lifespan, TimeUnit.MILLISECONDS, maxIdleTime, TimeUnit.MILLISECONDS) == null;
}
}
protected class HotRodBulkOperationsCache<K, V> extends HotRodCache<K, V> implements BulkOperations.Cache<K, V> {
protected final boolean preferAsync;
public HotRodBulkOperationsCache(RemoteCache<K, V> noReturn, RemoteCache<K, V> forceReturn, boolean preferAsync) {
super(noReturn, forceReturn);
this.preferAsync = preferAsync;
}
@Override
public Map<K, V> getAll(Set<K> keys) {
if (trace) log.tracef("GET_ALL cache=%s keys=%s", forceReturn.getName(), keys);
Map<K, V> result = new HashMap<>(keys.size());
Map<K, Future<V>> futureMap = new HashMap<>(keys.size());
for (K key : keys) {
futureMap.put(key, forceReturn.getAsync(key));
}
for (Map.Entry<K, Future<V>> entry : futureMap.entrySet()) {
try {
V value = entry.getValue().get();
if (value != null) {
result.put(entry.getKey(), value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return result;
}
@Override
public void putAll(Map<K, V> entries) {
if (trace) log.tracef("PUT_ALL cache=%s keys=%s", noReturn.getName(), entries);
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(), noReturn.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 {
noReturn.putAll(entries);
}
}
@Override
public void removeAll(Set<K> keys) {
if (trace) log.tracef("REMOVE_ALL cache=%s keys=%s", forceReturn.getName(), keys);
if (preferAsync) {
Map<K, Future<V>> futureMap = new HashMap<>(keys.size());
for (K key : keys) {
futureMap.put(key, forceReturn.removeAsync(key));
}
for (Map.Entry<K, Future<V>> entry : futureMap.entrySet()) {
try {
entry.getValue().get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} else {
for (K key : keys) {
noReturn.remove(key);
}
}
}
}
}