/**
* 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 connPool;
public DynoMCacheClient(String name, ConnectionPool 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 implements Operation {
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 implements AsyncOperation {
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 getAvailableServers() {
throw new RuntimeException("Not Implemented");
}
@Override public Collection getUnavailableServers() {
throw new RuntimeException("Not Implemented");
}
@Override public Transcoder getTranscoder() {
throw new RuntimeException("Not Implemented");
}
@Override public NodeLocator getNodeLocator() {
throw new RuntimeException("Not Implemented");
}
@Override public Future append(final long cas, final String key, final Object val) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.append(cas, key, val));
}
}));
}
@Override public Future append(final String key, final Object val) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.append(key, val));
}
}));
}
@Override public Future append(final long cas, final String key, final T val, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.append(cas, key, val));
}
}));
}
@Override public Future append(final String key, final T val, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.append(key, val));
}
}));
}
@Override public Future prepend(final long cas, final String key, final Object val) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Prepend) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.prepend(cas, key, val));
}
}));
}
@Override public Future prepend(final String key, final Object val) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Prepend) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.prepend(key, val));
}
}));
}
@Override public Future prepend(final long cas, final String key, final T val, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Prepend) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.prepend(cas, key, val));
}
}));
}
@Override public Future prepend(final String key, final T val, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Prepend) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.prepend(key, val, tc));
}
}));
}
@Override public Future asyncCAS(final String key, final long casId, final T value, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncCas) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncCAS(key, casId, value, tc));
}
}));
}
@Override public Future asyncCAS(final String key, final long casId, final Object value) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncCas) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncCAS(key, casId, value));
}
}));
}
@Override public Future asyncCAS(final String key, final long casId, final int exp, final Object value) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Cas) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncCAS(key, casId, exp, value));
}
}));
}
@Override public CASResponse cas(final String key, final long casId, final int exp, final T value, final Transcoder tc) {
return connPool.executeWithFailover(new BaseKeyOperation(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(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(key, OpName.Cas) {
@Override public CASResponse execute(final MemcachedClient client, ConnectionContext state) throws DynoException {
return client.cas(key, casId, exp, value);
}
}).getResult();
}
@Override public Future add(final String key, final int exp, final T o, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Add) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.add(key, exp, o));
}
}));
}
@Override public Future add(final String key, final int exp, final Object o) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Add) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.add(key, exp, o));
}
}));
}
@Override public Future set(final String key, final int exp, final T o, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Set) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.set(key, exp, o, tc));
}
}));
}
@Override public Future set(final String key, final int exp, final Object o) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Set) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.set(key, exp, o));
}
}));
}
@Override public Future replace(final String key, final int exp, final T o, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.replace(key, exp, o, tc));
}
}));
}
@Override public Future replace(final String key, final int exp, final Object o) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.replace(key, exp, o));
}
}));
}
@Override public Future asyncGet(final String key, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncGet) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncGet(key, tc));
}
}));
}
@Override public Future asyncGet(final String key) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncGet) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncGet(key));
}
}));
}
@Override public Future> asyncGetAndTouch(final String key, final int exp) {
return new DecoratingFuture>(connPool.executeAsync(new BaseAsyncKeyOperation>(key, OpName.AsyncGetAndTouch) {
@Override public ListenableFuture> executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture>(client.asyncGets(key));
}
}));
}
@Override public Future> asyncGetAndTouch(final String key, final int exp, final Transcoder tc) {
return new DecoratingFuture>(connPool.executeAsync(new BaseAsyncKeyOperation>(key, OpName.AsyncGetAndTouch) {
@Override public ListenableFuture> executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture>(client.asyncGetAndTouch(key, exp, tc));
}
}));
}
@Override public Future> asyncGets(final String key, final Transcoder tc) {
return new DecoratingFuture>(connPool.executeAsync(new BaseAsyncKeyOperation>(key, OpName.AsyncGets) {
@Override public ListenableFuture> executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture>(client.asyncGets(key, tc));
}
}));
}
@Override public Future> asyncGets(final String key) {
return new DecoratingFuture>(connPool.executeAsync(new BaseAsyncKeyOperation>(key, OpName.AsyncGets) {
@Override public ListenableFuture> executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture>(client.asyncGets(key));
}
}));
}
@Override public CASValue gets(final String key, final Transcoder tc) {
return connPool.executeWithFailover(new BaseKeyOperation>(key, OpName.Gets) {
@Override public CASValue execute(final MemcachedClient client, ConnectionContext state) throws DynoException {
return client.gets(key, tc);
}
}).getResult();
}
@Override public CASValue gets(final String key) {
return connPool.executeWithFailover(new BaseKeyOperation>(key, OpName.Gets) {
@Override public CASValue execute(final MemcachedClient client, ConnectionContext state) throws DynoException {
return client.gets(key);
}
}).getResult();
}
@Override public T get(final String key, final Transcoder tc) {
return connPool.executeWithFailover(new BaseKeyOperation(key, OpName.Get) {
@Override public T execute(final MemcachedClient client, ConnectionContext state) throws DynoException {
return client.get(key, tc);
}
}).getResult();
}
@Override public BulkFuture> asyncGetBulk(Iterator keys, Iterator> tcs) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Collection keys, Iterator> tcs) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Iterator keys, Transcoder tc) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Collection keys, Transcoder tc) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Iterator keys) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Collection keys) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(Transcoder tc, String... keys) {
throw new RuntimeException("Not Implemented");
}
@Override public BulkFuture> asyncGetBulk(String... keys) {
throw new RuntimeException("Not Implemented");
}
@Override public Map getBulk(Iterator keys, Transcoder tc) {
throw new RuntimeException("Not Implemented");
}
@Override public Map getBulk(Iterator keys) {
throw new RuntimeException("Not Implemented");
}
@Override public Future touch(final String key, final int exp, final Transcoder tc) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Touch) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.touch(key, exp, tc));
}
}));
}
@Override public Future touch(final String key, final int exp) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Append) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.touch(key, exp));
}
}));
}
@Override public Map getVersions() {
throw new RuntimeException("Not Implemented");
}
@Override public Map> getStats() {
throw new RuntimeException("Not Implemented");
}
@Override public Map> getStats(String prefix) {
throw new RuntimeException("Not Implemented");
}
@Override public long incr(final String key, final long by) {
return connPool.executeWithFailover(new BaseKeyOperation(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(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(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(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(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(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(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(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 asyncIncr(final String key, final long by) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncIncr) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncIncr(key, by));
}
}));
}
@Override public Future asyncIncr(final String key, final int by) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncIncr) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncIncr(key, by));
}
}));
}
@Override public Future asyncDecr(final String key, final long by) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncDecr) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncDecr(key, by));
}
}));
}
@Override public Future asyncDecr(final String key, final int by) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.AsyncDecr) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.asyncDecr(key, by));
}
}));
}
@Override public long incr(final String key, final long by, final long def) {
return connPool.executeWithFailover(new BaseKeyOperation(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(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(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(key, OpName.Decr) {
@Override public Long execute(final MemcachedClient client, ConnectionContext state) throws DynoException {
return client.decr(key, by, def);
}
}).getResult();
}
@Override public Future delete(final String key, final long cas) {
return new DecoratingFuture(connPool.executeAsync(new BaseAsyncKeyOperation(key, OpName.Delete) {
@Override public ListenableFuture executeAsync(MemcachedClient client) throws DynoException {
return new DecoratingListenableFuture(client.delete(key, cas));
}
}));
}
@Override public Future flush(int delay) {
throw new RuntimeException("Not Implemented");
}
@Override public Future 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 listSaslMechanisms() {
throw new RuntimeException("Not Implemented");
}
@Override public CASValue getAndTouch(final String key, final int exp) {
return connPool.executeWithFailover(new BaseKeyOperation