Madan Jampani

sendAndReceive now returns a Future instead of Reponse

...@@ -4,6 +4,7 @@ import static java.lang.Thread.sleep; ...@@ -4,6 +4,7 @@ import static java.lang.Thread.sleep;
4 4
5 import java.io.IOException; 5 import java.io.IOException;
6 import java.util.concurrent.ExecutionException; 6 import java.util.concurrent.ExecutionException;
7 +import java.util.concurrent.Future;
7 import java.util.concurrent.TimeUnit; 8 import java.util.concurrent.TimeUnit;
8 import java.util.concurrent.TimeoutException; 9 import java.util.concurrent.TimeoutException;
9 10
...@@ -12,7 +13,6 @@ import org.onlab.metrics.MetricsFeature; ...@@ -12,7 +13,6 @@ import org.onlab.metrics.MetricsFeature;
12 import org.onlab.metrics.MetricsManager; 13 import org.onlab.metrics.MetricsManager;
13 import org.onlab.netty.Endpoint; 14 import org.onlab.netty.Endpoint;
14 import org.onlab.netty.NettyMessagingService; 15 import org.onlab.netty.NettyMessagingService;
15 -import org.onlab.netty.Response;
16 import org.slf4j.Logger; 16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory; 17 import org.slf4j.LoggerFactory;
18 18
...@@ -74,10 +74,10 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); ...@@ -74,10 +74,10 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
74 74
75 for (int i = 0; i < warmup; i++) { 75 for (int i = 0; i < warmup; i++) {
76 messaging.sendAsync(endpoint, "simple", "Hello World".getBytes()); 76 messaging.sendAsync(endpoint, "simple", "Hello World".getBytes());
77 - Response response = messaging 77 + Future<byte[]> responseFuture = messaging
78 .sendAndReceive(endpoint, "echo", 78 .sendAndReceive(endpoint, "echo",
79 "Hello World".getBytes()); 79 "Hello World".getBytes());
80 - response.get(100000, TimeUnit.MILLISECONDS); 80 + responseFuture.get(100000, TimeUnit.MILLISECONDS);
81 } 81 }
82 82
83 log.info("measuring round-trip send & receive"); 83 log.info("measuring round-trip send & receive");
...@@ -85,13 +85,13 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class); ...@@ -85,13 +85,13 @@ private static Logger log = LoggerFactory.getLogger(SimpleNettyClient.class);
85 int timeouts = 0; 85 int timeouts = 0;
86 86
87 for (int i = 0; i < iterations; i++) { 87 for (int i = 0; i < iterations; i++) {
88 - Response response; 88 + Future<byte[]> responseFuture;
89 Timer.Context context = sendAndReceiveTimer.time(); 89 Timer.Context context = sendAndReceiveTimer.time();
90 try { 90 try {
91 - response = messaging 91 + responseFuture = messaging
92 .sendAndReceive(endpoint, "echo", 92 .sendAndReceive(endpoint, "echo",
93 "Hello World".getBytes()); 93 "Hello World".getBytes());
94 - response.get(10000, TimeUnit.MILLISECONDS); 94 + responseFuture.get(10000, TimeUnit.MILLISECONDS);
95 } catch (TimeoutException e) { 95 } catch (TimeoutException e) {
96 timeouts++; 96 timeouts++;
97 log.info("timeout:" + timeouts + " at iteration:" + i); 97 log.info("timeout:" + timeouts + " at iteration:" + i);
......
...@@ -5,6 +5,8 @@ import java.util.Set; ...@@ -5,6 +5,8 @@ import java.util.Set;
5 5
6 import org.onlab.onos.cluster.NodeId; 6 import org.onlab.onos.cluster.NodeId;
7 7
8 +import com.google.common.util.concurrent.ListenableFuture;
9 +
8 // TODO: remove IOExceptions? 10 // TODO: remove IOExceptions?
9 /** 11 /**
10 * Service for assisting communications between controller cluster nodes. 12 * Service for assisting communications between controller cluster nodes.
...@@ -40,10 +42,10 @@ public interface ClusterCommunicationService { ...@@ -40,10 +42,10 @@ public interface ClusterCommunicationService {
40 * Sends a message synchronously. 42 * Sends a message synchronously.
41 * @param message message to send 43 * @param message message to send
42 * @param toNodeId recipient node identifier 44 * @param toNodeId recipient node identifier
43 - * @return ClusterMessageResponse which is reply future. 45 + * @return reply future.
44 * @throws IOException 46 * @throws IOException
45 */ 47 */
46 - ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException; 48 + ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException;
47 49
48 /** 50 /**
49 * Adds a new subscriber for the specified message subject. 51 * Adds a new subscriber for the specified message subject.
......
1 -package org.onlab.onos.store.cluster.messaging;
2 -
3 -import java.util.concurrent.Future;
4 -import java.util.concurrent.TimeUnit;
5 -import java.util.concurrent.TimeoutException;
6 -
7 -import org.onlab.onos.cluster.NodeId;
8 -
9 -public interface ClusterMessageResponse extends Future<byte[]> {
10 -
11 - public NodeId sender();
12 -
13 - // TODO InterruptedException, ExecutionException removed from original
14 - // Future declaration. Revisit if we ever need those.
15 - @Override
16 - public byte[] get(long timeout, TimeUnit unit) throws TimeoutException;
17 -
18 -}
...@@ -4,9 +4,7 @@ import static com.google.common.base.Preconditions.checkArgument; ...@@ -4,9 +4,7 @@ import static com.google.common.base.Preconditions.checkArgument;
4 4
5 import java.io.IOException; 5 import java.io.IOException;
6 import java.util.Set; 6 import java.util.Set;
7 -import java.util.concurrent.ExecutionException; 7 +
8 -import java.util.concurrent.TimeUnit;
9 -import java.util.concurrent.TimeoutException;
10 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
11 import org.apache.felix.scr.annotations.Component; 9 import org.apache.felix.scr.annotations.Component;
12 import org.apache.felix.scr.annotations.Deactivate; 10 import org.apache.felix.scr.annotations.Deactivate;
...@@ -20,7 +18,6 @@ import org.onlab.onos.store.cluster.impl.ClusterMembershipEvent; ...@@ -20,7 +18,6 @@ import org.onlab.onos.store.cluster.impl.ClusterMembershipEvent;
20 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 18 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
21 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 19 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
22 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 20 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
23 -import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
24 import org.onlab.onos.store.cluster.messaging.MessageSubject; 21 import org.onlab.onos.store.cluster.messaging.MessageSubject;
25 import org.onlab.onos.store.serializers.ClusterMessageSerializer; 22 import org.onlab.onos.store.serializers.ClusterMessageSerializer;
26 import org.onlab.onos.store.serializers.KryoNamespaces; 23 import org.onlab.onos.store.serializers.KryoNamespaces;
...@@ -32,10 +29,11 @@ import org.onlab.netty.Message; ...@@ -32,10 +29,11 @@ import org.onlab.netty.Message;
32 import org.onlab.netty.MessageHandler; 29 import org.onlab.netty.MessageHandler;
33 import org.onlab.netty.MessagingService; 30 import org.onlab.netty.MessagingService;
34 import org.onlab.netty.NettyMessagingService; 31 import org.onlab.netty.NettyMessagingService;
35 -import org.onlab.netty.Response;
36 import org.slf4j.Logger; 32 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory; 33 import org.slf4j.LoggerFactory;
38 34
35 +import com.google.common.util.concurrent.ListenableFuture;
36 +
39 @Component(immediate = true) 37 @Component(immediate = true)
40 @Service 38 @Service
41 public class ClusterCommunicationManager 39 public class ClusterCommunicationManager
...@@ -133,14 +131,12 @@ public class ClusterCommunicationManager ...@@ -133,14 +131,12 @@ public class ClusterCommunicationManager
133 } 131 }
134 132
135 @Override 133 @Override
136 - public ClusterMessageResponse sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException { 134 + public ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException {
137 ControllerNode node = clusterService.getNode(toNodeId); 135 ControllerNode node = clusterService.getNode(toNodeId);
138 checkArgument(node != null, "Unknown nodeId: %s", toNodeId); 136 checkArgument(node != null, "Unknown nodeId: %s", toNodeId);
139 Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort()); 137 Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort());
140 try { 138 try {
141 - Response responseFuture = 139 + return messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message));
142 - messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message));
143 - return new InternalClusterMessageResponse(toNodeId, responseFuture);
144 140
145 } catch (IOException e) { 141 } catch (IOException e) {
146 log.error("Failed interaction with remote nodeId: " + toNodeId, e); 142 log.error("Failed interaction with remote nodeId: " + toNodeId, e);
...@@ -188,60 +184,4 @@ public class ClusterCommunicationManager ...@@ -188,60 +184,4 @@ public class ClusterCommunicationManager
188 rawMessage.respond(response); 184 rawMessage.respond(response);
189 } 185 }
190 } 186 }
191 - 187 +}
192 - private static final class InternalClusterMessageResponse
193 - implements ClusterMessageResponse {
194 -
195 - private final NodeId sender;
196 - private final Response responseFuture;
197 - private volatile boolean isCancelled = false;
198 - private volatile boolean isDone = false;
199 -
200 - public InternalClusterMessageResponse(NodeId sender, Response responseFuture) {
201 - this.sender = sender;
202 - this.responseFuture = responseFuture;
203 - }
204 - @Override
205 - public NodeId sender() {
206 - return sender;
207 - }
208 -
209 - @Override
210 - public byte[] get(long timeout, TimeUnit timeunit)
211 - throws TimeoutException {
212 - final byte[] result = responseFuture.get(timeout, timeunit);
213 - isDone = true;
214 - return result;
215 - }
216 -
217 - @Override
218 - public boolean cancel(boolean mayInterruptIfRunning) {
219 - if (isDone()) {
220 - return false;
221 - }
222 - // doing nothing for now
223 - // when onlab.netty Response support cancel, call them.
224 - isCancelled = true;
225 - return true;
226 - }
227 -
228 - @Override
229 - public boolean isCancelled() {
230 - return isCancelled;
231 - }
232 -
233 - @Override
234 - public boolean isDone() {
235 - return this.isDone || isCancelled();
236 - }
237 -
238 - @Override
239 - public byte[] get() throws InterruptedException, ExecutionException {
240 - // TODO: consider forbidding this call and force the use of timed get
241 - // to enforce handling of remote peer failure scenario
242 - final byte[] result = responseFuture.get();
243 - isDone = true;
244 - return result;
245 - }
246 - }
247 -}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -12,6 +12,7 @@ import java.util.Collection; ...@@ -12,6 +12,7 @@ import java.util.Collection;
12 import java.util.Collections; 12 import java.util.Collections;
13 import java.util.Map; 13 import java.util.Map;
14 import java.util.Set; 14 import java.util.Set;
15 +import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.ExecutorService; 16 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors; 17 import java.util.concurrent.Executors;
17 import java.util.concurrent.Future; 18 import java.util.concurrent.Future;
...@@ -49,7 +50,6 @@ import org.onlab.onos.store.AbstractStore; ...@@ -49,7 +50,6 @@ import org.onlab.onos.store.AbstractStore;
49 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 50 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
50 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 51 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
51 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 52 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
52 -import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
53 import org.onlab.onos.store.flow.ReplicaInfo; 53 import org.onlab.onos.store.flow.ReplicaInfo;
54 import org.onlab.onos.store.flow.ReplicaInfoService; 54 import org.onlab.onos.store.flow.ReplicaInfoService;
55 import org.onlab.onos.store.serializers.DistributedStoreSerializers; 55 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
...@@ -57,6 +57,7 @@ import org.onlab.onos.store.serializers.KryoSerializer; ...@@ -57,6 +57,7 @@ import org.onlab.onos.store.serializers.KryoSerializer;
57 import org.onlab.util.KryoNamespace; 57 import org.onlab.util.KryoNamespace;
58 import org.slf4j.Logger; 58 import org.slf4j.Logger;
59 59
60 +import com.google.common.base.Function;
60 import com.google.common.collect.ArrayListMultimap; 61 import com.google.common.collect.ArrayListMultimap;
61 import com.google.common.collect.ImmutableSet; 62 import com.google.common.collect.ImmutableSet;
62 import com.google.common.collect.Iterables; 63 import com.google.common.collect.Iterables;
...@@ -213,9 +214,9 @@ public class DistributedFlowRuleStore ...@@ -213,9 +214,9 @@ public class DistributedFlowRuleStore
213 SERIALIZER.encode(rule)); 214 SERIALIZER.encode(rule));
214 215
215 try { 216 try {
216 - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 217 + Future<byte[]> responseFuture = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
217 - return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 218 + return SERIALIZER.decode(responseFuture.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
218 - } catch (IOException | TimeoutException e) { 219 + } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
219 // FIXME: throw a FlowStoreException 220 // FIXME: throw a FlowStoreException
220 throw new RuntimeException(e); 221 throw new RuntimeException(e);
221 } 222 }
...@@ -247,9 +248,9 @@ public class DistributedFlowRuleStore ...@@ -247,9 +248,9 @@ public class DistributedFlowRuleStore
247 SERIALIZER.encode(deviceId)); 248 SERIALIZER.encode(deviceId));
248 249
249 try { 250 try {
250 - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 251 + Future<byte[]> responseFuture = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
251 - return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 252 + return SERIALIZER.decode(responseFuture.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
252 - } catch (IOException | TimeoutException e) { 253 + } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
253 // FIXME: throw a FlowStoreException 254 // FIXME: throw a FlowStoreException
254 throw new RuntimeException(e); 255 throw new RuntimeException(e);
255 } 256 }
...@@ -291,14 +292,17 @@ public class DistributedFlowRuleStore ...@@ -291,14 +292,17 @@ public class DistributedFlowRuleStore
291 SERIALIZER.encode(operation)); 292 SERIALIZER.encode(operation));
292 293
293 try { 294 try {
294 - ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 295 + ListenableFuture<byte[]> responseFuture =
295 - response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 296 + clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
296 - } catch (IOException | TimeoutException e) { 297 + return Futures.transform(responseFuture, new Function<byte[], CompletedBatchOperation>() {
297 - // FIXME: throw a FlowStoreException 298 + @Override
298 - throw new RuntimeException(e); 299 + public CompletedBatchOperation apply(byte[] input) {
300 + return SERIALIZER.decode(input);
301 + }
302 + });
303 + } catch (IOException e) {
304 + return Futures.immediateFailedFuture(e);
299 } 305 }
300 -
301 - return null;
302 } 306 }
303 307
304 private ListenableFuture<CompletedBatchOperation> storeBatchInternal(FlowRuleBatchOperation operation) { 308 private ListenableFuture<CompletedBatchOperation> storeBatchInternal(FlowRuleBatchOperation operation) {
......
...@@ -4,6 +4,7 @@ import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects. ...@@ -4,6 +4,7 @@ import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects.
4 import static org.slf4j.LoggerFactory.getLogger; 4 import static org.slf4j.LoggerFactory.getLogger;
5 5
6 import com.google.common.collect.Sets; 6 import com.google.common.collect.Sets;
7 +
7 import org.apache.felix.scr.annotations.Activate; 8 import org.apache.felix.scr.annotations.Activate;
8 import org.apache.felix.scr.annotations.Component; 9 import org.apache.felix.scr.annotations.Component;
9 import org.apache.felix.scr.annotations.Deactivate; 10 import org.apache.felix.scr.annotations.Deactivate;
...@@ -21,7 +22,6 @@ import org.onlab.onos.net.statistic.StatisticStore; ...@@ -21,7 +22,6 @@ import org.onlab.onos.net.statistic.StatisticStore;
21 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; 22 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
22 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 23 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
23 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 24 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
24 -import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
25 import org.onlab.onos.store.flow.ReplicaInfo; 25 import org.onlab.onos.store.flow.ReplicaInfo;
26 import org.onlab.onos.store.flow.ReplicaInfoService; 26 import org.onlab.onos.store.flow.ReplicaInfoService;
27 import org.onlab.onos.store.serializers.KryoNamespaces; 27 import org.onlab.onos.store.serializers.KryoNamespaces;
...@@ -34,6 +34,8 @@ import java.util.HashSet; ...@@ -34,6 +34,8 @@ import java.util.HashSet;
34 import java.util.Map; 34 import java.util.Map;
35 import java.util.Set; 35 import java.util.Set;
36 import java.util.concurrent.ConcurrentHashMap; 36 import java.util.concurrent.ConcurrentHashMap;
37 +import java.util.concurrent.ExecutionException;
38 +import java.util.concurrent.Future;
37 import java.util.concurrent.TimeUnit; 39 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.TimeoutException; 40 import java.util.concurrent.TimeoutException;
39 import java.util.concurrent.atomic.AtomicInteger; 41 import java.util.concurrent.atomic.AtomicInteger;
...@@ -184,11 +186,11 @@ public class DistributedStatisticStore implements StatisticStore { ...@@ -184,11 +186,11 @@ public class DistributedStatisticStore implements StatisticStore {
184 SERIALIZER.encode(connectPoint)); 186 SERIALIZER.encode(connectPoint));
185 187
186 try { 188 try {
187 - ClusterMessageResponse response = 189 + Future<byte[]> response =
188 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 190 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
189 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS, 191 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
190 TimeUnit.MILLISECONDS)); 192 TimeUnit.MILLISECONDS));
191 - } catch (IOException | TimeoutException e) { 193 + } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
192 // FIXME: throw a StatsStoreException 194 // FIXME: throw a StatsStoreException
193 throw new RuntimeException(e); 195 throw new RuntimeException(e);
194 } 196 }
...@@ -212,11 +214,11 @@ public class DistributedStatisticStore implements StatisticStore { ...@@ -212,11 +214,11 @@ public class DistributedStatisticStore implements StatisticStore {
212 SERIALIZER.encode(connectPoint)); 214 SERIALIZER.encode(connectPoint));
213 215
214 try { 216 try {
215 - ClusterMessageResponse response = 217 + Future<byte[]> response =
216 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get()); 218 clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
217 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS, 219 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
218 TimeUnit.MILLISECONDS)); 220 TimeUnit.MILLISECONDS));
219 - } catch (IOException | TimeoutException e) { 221 + } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
220 // FIXME: throw a StatsStoreException 222 // FIXME: throw a StatsStoreException
221 throw new RuntimeException(e); 223 throw new RuntimeException(e);
222 } 224 }
......
1 -package org.onlab.netty;
2 -
3 -import java.util.concurrent.TimeUnit;
4 -import java.util.concurrent.TimeoutException;
5 -
6 -/**
7 - * An asynchronous response.
8 - * This class provides a base implementation of Response, with methods to retrieve the
9 - * result and query to see if the result is ready. The result can only be retrieved when
10 - * it is ready and the get methods will block if the result is not ready yet.
11 - */
12 -public class AsyncResponse implements Response {
13 -
14 - private byte[] value;
15 - private boolean done = false;
16 - private final long start = System.nanoTime();
17 -
18 - @Override
19 - public byte[] get(long timeout, TimeUnit timeUnit) throws TimeoutException {
20 - timeout = timeUnit.toNanos(timeout);
21 - boolean interrupted = false;
22 - try {
23 - synchronized (this) {
24 - while (!done) {
25 - try {
26 - long timeRemaining = timeout - (System.nanoTime() - start);
27 - if (timeRemaining <= 0) {
28 - throw new TimeoutException("Operation timed out.");
29 - }
30 - TimeUnit.NANOSECONDS.timedWait(this, timeRemaining);
31 - } catch (InterruptedException e) {
32 - interrupted = true;
33 - }
34 - }
35 - }
36 - } finally {
37 - if (interrupted) {
38 - Thread.currentThread().interrupt();
39 - }
40 - }
41 - return value;
42 - }
43 -
44 - @Override
45 - public byte[] get() throws InterruptedException {
46 - throw new UnsupportedOperationException();
47 - }
48 -
49 - @Override
50 - public boolean isReady() {
51 - return done;
52 - }
53 -
54 - /**
55 - * Sets response value and unblocks any thread blocking on the response to become
56 - * available.
57 - * @param data response data.
58 - */
59 - public synchronized void setResponse(byte[] data) {
60 - if (!done) {
61 - done = true;
62 - value = data;
63 - this.notifyAll();
64 - }
65 - }
66 -}
...@@ -2,6 +2,8 @@ package org.onlab.netty; ...@@ -2,6 +2,8 @@ package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
5 +import com.google.common.util.concurrent.ListenableFuture;
6 +
5 /** 7 /**
6 * Interface for low level messaging primitives. 8 * Interface for low level messaging primitives.
7 */ 9 */
...@@ -24,7 +26,7 @@ public interface MessagingService { ...@@ -24,7 +26,7 @@ public interface MessagingService {
24 * @return a response future 26 * @return a response future
25 * @throws IOException 27 * @throws IOException
26 */ 28 */
27 - public Response sendAndReceive(Endpoint ep, String type, byte[] payload) throws IOException; 29 + public ListenableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload) throws IOException;
28 30
29 /** 31 /**
30 * Registers a new message handler for message type. 32 * Registers a new message handler for message type.
......
...@@ -5,6 +5,7 @@ import java.net.UnknownHostException; ...@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
5 import java.util.concurrent.ConcurrentHashMap; 5 import java.util.concurrent.ConcurrentHashMap;
6 import java.util.concurrent.ConcurrentMap; 6 import java.util.concurrent.ConcurrentMap;
7 import java.util.concurrent.TimeUnit; 7 import java.util.concurrent.TimeUnit;
8 +import java.util.concurrent.atomic.AtomicLong;
8 9
9 import io.netty.bootstrap.Bootstrap; 10 import io.netty.bootstrap.Bootstrap;
10 import io.netty.bootstrap.ServerBootstrap; 11 import io.netty.bootstrap.ServerBootstrap;
...@@ -26,7 +27,6 @@ import io.netty.channel.socket.SocketChannel; ...@@ -26,7 +27,6 @@ import io.netty.channel.socket.SocketChannel;
26 import io.netty.channel.socket.nio.NioServerSocketChannel; 27 import io.netty.channel.socket.nio.NioServerSocketChannel;
27 import io.netty.channel.socket.nio.NioSocketChannel; 28 import io.netty.channel.socket.nio.NioSocketChannel;
28 29
29 -import org.apache.commons.lang.math.RandomUtils;
30 import org.apache.commons.pool.KeyedPoolableObjectFactory; 30 import org.apache.commons.pool.KeyedPoolableObjectFactory;
31 import org.apache.commons.pool.impl.GenericKeyedObjectPool; 31 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
32 import org.slf4j.Logger; 32 import org.slf4j.Logger;
...@@ -34,6 +34,8 @@ import org.slf4j.LoggerFactory; ...@@ -34,6 +34,8 @@ import org.slf4j.LoggerFactory;
34 34
35 import com.google.common.cache.Cache; 35 import com.google.common.cache.Cache;
36 import com.google.common.cache.CacheBuilder; 36 import com.google.common.cache.CacheBuilder;
37 +import com.google.common.util.concurrent.ListenableFuture;
38 +import com.google.common.util.concurrent.SettableFuture;
37 39
38 /** 40 /**
39 * A Netty based implementation of MessagingService. 41 * A Netty based implementation of MessagingService.
...@@ -44,7 +46,8 @@ public class NettyMessagingService implements MessagingService { ...@@ -44,7 +46,8 @@ public class NettyMessagingService implements MessagingService {
44 46
45 private final Endpoint localEp; 47 private final Endpoint localEp;
46 private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>(); 48 private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>();
47 - private final Cache<Long, AsyncResponse> responseFutures = CacheBuilder.newBuilder() 49 + private final AtomicLong messageIdGenerator = new AtomicLong(0);
50 + private final Cache<Long, SettableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder()
48 .maximumSize(100000) 51 .maximumSize(100000)
49 .weakValues() 52 .weakValues()
50 // TODO: Once the entry expires, notify blocking threads (if any). 53 // TODO: Once the entry expires, notify blocking threads (if any).
...@@ -119,7 +122,7 @@ public class NettyMessagingService implements MessagingService { ...@@ -119,7 +122,7 @@ public class NettyMessagingService implements MessagingService {
119 @Override 122 @Override
120 public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException { 123 public void sendAsync(Endpoint ep, String type, byte[] payload) throws IOException {
121 InternalMessage message = new InternalMessage.Builder(this) 124 InternalMessage message = new InternalMessage.Builder(this)
122 - .withId(RandomUtils.nextLong()) 125 + .withId(messageIdGenerator.incrementAndGet())
123 .withSender(localEp) 126 .withSender(localEp)
124 .withType(type) 127 .withType(type)
125 .withPayload(payload) 128 .withPayload(payload)
...@@ -142,10 +145,10 @@ public class NettyMessagingService implements MessagingService { ...@@ -142,10 +145,10 @@ public class NettyMessagingService implements MessagingService {
142 } 145 }
143 146
144 @Override 147 @Override
145 - public Response sendAndReceive(Endpoint ep, String type, byte[] payload) 148 + public ListenableFuture<byte[]> sendAndReceive(Endpoint ep, String type, byte[] payload)
146 throws IOException { 149 throws IOException {
147 - AsyncResponse futureResponse = new AsyncResponse(); 150 + SettableFuture<byte[]> futureResponse = SettableFuture.create();
148 - Long messageId = RandomUtils.nextLong(); 151 + Long messageId = messageIdGenerator.incrementAndGet();
149 responseFutures.put(messageId, futureResponse); 152 responseFutures.put(messageId, futureResponse);
150 InternalMessage message = new InternalMessage.Builder(this) 153 InternalMessage message = new InternalMessage.Builder(this)
151 .withId(messageId) 154 .withId(messageId)
...@@ -267,10 +270,10 @@ public class NettyMessagingService implements MessagingService { ...@@ -267,10 +270,10 @@ public class NettyMessagingService implements MessagingService {
267 String type = message.type(); 270 String type = message.type();
268 if (type.equals(InternalMessage.REPLY_MESSAGE_TYPE)) { 271 if (type.equals(InternalMessage.REPLY_MESSAGE_TYPE)) {
269 try { 272 try {
270 - AsyncResponse futureResponse = 273 + SettableFuture<byte[]> futureResponse =
271 NettyMessagingService.this.responseFutures.getIfPresent(message.id()); 274 NettyMessagingService.this.responseFutures.getIfPresent(message.id());
272 if (futureResponse != null) { 275 if (futureResponse != null) {
273 - futureResponse.setResponse(message.payload()); 276 + futureResponse.set(message.payload());
274 } else { 277 } else {
275 log.warn("Received a reply. But was unable to locate the request handle"); 278 log.warn("Received a reply. But was unable to locate the request handle");
276 } 279 }
......
1 -package org.onlab.netty;
2 -
3 -import java.util.concurrent.TimeUnit;
4 -import java.util.concurrent.TimeoutException;
5 -
6 -/**
7 - * Response object returned when making synchronous requests.
8 - * Can you used to check is a response is ready and/or wait for a response
9 - * to become available.
10 - */
11 -public interface Response {
12 -
13 - /**
14 - * Gets the response waiting for a designated timeout period.
15 - * @param timeout timeout period (since request was sent out)
16 - * @param tu unit of time.
17 - * @return response payload
18 - * @throws TimeoutException if the timeout expires before the response arrives.
19 - */
20 - public byte[] get(long timeout, TimeUnit tu) throws TimeoutException;
21 -
22 - /**
23 - * Gets the response waiting for indefinite timeout period.
24 - * @return response payload
25 - * @throws InterruptedException if the thread is interrupted before the response arrives.
26 - */
27 - public byte[] get() throws InterruptedException;
28 -
29 - /**
30 - * Checks if the response is ready without blocking.
31 - * @return true if response is ready, false otherwise.
32 - */
33 - public boolean isReady();
34 -}
1 package org.onlab.netty; 1 package org.onlab.netty;
2 2
3 +import java.util.concurrent.Future;
3 import java.util.concurrent.TimeUnit; 4 import java.util.concurrent.TimeUnit;
4 5
5 import org.apache.commons.lang3.RandomUtils; 6 import org.apache.commons.lang3.RandomUtils;
7 +
6 import static org.junit.Assert.*; 8 import static org.junit.Assert.*;
9 +
7 import org.junit.Test; 10 import org.junit.Test;
8 11
9 /** 12 /**
...@@ -20,8 +23,8 @@ public class PingPongTest { ...@@ -20,8 +23,8 @@ public class PingPongTest {
20 ponger.activate(); 23 ponger.activate();
21 ponger.registerHandler("echo", new EchoHandler()); 24 ponger.registerHandler("echo", new EchoHandler());
22 byte[] payload = RandomUtils.nextBytes(100); 25 byte[] payload = RandomUtils.nextBytes(100);
23 - Response response = pinger.sendAndReceive(new Endpoint("localhost", 9086), "echo", payload); 26 + Future<byte[]> responseFuture = pinger.sendAndReceive(new Endpoint("localhost", 9086), "echo", payload);
24 - assertArrayEquals(payload, response.get(10000, TimeUnit.MILLISECONDS)); 27 + assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS));
25 } finally { 28 } finally {
26 pinger.deactivate(); 29 pinger.deactivate();
27 ponger.deactivate(); 30 ponger.deactivate();
......