/** * Copyright 2016 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.dyno.memcache; /** * Dyno client for Memcached that uses the {@link RollingMemcachedConnectionPoolImpl} for managing connections to {@link MemcachedClient}s * with local zone aware based RR load balancing and fallbacks to the remote zones * * @author poberai * */ public class DynoMCacheClient { /**implements MemcachedClientIF { private final String cacheName; private final ConnectionPool<MemcachedClient> connPool; public DynoMCacheClient(String name, ConnectionPool<MemcachedClient> pool) { this.cacheName = name; this.connPool = pool; } private enum OpName { Add, Append, AsyncCas, AsyncDecr, AsyncGet, AsyncGetAndTouch, AsyncGets, AsyncIncr, Cas, Decr, Delete, Get, GetAndTouch, GetAsync, GetBulk, Gets, Incr, Prepend, Set, Touch } private abstract class BaseKeyOperation<T> implements Operation<MemcachedClient, T> { private final String key; private final OpName op; private BaseKeyOperation(final String k, final OpName o) { this.key = k; this.op = o; } @Override public String getName() { return op.name(); } @Override public String getKey() { return key; } } private abstract class BaseAsyncKeyOperation<T> implements AsyncOperation<MemcachedClient, T> { private final String key; private final OpName op; private BaseAsyncKeyOperation(final String k, final OpName o) { this.key = k; this.op = o; } @Override public String getName() { return op.name(); } @Override public String getKey() { return key; } } public String toString() { return this.cacheName; } public static class Builder { private String appName; private String clusterName; private ConnectionPoolConfigurationImpl cpConfig; public Builder(String name) { appName = name; } public Builder withDynomiteClusterName(String cluster) { clusterName = cluster; return this; } public Builder withConnectionPoolConfig(ConnectionPoolConfigurationImpl config) { cpConfig = config; return this; } public DynoMCacheClient build() { assert(appName != null); assert(clusterName != null); assert(cpConfig != null); // TODO: Add conn pool impl for MemcachedClient throw new RuntimeException("Dyno conn pool for Memcached Client NOT implemented. Coming soon."); } public static Builder withName(String name) { return new Builder(name); } } @Override public Collection<SocketAddress> getAvailableServers() { throw new RuntimeException("Not Implemented"); } @Override public Collection<SocketAddress> getUnavailableServers() { throw new RuntimeException("Not Implemented"); } @Override public Transcoder<Object> getTranscoder() { throw new RuntimeException("Not Implemented"); } @Override public NodeLocator getNodeLocator() { throw new RuntimeException("Not Implemented"); } @Override public Future<Boolean> append(final long cas, final String key, final Object val) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.append(cas, key, val)); } })); } @Override public Future<Boolean> append(final String key, final Object val) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.append(key, val)); } })); } @Override public <T> Future<Boolean> append(final long cas, final String key, final T val, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.append(cas, key, val)); } })); } @Override public <T> Future<Boolean> append(final String key, final T val, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.append(key, val)); } })); } @Override public Future<Boolean> prepend(final long cas, final String key, final Object val) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Prepend) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.prepend(cas, key, val)); } })); } @Override public Future<Boolean> prepend(final String key, final Object val) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Prepend) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.prepend(key, val)); } })); } @Override public <T> Future<Boolean> prepend(final long cas, final String key, final T val, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Prepend) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.prepend(cas, key, val)); } })); } @Override public <T> Future<Boolean> prepend(final String key, final T val, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Prepend) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.prepend(key, val, tc)); } })); } @Override public <T> Future<CASResponse> asyncCAS(final String key, final long casId, final T value, final Transcoder<T> tc) { return new DecoratingFuture<CASResponse>(connPool.executeAsync(new BaseAsyncKeyOperation<CASResponse>(key, OpName.AsyncCas) { @Override public ListenableFuture<CASResponse> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASResponse>(client.asyncCAS(key, casId, value, tc)); } })); } @Override public Future<CASResponse> asyncCAS(final String key, final long casId, final Object value) { return new DecoratingFuture<CASResponse>(connPool.executeAsync(new BaseAsyncKeyOperation<CASResponse>(key, OpName.AsyncCas) { @Override public ListenableFuture<CASResponse> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASResponse>(client.asyncCAS(key, casId, value)); } })); } @Override public Future<CASResponse> asyncCAS(final String key, final long casId, final int exp, final Object value) { return new DecoratingFuture<CASResponse>(connPool.executeAsync(new BaseAsyncKeyOperation<CASResponse>(key, OpName.Cas) { @Override public ListenableFuture<CASResponse> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASResponse>(client.asyncCAS(key, casId, exp, value)); } })); } @Override public <T> CASResponse cas(final String key, final long casId, final int exp, final T value, final Transcoder<T> tc) { return connPool.executeWithFailover(new BaseKeyOperation<CASResponse>(key, OpName.Cas) { @Override public CASResponse execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.cas(key, casId, exp, value, tc); } }).getResult(); } @Override public CASResponse cas(final String key, final long casId, final Object value) { return connPool.executeWithFailover(new BaseKeyOperation<CASResponse>(key, OpName.Cas) { @Override public CASResponse execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.cas(key, casId, value); } }).getResult(); } @Override public CASResponse cas(final String key, final long casId, final int exp, final Object value) { return connPool.executeWithFailover(new BaseKeyOperation<CASResponse>(key, OpName.Cas) { @Override public CASResponse execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.cas(key, casId, exp, value); } }).getResult(); } @Override public <T> Future<Boolean> add(final String key, final int exp, final T o, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Add) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.add(key, exp, o)); } })); } @Override public Future<Boolean> add(final String key, final int exp, final Object o) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Add) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.add(key, exp, o)); } })); } @Override public <T> Future<Boolean> set(final String key, final int exp, final T o, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Set) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.set(key, exp, o, tc)); } })); } @Override public Future<Boolean> set(final String key, final int exp, final Object o) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Set) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.set(key, exp, o)); } })); } @Override public <T> Future<Boolean> replace(final String key, final int exp, final T o, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.replace(key, exp, o, tc)); } })); } @Override public Future<Boolean> replace(final String key, final int exp, final Object o) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.replace(key, exp, o)); } })); } @Override public <T> Future<T> asyncGet(final String key, final Transcoder<T> tc) { return new DecoratingFuture<T>(connPool.executeAsync(new BaseAsyncKeyOperation<T>(key, OpName.AsyncGet) { @Override public ListenableFuture<T> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<T>(client.asyncGet(key, tc)); } })); } @Override public Future<Object> asyncGet(final String key) { return new DecoratingFuture<Object>(connPool.executeAsync(new BaseAsyncKeyOperation<Object>(key, OpName.AsyncGet) { @Override public ListenableFuture<Object> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Object>(client.asyncGet(key)); } })); } @Override public Future<CASValue<Object>> asyncGetAndTouch(final String key, final int exp) { return new DecoratingFuture<CASValue<Object>>(connPool.executeAsync(new BaseAsyncKeyOperation<CASValue<Object>>(key, OpName.AsyncGetAndTouch) { @Override public ListenableFuture<CASValue<Object>> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASValue<Object>>(client.asyncGets(key)); } })); } @Override public <T> Future<CASValue<T>> asyncGetAndTouch(final String key, final int exp, final Transcoder<T> tc) { return new DecoratingFuture<CASValue<T>>(connPool.executeAsync(new BaseAsyncKeyOperation<CASValue<T>>(key, OpName.AsyncGetAndTouch) { @Override public ListenableFuture<CASValue<T>> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASValue<T>>(client.asyncGetAndTouch(key, exp, tc)); } })); } @Override public <T> Future<CASValue<T>> asyncGets(final String key, final Transcoder<T> tc) { return new DecoratingFuture<CASValue<T>>(connPool.executeAsync(new BaseAsyncKeyOperation<CASValue<T>>(key, OpName.AsyncGets) { @Override public ListenableFuture<CASValue<T>> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASValue<T>>(client.asyncGets(key, tc)); } })); } @Override public Future<CASValue<Object>> asyncGets(final String key) { return new DecoratingFuture<CASValue<Object>>(connPool.executeAsync(new BaseAsyncKeyOperation<CASValue<Object>>(key, OpName.AsyncGets) { @Override public ListenableFuture<CASValue<Object>> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<CASValue<Object>>(client.asyncGets(key)); } })); } @Override public <T> CASValue<T> gets(final String key, final Transcoder<T> tc) { return connPool.executeWithFailover(new BaseKeyOperation<CASValue<T>>(key, OpName.Gets) { @Override public CASValue<T> execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.gets(key, tc); } }).getResult(); } @Override public CASValue<Object> gets(final String key) { return connPool.executeWithFailover(new BaseKeyOperation<CASValue<Object>>(key, OpName.Gets) { @Override public CASValue<Object> execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.gets(key); } }).getResult(); } @Override public <T> T get(final String key, final Transcoder<T> tc) { return connPool.executeWithFailover(new BaseKeyOperation<T>(key, OpName.Get) { @Override public T execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.get(key, tc); } }).getResult(); } @Override public <T> BulkFuture<Map<String, T>> asyncGetBulk(Iterator<String> keys, Iterator<Transcoder<T>> tcs) { throw new RuntimeException("Not Implemented"); } @Override public <T> BulkFuture<Map<String, T>> asyncGetBulk(Collection<String> keys, Iterator<Transcoder<T>> tcs) { throw new RuntimeException("Not Implemented"); } @Override public <T> BulkFuture<Map<String, T>> asyncGetBulk(Iterator<String> keys, Transcoder<T> tc) { throw new RuntimeException("Not Implemented"); } @Override public <T> BulkFuture<Map<String, T>> asyncGetBulk(Collection<String> keys, Transcoder<T> tc) { throw new RuntimeException("Not Implemented"); } @Override public BulkFuture<Map<String, Object>> asyncGetBulk(Iterator<String> keys) { throw new RuntimeException("Not Implemented"); } @Override public BulkFuture<Map<String, Object>> asyncGetBulk(Collection<String> keys) { throw new RuntimeException("Not Implemented"); } @Override public <T> BulkFuture<Map<String, T>> asyncGetBulk(Transcoder<T> tc, String... keys) { throw new RuntimeException("Not Implemented"); } @Override public BulkFuture<Map<String, Object>> asyncGetBulk(String... keys) { throw new RuntimeException("Not Implemented"); } @Override public <T> Map<String, T> getBulk(Iterator<String> keys, Transcoder<T> tc) { throw new RuntimeException("Not Implemented"); } @Override public Map<String, Object> getBulk(Iterator<String> keys) { throw new RuntimeException("Not Implemented"); } @Override public <T> Future<Boolean> touch(final String key, final int exp, final Transcoder<T> tc) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Touch) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.touch(key, exp, tc)); } })); } @Override public <T> Future<Boolean> touch(final String key, final int exp) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Append) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.touch(key, exp)); } })); } @Override public Map<SocketAddress, String> getVersions() { throw new RuntimeException("Not Implemented"); } @Override public Map<SocketAddress, Map<String, String>> getStats() { throw new RuntimeException("Not Implemented"); } @Override public Map<SocketAddress, Map<String, String>> getStats(String prefix) { throw new RuntimeException("Not Implemented"); } @Override public long incr(final String key, final long by) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by); } }).getResult(); } @Override public long incr(final String key, final int by) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by); } }).getResult(); } @Override public long decr(final String key, final long by) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.decr(key, by); } }).getResult(); } @Override public long decr(final String key, final int by) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.decr(key, by); } }).getResult(); } @Override public long incr(final String key, final long by, final long def, final int exp) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def, exp); } }).getResult(); } @Override public long incr(final String key, final int by, final long def, final int exp) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def, exp); } }).getResult(); } @Override public long decr(final String key, final long by, final long def, final int exp) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def, exp); } }).getResult(); } @Override public long decr(final String key, final int by, final long def, final int exp) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def, exp); } }).getResult(); } @Override public Future<Long> asyncIncr(final String key, final long by) { return new DecoratingFuture<Long>(connPool.executeAsync(new BaseAsyncKeyOperation<Long>(key, OpName.AsyncIncr) { @Override public ListenableFuture<Long> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Long>(client.asyncIncr(key, by)); } })); } @Override public Future<Long> asyncIncr(final String key, final int by) { return new DecoratingFuture<Long>(connPool.executeAsync(new BaseAsyncKeyOperation<Long>(key, OpName.AsyncIncr) { @Override public ListenableFuture<Long> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Long>(client.asyncIncr(key, by)); } })); } @Override public Future<Long> asyncDecr(final String key, final long by) { return new DecoratingFuture<Long>(connPool.executeAsync(new BaseAsyncKeyOperation<Long>(key, OpName.AsyncDecr) { @Override public ListenableFuture<Long> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Long>(client.asyncDecr(key, by)); } })); } @Override public Future<Long> asyncDecr(final String key, final int by) { return new DecoratingFuture<Long>(connPool.executeAsync(new BaseAsyncKeyOperation<Long>(key, OpName.AsyncDecr) { @Override public ListenableFuture<Long> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Long>(client.asyncDecr(key, by)); } })); } @Override public long incr(final String key, final long by, final long def) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def); } }).getResult(); } @Override public long incr(final String key, final int by, final long def) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Incr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.incr(key, by, def); } }).getResult(); } @Override public long decr(final String key, final long by, final long def) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.decr(key, by, def); } }).getResult(); } @Override public long decr(final String key, final int by, final long def) { return connPool.executeWithFailover(new BaseKeyOperation<Long>(key, OpName.Decr) { @Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.decr(key, by, def); } }).getResult(); } @Override public Future<Boolean> delete(final String key, final long cas) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Delete) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.delete(key, cas)); } })); } @Override public Future<Boolean> flush(int delay) { throw new RuntimeException("Not Implemented"); } @Override public Future<Boolean> flush() { throw new RuntimeException("Not Implemented"); } @Override public void shutdown() { throw new RuntimeException("Not Implemented"); } @Override public boolean shutdown(long timeout, TimeUnit unit) { throw new RuntimeException("Not Implemented"); } @Override public boolean waitForQueues(long timeout, TimeUnit unit) { throw new RuntimeException("Not Implemented"); } @Override public boolean addObserver(ConnectionObserver obs) { throw new RuntimeException("Not Implemented"); } @Override public boolean removeObserver(ConnectionObserver obs) { throw new RuntimeException("Not Implemented"); } @Override public Set<String> listSaslMechanisms() { throw new RuntimeException("Not Implemented"); } @Override public CASValue<Object> getAndTouch(final String key, final int exp) { return connPool.executeWithFailover(new BaseKeyOperation<CASValue<Object>>(key, OpName.GetAndTouch) { @Override public CASValue<Object> execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.getAndTouch(key, exp); } }).getResult(); } @Override public <T> CASValue<T> getAndTouch(final String key, final int exp, final Transcoder<T> tc) { return connPool.executeWithFailover(new BaseKeyOperation<CASValue<T>>(key, OpName.GetAndTouch) { @Override public CASValue<T> execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.getAndTouch(key, exp ,tc); } }).getResult(); } @Override public Object get(final String key) { return connPool.executeWithFailover(new BaseKeyOperation<Object>(key, OpName.Get) { @Override public Object execute(final MemcachedClient client, ConnectionContext state) throws DynoException { return client.get(key); } }).getResult(); } @Override public <T> Map<String, T> getBulk(Collection<String> keys, Transcoder<T> tc) { throw new RuntimeException("Not Implemented"); } @Override public Map<String, Object> getBulk(Collection<String> keys) { throw new RuntimeException("Not Implemented"); } @Override public <T> Map<String, T> getBulk(Transcoder<T> tc, String... keys) { throw new RuntimeException("Not Implemented"); } @Override public Map<String, Object> getBulk(String... keys) { throw new RuntimeException("Not Implemented"); } @Override public Future<Boolean> delete(final String key) { return new DecoratingFuture<Boolean>(connPool.executeAsync(new BaseAsyncKeyOperation<Boolean>(key, OpName.Delete) { @Override public ListenableFuture<Boolean> executeAsync(MemcachedClient client) throws DynoException { return new DecoratingListenableFuture<Boolean>(client.delete(key)); } })); } */ }