diff --git a/pom.xml b/pom.xml
index 4a07d5fbc..ae0d49c61 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,7 +14,7 @@
4.0.0
net.spy
spymemcached
- 2.999.999-SNAPSHOT
+ 2.12.3-kwai-0.0.11
Spymemcached
A client library for memcached.
@@ -42,6 +42,19 @@
http://couchbase.com/
+
+
+
+ kuaishou.releases
+ Internal Release Repository
+ http://nexus.corp.kuaishou.com:88/nexus/content/repositories/releases/
+
+
+ kuaishou.snapshots
+ Internal Snapshot Repository
+ http://nexus.corp.kuaishou.com:88/nexus/content/repositories/snapshots/
+
+
@@ -85,5 +98,22 @@
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.0.0
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
diff --git a/src/main/java/net/spy/memcached/AsyncOpListener.java b/src/main/java/net/spy/memcached/AsyncOpListener.java
new file mode 100644
index 000000000..17d66f420
--- /dev/null
+++ b/src/main/java/net/spy/memcached/AsyncOpListener.java
@@ -0,0 +1,17 @@
+package net.spy.memcached;
+
+import net.spy.memcached.TimeoutListener.Method;
+import net.spy.memcached.internal.BulkGetFuture;
+import net.spy.memcached.internal.GetFuture;
+import net.spy.memcached.internal.OperationFuture;
+
+public interface AsyncOpListener {
+
+ T beforeInvoke(Method method);
+
+ void onBulkGetCompletion(T before, BulkGetFuture> future);
+
+ void onGetCompletion(T before, GetFuture> future);
+
+ void onOperationCompletion(T before, Method method, OperationFuture> future);
+}
diff --git a/src/main/java/net/spy/memcached/ConnectionFactory.java b/src/main/java/net/spy/memcached/ConnectionFactory.java
index a85a6dda3..2ed6af30d 100644
--- a/src/main/java/net/spy/memcached/ConnectionFactory.java
+++ b/src/main/java/net/spy/memcached/ConnectionFactory.java
@@ -30,6 +30,7 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import net.spy.memcached.auth.AuthDescriptor;
@@ -87,7 +88,7 @@ MemcachedNode createMemcachedNode(SocketAddress sa, SocketChannel c,
* Get the ExecutorService which is used to asynchronously execute listeners
* on futures.
*/
- ExecutorService getListenerExecutorService();
+ Executor getListenerExecutorService();
/**
* Returns true if the default provided {@link ExecutorService} has not been
diff --git a/src/main/java/net/spy/memcached/ConnectionFactoryBuilder.java b/src/main/java/net/spy/memcached/ConnectionFactoryBuilder.java
index b3ece2eec..cfc040149 100644
--- a/src/main/java/net/spy/memcached/ConnectionFactoryBuilder.java
+++ b/src/main/java/net/spy/memcached/ConnectionFactoryBuilder.java
@@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import net.spy.memcached.auth.AuthDescriptor;
@@ -75,7 +76,7 @@ public class ConnectionFactoryBuilder {
protected MetricType metricType = null;
protected MetricCollector collector = null;
- protected ExecutorService executorService = null;
+ protected Executor executor = null;
protected long authWaitTime = DefaultConnectionFactory.DEFAULT_AUTH_WAIT_TIME;
/**
@@ -311,8 +312,8 @@ public ConnectionFactoryBuilder setMetricCollector(MetricCollector collector) {
*
* @param executorService the ExecutorService to use.
*/
- public ConnectionFactoryBuilder setListenerExecutorService(ExecutorService executorService) {
- this.executorService = executorService;
+ public ConnectionFactoryBuilder setListenerExecutorService(Executor executorService) {
+ this.executor = executorService;
return this;
}
@@ -447,13 +448,13 @@ public MetricCollector getMetricCollector() {
}
@Override
- public ExecutorService getListenerExecutorService() {
- return executorService == null ? super.getListenerExecutorService() : executorService;
+ public Executor getListenerExecutorService() {
+ return executor == null ? super.getListenerExecutorService() : executor;
}
@Override
public boolean isDefaultExecutorService() {
- return executorService == null;
+ return executor == null;
}
@Override
diff --git a/src/main/java/net/spy/memcached/DefaultConnectionFactory.java b/src/main/java/net/spy/memcached/DefaultConnectionFactory.java
index 16623cd3b..5c5f5f828 100644
--- a/src/main/java/net/spy/memcached/DefaultConnectionFactory.java
+++ b/src/main/java/net/spy/memcached/DefaultConnectionFactory.java
@@ -32,10 +32,9 @@
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -132,9 +131,9 @@ public class DefaultConnectionFactory extends SpyObject implements
private MetricCollector metrics;
/**
- * The ExecutorService in which the listener callbacks will be executed.
+ * The Executor in which the listener callbacks will be executed.
*/
- private ExecutorService executorService;
+ private Executor executor;
/**
* Construct a DefaultConnectionFactory with the given parameters.
@@ -289,16 +288,16 @@ public long getAuthWaitTime() {
* @return the stored {@link ExecutorService}.
*/
@Override
- public ExecutorService getListenerExecutorService() {
- if (executorService == null) {
+ public Executor getListenerExecutorService() {
+ if (executor == null) {
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
- return new Thread(r, "FutureNotifyListener");
+ return new Thread(r, "FutureNotifyListener[" + DefaultConnectionFactory.this.getName() + "]");
}
};
- executorService = new ThreadPoolExecutor(
+ executor = new ThreadPoolExecutor(
0,
Runtime.getRuntime().availableProcessors(),
60L,
@@ -308,7 +307,7 @@ public Thread newThread(Runnable r) {
);
}
- return executorService;
+ return executor;
}
@Override
diff --git a/src/main/java/net/spy/memcached/MemcachedClient.java b/src/main/java/net/spy/memcached/MemcachedClient.java
index 77d0f048e..eb1c2f18d 100644
--- a/src/main/java/net/spy/memcached/MemcachedClient.java
+++ b/src/main/java/net/spy/memcached/MemcachedClient.java
@@ -23,12 +23,53 @@
package net.spy.memcached;
+import static net.spy.memcached.TimeoutListener.Method.cas;
+import static net.spy.memcached.TimeoutListener.Method.from;
+import static net.spy.memcached.TimeoutListener.Method.get;
+import static net.spy.memcached.TimeoutListener.Method.getBulk;
+import static net.spy.memcached.TimeoutListener.Method.gets;
+import static net.spy.memcached.TimeoutListener.Method.touch;
+
+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.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+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.Executor;
+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;
+
+import net.spy.memcached.TimeoutListener.Method;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.AuthThreadMonitor;
import net.spy.memcached.compat.SpyObject;
+import net.spy.memcached.compat.log.LoggerFactory;
import net.spy.memcached.internal.BulkFuture;
+import net.spy.memcached.internal.BulkGetCompletionListener;
import net.spy.memcached.internal.BulkGetFuture;
+import net.spy.memcached.internal.GetCompletionListener;
import net.spy.memcached.internal.GetFuture;
+import net.spy.memcached.internal.OperationCompletionListener;
import net.spy.memcached.internal.OperationFuture;
import net.spy.memcached.internal.SingleElementInfiniteIterator;
import net.spy.memcached.ops.CASOperationStatus;
@@ -53,32 +94,6 @@
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.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;
-
/**
* Client to a memcached server.
*
@@ -157,7 +172,11 @@ public class MemcachedClient extends SpyObject implements MemcachedClientIF,
protected final AuthThreadMonitor authMonitor = new AuthThreadMonitor();
- protected final ExecutorService executorService;
+ protected final Executor executor;
+
+ private final List timeoutListeners = new ArrayList();
+
+ private final List> asyncOpListeners = new ArrayList>();
/**
* Get a memcache client operating on the specified memcached locations.
@@ -210,7 +229,7 @@ public MemcachedClient(ConnectionFactory cf, List addrs)
assert mconn != null : "Connection factory failed to make a connection";
operationTimeout = cf.getOperationTimeout();
authDescriptor = cf.getAuthDescriptor();
- executorService = cf.getListenerExecutorService();
+ executor = cf.getListenerExecutorService();
if (authDescriptor != null) {
addObserver(this);
}
@@ -301,11 +320,13 @@ private CountDownLatch broadcastOp(BroadcastOpFactory of,
private OperationFuture asyncStore(StoreType storeType,
String key, int exp, T value, Transcoder tc) {
+ Method method = from(storeType);
+ final Map, Object> before = before(method);
CachedData co = tc.encode(value);
final CountDownLatch latch = new CountDownLatch(1);
final OperationFuture rv =
- new OperationFuture(key, latch, operationTimeout,
- executorService);
+ new OperationFuture(key, latch, operationTimeout, executor);
+
Operation op = opFact.store(storeType, key, co.getFlags(), exp,
co.getData(), new StoreOperation.Callback() {
@Override
@@ -323,11 +344,33 @@ public void complete() {
rv.signalComplete();
}
});
+ rv.setTimeoutListeners(method, timeoutListeners);
rv.setOperation(op);
mconn.enqueueOperation(key, op);
+ addOpAsyncListener(method, before, rv);
return rv;
}
+ private void addOpAsyncListener(final Method method,
+ final Map, Object> before, OperationFuture> rv) {
+ rv.addListener(new OperationCompletionListener() {
+
+ public void onComplete(OperationFuture> future) {
+ for (Entry, Object> entry : before.entrySet()) {
+ entry.getKey().onOperationCompletion(entry.getValue(), method, future);
+ }
+ }
+ });
+ }
+
+ private Map, Object> before(Method method) {
+ Map, Object> result = new IdentityHashMap, Object>();
+ for (AsyncOpListener