Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.spy.memcached.MemcachedClient Maven / Gradle / Ivy
Go to download
Amazon ElastiCache Cluster Client is an enhanced Java library to connect to ElastiCache clusters. This client library has been built upon Spymemcached and is released under the Amazon Software License.
package net.spy.memcached;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.AuthThreadMonitor;
import net.spy.memcached.compat.SpyObject;
import net.spy.memcached.config.ClusterConfiguration;
import net.spy.memcached.ConfigurationPoller;
import net.spy.memcached.config.NodeEndPoint;
import net.spy.memcached.internal.BulkFuture;
import net.spy.memcached.internal.BulkGetFuture;
import net.spy.memcached.internal.GetConfigFuture;
import net.spy.memcached.internal.GetFuture;
import net.spy.memcached.internal.OperationFuture;
import net.spy.memcached.internal.SingleElementInfiniteIterator;
import net.spy.memcached.ops.CASOperationStatus;
import net.spy.memcached.ops.CancelledOperationStatus;
import net.spy.memcached.ops.ConcatenationType;
import net.spy.memcached.ops.ConfigurationType;
import net.spy.memcached.ops.DeleteConfigOperation;
import net.spy.memcached.ops.DeleteOperation;
import net.spy.memcached.ops.GetAndTouchOperation;
import net.spy.memcached.ops.GetConfigOperation;
import net.spy.memcached.ops.GetOperation;
import net.spy.memcached.ops.GetsOperation;
import net.spy.memcached.ops.Mutator;
import net.spy.memcached.ops.Operation;
import net.spy.memcached.ops.OperationCallback;
import net.spy.memcached.ops.OperationErrorType;
import net.spy.memcached.ops.OperationException;
import net.spy.memcached.ops.OperationState;
import net.spy.memcached.ops.OperationStatus;
import net.spy.memcached.ops.StatsOperation;
import net.spy.memcached.ops.StatusCode;
import net.spy.memcached.ops.StoreOperation;
import net.spy.memcached.ops.StoreType;
import net.spy.memcached.ops.TimedOutOperationStatus;
import net.spy.memcached.protocol.binary.BinaryOperationFactory;
import net.spy.memcached.transcoders.SerializingTranscoder;
import net.spy.memcached.transcoders.TranscodeService;
import net.spy.memcached.transcoders.Transcoder;
import net.spy.memcached.util.StringUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
public class MemcachedClient extends SpyObject implements MemcachedClientIF ,
ConnectionObserver {
protected final ClientMode clientMode;
protected volatile boolean shuttingDown;
protected final long operationTimeout;
protected MemcachedConnection mconn;
protected final OperationFactory opFact;
protected final Transcoder transcoder;
protected final TranscodeService tcService;
protected final AuthDescriptor authDescriptor;
protected final ConnectionFactory connFactory;
protected final AuthThreadMonitor authMonitor = new AuthThreadMonitor();
protected final ExecutorService executorService;
private NodeEndPoint configurationNode;
private boolean isConfigurationProtocolSupported = true ;
private boolean isConfigurationInitialized = false ;
private Transcoder configTranscoder = new SerializingTranscoder();
private ConfigurationPoller configPoller;
public MemcachedClient (InetSocketAddress... addrs) throws IOException {
this (null , Arrays.asList(addrs), true );
}
public MemcachedClient (List addrs) throws IOException {
this (null , addrs, true );
}
public MemcachedClient (ConnectionFactory cf, List addrs) throws IOException {
this (cf, addrs, cf != null && cf.getClientMode() == ClientMode.Unset);
}
private MemcachedClient (ConnectionFactory cf, List addrs, boolean determineClientMode) throws IOException {
if (addrs == null ) {
throw new NullPointerException("Server list required" );
}
if (addrs.isEmpty()) {
throw new IllegalArgumentException("You must have at least one server to"
+ " connect to" );
}
if (determineClientMode){
boolean isClientModeDetermined = false ;
if (addrs.size() == 1 ){
if (addrs.get(0 ) == null ){
throw new NullPointerException("Socket address is null" );
}
String hostName = addrs.get(0 ).getHostName();
if (hostName != null && hostName.contains(".cfg." )){
cf = updateClientMode(cf, ClientMode.Dynamic);
isClientModeDetermined = true ;
}
}
if (!isClientModeDetermined) {
cf = updateClientMode(cf, ClientMode.Static);
isClientModeDetermined = true ;
}
}
if (cf == null ) {
throw new NullPointerException("Connection factory required" );
}
if (cf.getOperationTimeout() <= 0 ) {
throw new IllegalArgumentException("Operation timeout must be positive." );
}
if (cf.getClientMode() == ClientMode.Dynamic && addrs.size() > 1 ){
throw new IllegalArgumentException("Only one configuration endpoint is valid with dynamic client mode." );
}
connFactory = cf;
clientMode = cf.getClientMode();
tcService = new TranscodeService(cf.isDaemon());
transcoder = cf.getDefaultTranscoder();
opFact = cf.getOperationFactory();
assert opFact != null : "Connection factory failed to make op factory" ;
operationTimeout = cf.getOperationTimeout();
authDescriptor = cf.getAuthDescriptor();
executorService = cf.getListenerExecutorService();
if (clientMode == ClientMode.Dynamic){
initializeClientUsingConfigEndPoint(cf, addrs.get(0 ));
} else {
setupConnection(cf, addrs);
}
if (authDescriptor != null ) {
addObserver(this );
}
}
private ConnectionFactory updateClientMode (ConnectionFactory f, ClientMode mode) {
if (f == null ) {
f = new DefaultConnectionFactory(mode);
} else {
f.setClientMode(mode);
}
return f;
}
private void initializeClientUsingConfigEndPoint (ConnectionFactory cf, InetSocketAddress configurationEndPoint)
throws IOException {
configurationNode = new NodeEndPoint(configurationEndPoint.getHostName(), configurationEndPoint.getPort());
setupConnection(cf, Collections.singletonList(configurationEndPoint));
boolean checkKey = false ;
String configResult = null ;
try {
try {
configResult = (String)this .getConfig(configurationEndPoint, ConfigurationType.CLUSTER, configTranscoder);
}catch (OperationNotSupportedException e){
checkKey = true ;
}
if (checkKey || configResult == null || configResult.trim().isEmpty()){
configResult = (String)this .get(configurationEndPoint, ConfigurationType.CLUSTER.getValueWithNameSpace(), configTranscoder);
if (configResult != null && ! configResult.trim().isEmpty()){
isConfigurationProtocolSupported = false ;
}
}
if (configResult != null && ! configResult.trim().isEmpty()){
ClusterConfiguration clusterConfiguration = AddrUtil.parseClusterTypeConfiguration(configResult);
mconn.notifyUpdate(clusterConfiguration);
mconn.waitForInitialConfigApplied();
isConfigurationInitialized = true ;
}
}catch (OperationTimeoutException e){
getLogger().warn("Configuration endpoint timed out for config call. Leaving the initialization work to configuration poller." );
}
configPoller = new ConfigurationPoller(this , cf.getDynamicModePollingInterval(), cf.isDaemon());
configPoller.subscribeForClusterConfiguration(mconn);
}
private void setupConnection (ConnectionFactory cf, List addrs)
throws IOException {
mconn = cf.createConnection(addrs);
assert mconn != null : "Connection factory failed to make a connection" ;
}
public NodeEndPoint getConfigurationNode () {
return configurationNode;
}
@Override
public Collection getAvailableServers () {
ArrayList rv = new ArrayList();
for (MemcachedNode node : mconn.getLocator().getAll()) {
if (node.isActive()) {
rv.add(node.getSocketAddress());
}
}
return rv;
}
public Collection getAvailableNodeEndPoints () {
ArrayList rv = new ArrayList();
for (MemcachedNode node : mconn.getLocator().getAll()) {
if (node.isActive()) {
rv.add(node.getNodeEndPoint());
}
}
return rv;
}
public Collection getAllNodeEndPoints () {
ArrayList rv = new ArrayList();
for (MemcachedNode node : mconn.getLocator().getAll()) {
rv.add(node.getNodeEndPoint());
}
return rv;
}
@Override
public Collection getUnavailableServers () {
ArrayList rv = new ArrayList();
for (MemcachedNode node : mconn.getLocator().getAll()) {
if (!node.isActive()) {
rv.add(node.getSocketAddress());
}
}
return rv;
}
@Override
public NodeLocator getNodeLocator () {
return mconn.getLocator().getReadonlyCopy();
}
@Override
public Transcoder getTranscoder () {
return transcoder;
}
@Override
public CountDownLatch broadcastOp (final BroadcastOpFactory of) {
return broadcastOp(of, mconn.getLocator().getAll(), true );
}
@Override
public CountDownLatch broadcastOp (final BroadcastOpFactory of,
Collection nodes) {
return broadcastOp(of, nodes, true );
}
private CountDownLatch broadcastOp (BroadcastOpFactory of,
Collection nodes, boolean checkShuttingDown) {
checkState();
if (checkShuttingDown && shuttingDown) {
throw new IllegalStateException("Shutting down" );
}
return mconn.broadcastOperation(of, nodes);
}
private OperationFuture asyncStore (StoreType storeType,
String key, int exp, T value, Transcoder tc) {
CachedData co = tc.encode(value);
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv =
new OperationFuture(key, latch, operationTimeout,
executorService);
Operation op = opFact.store(storeType, key, co.getFlags(), exp,
co.getData(), new StoreOperation.Callback() {
@Override
public void receivedStatus (OperationStatus val) {
rv.set(val.isSuccess(), val);
}
@Override
public void gotData (String key, long cas) {
rv.setCas(cas);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
private OperationFuture asyncStore (StoreType storeType, String key,
int exp, Object value) {
return asyncStore(storeType, key, exp, value, transcoder);
}
private OperationFuture asyncCat (ConcatenationType catType,
long cas, String key, T value, Transcoder tc) {
CachedData co = tc.encode(value);
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv = new OperationFuture(key,
latch, operationTimeout, executorService);
Operation op = opFact.cat(catType, cas, key, co.getData(),
new OperationCallback() {
@Override
public void receivedStatus (OperationStatus val) {
rv.set(val.isSuccess(), val);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
@Override
public OperationFuture touch (final String key, final int exp) {
return touch(key, exp, transcoder);
}
@Override
public OperationFuture touch (final String key, final int exp,
final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv =
new OperationFuture(key, latch, operationTimeout,
executorService);
Operation op = opFact.touch(key, exp, new OperationCallback() {
@Override
public void receivedStatus (OperationStatus status) {
rv.set(status.isSuccess(), status);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
@Override
public OperationFuture append (long cas, String key, Object val) {
return append(cas, key, val, transcoder);
}
@Override
public OperationFuture append (String key, Object val) {
return append(0 , key, val, transcoder);
}
@Override
public OperationFuture append (long cas, String key, T val,
Transcoder tc) {
return asyncCat(ConcatenationType.append, cas, key, val, tc);
}
@Override
public OperationFuture append (String key, T val,
Transcoder tc) {
return asyncCat(ConcatenationType.append, 0 , key, val, tc);
}
@Override
public OperationFuture prepend (long cas, String key, Object val) {
return prepend(cas, key, val, transcoder);
}
@Override
public OperationFuture prepend (String key, Object val) {
return prepend(0 , key, val, transcoder);
}
@Override
public OperationFuture prepend (long cas, String key, T val,
Transcoder tc) {
return asyncCat(ConcatenationType.prepend, cas, key, val, tc);
}
@Override
public OperationFuture prepend (String key, T val,
Transcoder tc) {
return asyncCat(ConcatenationType.prepend, 0 , key, val, tc);
}
@Override
public OperationFuture
asyncCAS (String key, long casId, T value, Transcoder tc) {
return asyncCAS(key, casId, 0 , value, tc);
}
@Override
public OperationFuture
asyncCAS (String key, long casId, int exp, T value, Transcoder tc) {
CachedData co = tc.encode(value);
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv =
new OperationFuture(key, latch, operationTimeout,
executorService);
Operation op = opFact.cas(StoreType.set, key, casId, co.getFlags(), exp,
co.getData(), new StoreOperation.Callback() {
@Override
public void receivedStatus (OperationStatus val) {
if (val instanceof CASOperationStatus) {
rv.set(((CASOperationStatus) val).getCASResponse(), val);
} else if (val instanceof CancelledOperationStatus) {
getLogger().debug("CAS operation cancelled" );
} else if (val instanceof TimedOutOperationStatus) {
getLogger().debug("CAS operation timed out" );
} else {
throw new RuntimeException("Unhandled state: " + val);
}
}
@Override
public void gotData (String key, long cas) {
rv.setCas(cas);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
@Override
public OperationFuture
asyncCAS (String key, long casId, Object value) {
return asyncCAS(key, casId, value, transcoder);
}
@Override
public OperationFuture
asyncCAS (String key, long casId, int exp, Object value) {
return asyncCAS(key, casId, exp, value, transcoder);
}
@Override
public CASResponse cas (String key, long casId, T value,
Transcoder tc) {
return cas(key, casId, 0 , value, tc);
}
@Override
public CASResponse cas (String key, long casId, int exp, T value,
Transcoder tc) {
CASResponse casr;
try {
OperationFuture casOp = asyncCAS(key,
casId, exp, value, tc);
casr = casOp.get(operationTimeout,
TimeUnit.MILLISECONDS);
return casr;
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for value" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Exception waiting for value" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for value: "
+ buildTimeoutMessage(operationTimeout, TimeUnit.MILLISECONDS), e);
}
}
@Override
public CASResponse cas (String key, long casId, Object value) {
return cas(key, casId, value, transcoder);
}
@Override
public CASResponse cas (String key, long casId, int exp, Object value) {
return cas(key, casId, exp, value, transcoder);
}
@Override
public OperationFuture add (String key, int exp, T o,
Transcoder tc) {
return asyncStore(StoreType.add, key, exp, o, tc);
}
@Override
public OperationFuture add (String key, int exp, Object o) {
return asyncStore(StoreType.add, key, exp, o, transcoder);
}
@Override
public OperationFuture set (String key, int exp, T o,
Transcoder tc) {
return asyncStore(StoreType.set, key, exp, o, tc);
}
@Override
public OperationFuture set (String key, int exp, Object o) {
return asyncStore(StoreType.set, key, exp, o, transcoder);
}
@Override
public OperationFuture replace (String key, int exp, T o,
Transcoder tc) {
return asyncStore(StoreType.replace, key, exp, o, tc);
}
@Override
public OperationFuture replace (String key, int exp, Object o) {
return asyncStore(StoreType.replace, key, exp, o, transcoder);
}
@Override
public GetFuture asyncGet (final String key, final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final GetFuture rv = new GetFuture(latch, operationTimeout, key,
executorService);
Operation op = opFact.get(key, new GetOperation.Callback() {
private Future val;
@Override
public void receivedStatus (OperationStatus status) {
rv.set(val, status);
}
@Override
public void gotData (String k, int flags, byte [] data) {
assert key.equals(k) : "Wrong key returned" ;
val =
tcService.decode(tc, new CachedData(flags, data, tc.getMaxSize()));
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
T get (InetSocketAddress sa, final String key, final Transcoder tc) {
try {
return asyncGet(sa, key, tc).get(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for value" , e);
} catch (ExecutionException e) {
throw new RuntimeException("Exception waiting for value" , e);
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for value" , e);
}
}
GetFuture asyncGet (InetSocketAddress sa, final String key, final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final GetFuture rv = new GetFuture(latch, operationTimeout, key, executorService);
Operation op = opFact.get(key, new GetOperation.Callback() {
private Future val = null ;
public void receivedStatus (OperationStatus status) {
rv.set(val, status);
}
public void gotData (String k, int flags, byte [] data) {
assert key.equals(k) : "Wrong key returned" ;
val =
tcService.decode(tc, new CachedData(flags, data, transcoder.getMaxSize()));
}
public void complete () {
latch.countDown();
}
});
rv.setOperation(op);
mconn.enqueueOperation(sa, op);
return rv;
}
@Override
public GetFuture asyncGet (final String key) {
return asyncGet(key, transcoder);
}
@Override
public OperationFuture> asyncGets(final String key,
final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture> rv =
new OperationFuture>(key, latch, operationTimeout,
executorService);
Operation op = opFact.gets(key, new GetsOperation.Callback() {
private CASValue val;
@Override
public void receivedStatus (OperationStatus status) {
rv.set(val, status);
}
@Override
public void gotData (String k, int flags, long cas, byte [] data) {
assert key.equals(k) : "Wrong key returned" ;
val =
new CASValue(cas, tc.decode(new CachedData(flags, data,
tc.getMaxSize())));
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
@Override
public OperationFuture> asyncGets(final String key) {
return asyncGets(key, transcoder);
}
@Override
public CASValue gets (String key, Transcoder tc) {
try {
return asyncGets(key, tc).get(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for value" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Exception waiting for value" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for value" , e);
}
}
@Override
public CASValue getAndTouch (String key, int exp, Transcoder tc) {
try {
return asyncGetAndTouch(key, exp, tc).get(operationTimeout,
TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for value" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Exception waiting for value" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for value" , e);
}
}
@Override
public CASValue getAndTouch (String key, int exp) {
return getAndTouch(key, exp, transcoder);
}
@Override
public CASValue gets (String key) {
return gets(key, transcoder);
}
@Override
public T get (String key, Transcoder tc) {
try {
return asyncGet(key, tc).get(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for value" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Exception waiting for value" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for value: "
+ buildTimeoutMessage(operationTimeout, TimeUnit.MILLISECONDS), e);
}
}
@Override
public Object get (String key) {
return get(key, transcoder);
}
@Override
public BulkFuture> asyncGetBulk(Iterator keyIter,
Iterator> tcIter) {
final Map> m = new ConcurrentHashMap>();
final Map> tcMap =
new HashMap>();
final Map> chunks =
new HashMap>();
final NodeLocator locator = mconn.getLocator();
while (keyIter.hasNext() && tcIter.hasNext()) {
String key = keyIter.next();
tcMap.put(key, tcIter.next());
StringUtils.validateKey(key, opFact instanceof BinaryOperationFactory);
final MemcachedNode primaryNode = locator.getPrimary(key);
MemcachedNode node = null ;
if (primaryNode.isActive()) {
node = primaryNode;
} else {
for (Iterator i = locator.getSequence(key); node == null
&& i.hasNext();) {
MemcachedNode n = i.next();
if (n.isActive()) {
node = n;
}
}
if (node == null ) {
node = primaryNode;
}
}
assert node != null : "Didn't find a node for " + key;
Collection ks = chunks.get(node);
if (ks == null ) {
ks = new ArrayList();
chunks.put(node, ks);
}
ks.add(key);
}
final AtomicInteger pendingChunks = new AtomicInteger(chunks.size());
int initialLatchCount = chunks.isEmpty() ? 0 : 1 ;
final CountDownLatch latch = new CountDownLatch(initialLatchCount);
final Collection ops = new ArrayList(chunks.size());
final BulkGetFuture rv = new BulkGetFuture(m, ops, latch, executorService);
GetOperation.Callback cb = new GetOperation.Callback() {
@Override
@SuppressWarnings ("synthetic-access" )
public void receivedStatus (OperationStatus status) {
if (status.getStatusCode() == StatusCode.ERR_NOT_MY_VBUCKET) {
pendingChunks.addAndGet(Integer.parseInt(status.getMessage()));
}
rv.setStatus(status);
}
@Override
public void gotData (String k, int flags, byte [] data) {
Transcoder tc = tcMap.get(k);
m.put(k,
tcService.decode(tc, new CachedData(flags, data, tc.getMaxSize())));
}
@Override
public void complete () {
if (pendingChunks.decrementAndGet() <= 0 ) {
latch.countDown();
rv.signalComplete();
}
}
};
final Map mops =
new HashMap();
for (Map.Entry> me : chunks.entrySet()) {
Operation op = opFact.get(me.getValue(), cb);
mops.put(me.getKey(), op);
ops.add(op);
}
assert mops.size() == chunks.size();
mconn.checkState();
mconn.addOperations(mops);
return rv;
}
@Override
public BulkFuture> asyncGetBulk(Collection keys,
Iterator> tcIter) {
return asyncGetBulk(keys.iterator(), tcIter);
}
@Override
public BulkFuture> asyncGetBulk(Iterator keyIter,
Transcoder tc) {
return asyncGetBulk(keyIter,
new SingleElementInfiniteIterator>(tc));
}
@Override
public BulkFuture> asyncGetBulk(Collection keys,
Transcoder tc) {
return asyncGetBulk(keys, new SingleElementInfiniteIterator>(
tc));
}
@Override
public BulkFuture> asyncGetBulk(
Iterator keyIter) {
return asyncGetBulk(keyIter, transcoder);
}
@Override
public BulkFuture> asyncGetBulk(Collection keys) {
return asyncGetBulk(keys, transcoder);
}
@Override
public BulkFuture> asyncGetBulk(Transcoder tc,
String... keys) {
return asyncGetBulk(Arrays.asList(keys), tc);
}
@Override
public BulkFuture> asyncGetBulk(String... keys) {
return asyncGetBulk(Arrays.asList(keys), transcoder);
}
@Override
public OperationFuture> asyncGetAndTouch(final String key,
final int exp) {
return asyncGetAndTouch(key, exp, transcoder);
}
@Override
public OperationFuture> asyncGetAndTouch(final String key,
final int exp, final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture> rv = new OperationFuture>(
key, latch, operationTimeout, executorService);
Operation op = opFact.getAndTouch(key, exp,
new GetAndTouchOperation.Callback() {
private CASValue val;
@Override
public void receivedStatus (OperationStatus status) {
rv.set(val, status);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
@Override
public void gotData (String k, int flags, long cas, byte [] data) {
assert k.equals(key) : "Wrong key returned" ;
val =
new CASValue(cas, tc.decode(new CachedData(flags, data,
tc.getMaxSize())));
}
});
rv.setOperation(op);
enqueueOperation(key, op);
return rv;
}
@Override
public Map getBulk (Iterator keyIter,
Transcoder tc) {
try {
return asyncGetBulk(keyIter, tc).get(operationTimeout,
TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted getting bulk values" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Exception waiting for bulk values" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for bulk values: "
+ buildTimeoutMessage(operationTimeout, TimeUnit.MILLISECONDS), e);
}
}
@Override
public Map getBulk (Iterator keyIter) {
return getBulk(keyIter, transcoder);
}
@Override
public Map getBulk (Collection keys,
Transcoder tc) {
return getBulk(keys.iterator(), tc);
}
@Override
public Map getBulk (Collection keys) {
return getBulk(keys, transcoder);
}
@Override
public Map getBulk (Transcoder tc, String... keys) {
return getBulk(Arrays.asList(keys), tc);
}
@Override
public Map getBulk (String... keys) {
return getBulk(Arrays.asList(keys), transcoder);
}
private void enqueueOperation (String key, Operation op) {
checkState();
mconn.enqueueOperation(key, op);
}
private void checkState () {
if (clientMode == ClientMode.Dynamic && !isConfigurationInitialized) {
throw new IllegalStateException("Client is not initialized" );
}
}
public Object getConfig (InetSocketAddress addr, ConfigurationType type) {
return getConfig(addr, type, transcoder);
}
public T getConfig (InetSocketAddress addr, ConfigurationType type, Transcoder tc) {
try {
return asyncGetConfig(addr, type, tc).get(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for config" , e);
} catch (OperationNotSupportedException e){
throw e;
} catch (ExecutionException e) {
if (e.getCause() instanceof OperationException){
OperationException exp = (OperationException)e.getCause();
if (OperationErrorType.GENERAL.equals(exp.getType())){
throw new OperationNotSupportedException("This version of getConfig command is not supported." );
}
}
throw new RuntimeException("Exception waiting for config" , e);
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting for config" , e);
}
}
public GetConfigFuture asyncGetConfig (InetSocketAddress addr, final ConfigurationType type, final Transcoder tc) {
final CountDownLatch latch = new CountDownLatch(1 );
final GetConfigFuture rv = new GetConfigFuture(latch, operationTimeout, type, executorService);
Operation op = opFact.getConfig(type, new GetConfigOperation.Callback() {
private Future val = null ;
public void receivedStatus (OperationStatus status) {
rv.set(val, status);
}
public void gotData (ConfigurationType configurationType, int flags, byte [] data) {
assert type.equals(configurationType) : "Wrong type returned" ;
val =
tcService.decode(tc, new CachedData(flags, data, tc.getMaxSize()));
}
public void complete () {
latch.countDown();
}
});
rv.setOperation(op);
mconn.enqueueOperation(addr, op);
return rv;
}
public OperationFuture setConfig (InetSocketAddress addr, ConfigurationType configurationType, Object o) {
return asyncSetConfig(addr, configurationType, o, transcoder);
}
public OperationFuture setConfig (InetSocketAddress addr, ConfigurationType configurationType, Object o, Transcoder tc) {
return asyncSetConfig(addr, configurationType, o, transcoder);
}
private OperationFuture asyncSetConfig (InetSocketAddress addr,
ConfigurationType configurationType, T value, Transcoder tc) {
CachedData co = tc.encode(value);
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv =
new OperationFuture(configurationType.getValue(), latch, operationTimeout, executorService);
Operation op = opFact.setConfig(configurationType, co.getFlags(), co.getData(),
new OperationCallback() {
public void receivedStatus (OperationStatus val) {
rv.set(val.isSuccess(), val);
}
public void complete () {
latch.countDown();
}
});
rv.setOperation(op);
mconn.enqueueOperation(addr, op);
return rv;
}
public OperationFuture deleteConfig (InetSocketAddress addr, ConfigurationType configurationType) {
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv = new OperationFuture(configurationType.getValue(),
latch, operationTimeout, executorService);
DeleteConfigOperation op = opFact.deleteConfig(configurationType, new OperationCallback() {
public void receivedStatus (OperationStatus s) {
rv.set(s.isSuccess(), s);
}
public void complete () {
latch.countDown();
}
});
rv.setOperation(op);
mconn.enqueueOperation(addr, op);
return rv;
}
@Override
public Map getVersions () {
final Map rv =
new ConcurrentHashMap();
CountDownLatch blatch = broadcastOp(new BroadcastOpFactory() {
@Override
public Operation newOp (final MemcachedNode n,
final CountDownLatch latch) {
final SocketAddress sa = n.getSocketAddress();
return opFact.version(new OperationCallback() {
@Override
public void receivedStatus (OperationStatus s) {
rv.put(sa, s.getMessage());
}
@Override
public void complete () {
latch.countDown();
}
});
}
});
try {
blatch.await(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for versions" , e);
}
return rv;
}
@Override
public Map> getStats() {
return getStats(null );
}
@Override
public Map> getStats(final String arg) {
final Map> rv =
new HashMap>();
CountDownLatch blatch = broadcastOp(new BroadcastOpFactory() {
@Override
public Operation newOp (final MemcachedNode n,
final CountDownLatch latch) {
final SocketAddress sa = n.getSocketAddress();
rv.put(sa, new HashMap());
return opFact.stats(arg, new StatsOperation.Callback() {
@Override
public void gotStat (String name, String val) {
rv.get(sa).put(name, val);
}
@Override
@SuppressWarnings ("synthetic-access" )
public void receivedStatus (OperationStatus status) {
if (!status.isSuccess()) {
getLogger().warn("Unsuccessful stat fetch: %s" , status);
}
}
@Override
public void complete () {
latch.countDown();
}
});
}
});
try {
blatch.await(operationTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for stats" , e);
}
return rv;
}
private long mutate (Mutator m, String key, long by, long def, int exp) {
final AtomicLong rv = new AtomicLong();
final CountDownLatch latch = new CountDownLatch(1 );
enqueueOperation(key, opFact.mutate(m, key, by, def, exp,
new OperationCallback() {
@Override
public void receivedStatus (OperationStatus s) {
rv.set(new Long(s.isSuccess() ? s.getMessage() : "-1" ));
}
@Override
public void complete () {
latch.countDown();
}
}));
try {
if (!latch.await(operationTimeout, TimeUnit.MILLISECONDS)) {
throw new OperationTimeoutException("Mutate operation timed out,"
+ "unable to modify counter [" + key + ']' );
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted" , e);
}
getLogger().debug("Mutation returned %s" , rv);
return rv.get();
}
@Override
public long incr (String key, long by) {
return mutate(Mutator.incr, key, by, 0 , -1 );
}
@Override
public long incr (String key, int by) {
return mutate(Mutator.incr, key, by, 0 , -1 );
}
@Override
public long decr (String key, long by) {
return mutate(Mutator.decr, key, by, 0 , -1 );
}
@Override
public long decr (String key, int by) {
return mutate(Mutator.decr, key, by, 0 , -1 );
}
@Override
public long incr (String key, long by, long def, int exp) {
return mutateWithDefault(Mutator.incr, key, by, def, exp);
}
@Override
public long incr (String key, int by, long def, int exp) {
return mutateWithDefault(Mutator.incr, key, by, def, exp);
}
@Override
public long decr (String key, long by, long def, int exp) {
return mutateWithDefault(Mutator.decr, key, by, def, exp);
}
@Override
public long decr (String key, int by, long def, int exp) {
return mutateWithDefault(Mutator.decr, key, by, def, exp);
}
private long mutateWithDefault (Mutator t, String key, long by, long def,
int exp) {
long rv = mutate(t, key, by, def, exp);
if (rv == -1 ) {
Future f = asyncStore(StoreType.add, key, exp,
String.valueOf(def));
try {
if (f.get(operationTimeout, TimeUnit.MILLISECONDS)) {
rv = def;
} else {
rv = mutate(t, key, by, 0 , exp);
assert rv != -1 : "Failed to mutate or init value" ;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting for store" , e);
} catch (ExecutionException e) {
if (e.getCause() instanceof CancellationException) {
throw (CancellationException) e.getCause();
} else {
throw new RuntimeException("Failed waiting for store" , e);
}
} catch (TimeoutException e) {
throw new OperationTimeoutException("Timeout waiting to mutate or init"
+ " value" + buildTimeoutMessage(operationTimeout,
TimeUnit.MILLISECONDS), e);
}
}
return rv;
}
private OperationFuture asyncMutate (Mutator m, String key, long by,
long def, int exp) {
if (!(opFact instanceof BinaryOperationFactory) && (def != 0 || exp != -1 )) {
throw new UnsupportedOperationException("Default value or expiration "
+ "time are not supported on the async mutate methods. Use either the "
+ "binary protocol or the sync variant." );
}
final CountDownLatch latch = new CountDownLatch(1 );
final OperationFuture rv =
new OperationFuture(key, latch, operationTimeout, executorService);
Operation op = opFact.mutate(m, key, by, def, exp,
new OperationCallback() {
@Override
public void receivedStatus (OperationStatus s) {
rv.set(new Long(s.isSuccess() ? s.getMessage() : "-1" ), s);
}
@Override
public void complete () {
latch.countDown();
rv.signalComplete();
}
});
enqueueOperation(key, op);
rv.setOperation(op);
return rv;
}
@Override
public OperationFuture asyncIncr (String key, long by) {
return asyncMutate(Mutator.incr, key, by, 0 , -1 );
}
@Override
public OperationFuture asyncIncr (String key, int by) {
return asyncMutate(Mutator.incr, key, by, 0 , -1 );
}
@Override
public OperationFuture asyncDecr (String key, long by) {
return asyncMutate(Mutator.decr, key, by, 0 , -1 );
}
@Override
public OperationFuture asyncDecr (String key, int by) {
return asyncMutate(Mutator.decr, key, by, 0 , -1 );
}
@Override
public OperationFuture asyncIncr (String key, long by, long def,
int exp) {
return asyncMutate(Mutator.incr, key, by, def, exp);
}
@Override
public OperationFuture asyncIncr (String key, int by, long def,
int exp) {
return asyncMutate(Mutator.incr, key, by, def, exp);
}
@Override
public OperationFuture asyncDecr (String key,