Madan Jampani
Committed by Gerrit Code Review

Bypass netty stack for messages that are sent to self

Change-Id: Ifb1fd610892bd22a291cda472a8a5ef7a1dcfe6d

Manual serde for ClusterMessage to avoid one additional kryo serialization overhead for each message sent/received

Change-Id: I08d9a2c10403b0e9e9e1736c6bd36fa008bb8db0
...@@ -15,14 +15,17 @@ ...@@ -15,14 +15,17 @@
15 */ 15 */
16 package org.onosproject.store.cluster.messaging; 16 package org.onosproject.store.cluster.messaging;
17 17
18 -import com.google.common.base.MoreObjects;
19 -import org.onlab.util.ByteArraySizeHashPrinter;
20 -import org.onosproject.cluster.NodeId;
21 -
22 import java.io.IOException; 18 import java.io.IOException;
19 +import java.nio.ByteBuffer;
23 import java.util.Arrays; 20 import java.util.Arrays;
24 import java.util.Objects; 21 import java.util.Objects;
25 22
23 +import org.onlab.util.ByteArraySizeHashPrinter;
24 +import org.onosproject.cluster.NodeId;
25 +
26 +import com.google.common.base.Charsets;
27 +import com.google.common.base.MoreObjects;
28 +
26 // TODO: Should payload type be ByteBuffer? 29 // TODO: Should payload type be ByteBuffer?
27 /** 30 /**
28 * Base message for cluster-wide communications. 31 * Base message for cluster-wide communications.
...@@ -105,6 +108,43 @@ public class ClusterMessage { ...@@ -105,6 +108,43 @@ public class ClusterMessage {
105 Arrays.equals(this.payload, that.payload); 108 Arrays.equals(this.payload, that.payload);
106 } 109 }
107 110
111 + /**
112 + * Serializes this instance.
113 + * @return bytes
114 + */
115 + public byte[] getBytes() {
116 + byte[] senderBytes = sender.toString().getBytes(Charsets.UTF_8);
117 + byte[] subjectBytes = subject.value().getBytes(Charsets.UTF_8);
118 + int capacity = 12 + senderBytes.length + subjectBytes.length + payload.length;
119 + ByteBuffer buffer = ByteBuffer.allocate(capacity);
120 + buffer.putInt(senderBytes.length);
121 + buffer.put(senderBytes);
122 + buffer.putInt(subjectBytes.length);
123 + buffer.put(subjectBytes);
124 + buffer.putInt(payload.length);
125 + buffer.put(payload);
126 + return buffer.array();
127 + }
128 +
129 + /**
130 + * Decodes a new ClusterMessage from raw bytes.
131 + * @param bytes raw bytes
132 + * @return cluster message
133 + */
134 + public static ClusterMessage fromBytes(byte[] bytes) {
135 + ByteBuffer buffer = ByteBuffer.wrap(bytes);
136 + byte[] senderBytes = new byte[buffer.getInt()];
137 + buffer.get(senderBytes);
138 + byte[] subjectBytes = new byte[buffer.getInt()];
139 + buffer.get(subjectBytes);
140 + byte[] payloadBytes = new byte[buffer.getInt()];
141 + buffer.get(payloadBytes);
142 +
143 + return new ClusterMessage(new NodeId(new String(senderBytes, Charsets.UTF_8)),
144 + new MessageSubject(new String(senderBytes, Charsets.UTF_8)),
145 + payloadBytes);
146 + }
147 +
108 @Override 148 @Override
109 public int hashCode() { 149 public int hashCode() {
110 return Objects.hash(sender, subject, payload); 150 return Objects.hash(sender, subject, payload);
......
...@@ -28,7 +28,6 @@ import org.onlab.netty.Message; ...@@ -28,7 +28,6 @@ import org.onlab.netty.Message;
28 import org.onlab.netty.MessageHandler; 28 import org.onlab.netty.MessageHandler;
29 import org.onlab.netty.MessagingService; 29 import org.onlab.netty.MessagingService;
30 import org.onlab.netty.NettyMessagingService; 30 import org.onlab.netty.NettyMessagingService;
31 -import org.onlab.util.KryoNamespace;
32 import org.onosproject.cluster.ClusterService; 31 import org.onosproject.cluster.ClusterService;
33 import org.onosproject.cluster.ControllerNode; 32 import org.onosproject.cluster.ControllerNode;
34 import org.onosproject.cluster.NodeId; 33 import org.onosproject.cluster.NodeId;
...@@ -36,10 +35,6 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService; ...@@ -36,10 +35,6 @@ import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
36 import org.onosproject.store.cluster.messaging.ClusterMessage; 35 import org.onosproject.store.cluster.messaging.ClusterMessage;
37 import org.onosproject.store.cluster.messaging.ClusterMessageHandler; 36 import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
38 import org.onosproject.store.cluster.messaging.MessageSubject; 37 import org.onosproject.store.cluster.messaging.MessageSubject;
39 -import org.onosproject.store.serializers.KryoNamespaces;
40 -import org.onosproject.store.serializers.KryoSerializer;
41 -import org.onosproject.store.serializers.impl.ClusterMessageSerializer;
42 -import org.onosproject.store.serializers.impl.MessageSubjectSerializer;
43 import org.slf4j.Logger; 38 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory; 39 import org.slf4j.LoggerFactory;
45 40
...@@ -62,19 +57,6 @@ public class ClusterCommunicationManager ...@@ -62,19 +57,6 @@ public class ClusterCommunicationManager
62 // TODO: This probably should not be a OSGi service. 57 // TODO: This probably should not be a OSGi service.
63 private MessagingService messagingService; 58 private MessagingService messagingService;
64 59
65 - private static final KryoSerializer SERIALIZER = new KryoSerializer() {
66 - @Override
67 - protected void setupKryoPool() {
68 - serializerPool = KryoNamespace.newBuilder()
69 - .register(KryoNamespaces.API)
70 - .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
71 - .register(new ClusterMessageSerializer(), ClusterMessage.class)
72 - .register(new MessageSubjectSerializer(), MessageSubject.class)
73 - .build();
74 - }
75 -
76 - };
77 -
78 @Activate 60 @Activate
79 public void activate() { 61 public void activate() {
80 ControllerNode localNode = clusterService.getLocalNode(); 62 ControllerNode localNode = clusterService.getLocalNode();
...@@ -105,7 +87,7 @@ public class ClusterCommunicationManager ...@@ -105,7 +87,7 @@ public class ClusterCommunicationManager
105 public boolean broadcast(ClusterMessage message) { 87 public boolean broadcast(ClusterMessage message) {
106 boolean ok = true; 88 boolean ok = true;
107 final ControllerNode localNode = clusterService.getLocalNode(); 89 final ControllerNode localNode = clusterService.getLocalNode();
108 - byte[] payload = SERIALIZER.encode(message); 90 + byte[] payload = message.getBytes();
109 for (ControllerNode node : clusterService.getNodes()) { 91 for (ControllerNode node : clusterService.getNodes()) {
110 if (!node.equals(localNode)) { 92 if (!node.equals(localNode)) {
111 ok = unicastUnchecked(message.subject(), payload, node.id()) && ok; 93 ok = unicastUnchecked(message.subject(), payload, node.id()) && ok;
...@@ -117,7 +99,7 @@ public class ClusterCommunicationManager ...@@ -117,7 +99,7 @@ public class ClusterCommunicationManager
117 @Override 99 @Override
118 public boolean broadcastIncludeSelf(ClusterMessage message) { 100 public boolean broadcastIncludeSelf(ClusterMessage message) {
119 boolean ok = true; 101 boolean ok = true;
120 - byte[] payload = SERIALIZER.encode(message); 102 + byte[] payload = message.getBytes();
121 for (ControllerNode node : clusterService.getNodes()) { 103 for (ControllerNode node : clusterService.getNodes()) {
122 ok = unicastUnchecked(message.subject(), payload, node.id()) && ok; 104 ok = unicastUnchecked(message.subject(), payload, node.id()) && ok;
123 } 105 }
...@@ -128,7 +110,7 @@ public class ClusterCommunicationManager ...@@ -128,7 +110,7 @@ public class ClusterCommunicationManager
128 public boolean multicast(ClusterMessage message, Set<NodeId> nodes) { 110 public boolean multicast(ClusterMessage message, Set<NodeId> nodes) {
129 boolean ok = true; 111 boolean ok = true;
130 final ControllerNode localNode = clusterService.getLocalNode(); 112 final ControllerNode localNode = clusterService.getLocalNode();
131 - byte[] payload = SERIALIZER.encode(message); 113 + byte[] payload = message.getBytes();
132 for (NodeId nodeId : nodes) { 114 for (NodeId nodeId : nodes) {
133 if (!nodeId.equals(localNode.id())) { 115 if (!nodeId.equals(localNode.id())) {
134 ok = unicastUnchecked(message.subject(), payload, nodeId) && ok; 116 ok = unicastUnchecked(message.subject(), payload, nodeId) && ok;
...@@ -139,7 +121,7 @@ public class ClusterCommunicationManager ...@@ -139,7 +121,7 @@ public class ClusterCommunicationManager
139 121
140 @Override 122 @Override
141 public boolean unicast(ClusterMessage message, NodeId toNodeId) throws IOException { 123 public boolean unicast(ClusterMessage message, NodeId toNodeId) throws IOException {
142 - return unicast(message.subject(), SERIALIZER.encode(message), toNodeId); 124 + return unicast(message.subject(), message.getBytes(), toNodeId);
143 } 125 }
144 126
145 private boolean unicast(MessageSubject subject, byte[] payload, NodeId toNodeId) throws IOException { 127 private boolean unicast(MessageSubject subject, byte[] payload, NodeId toNodeId) throws IOException {
...@@ -170,7 +152,7 @@ public class ClusterCommunicationManager ...@@ -170,7 +152,7 @@ public class ClusterCommunicationManager
170 checkArgument(node != null, "Unknown nodeId: %s", toNodeId); 152 checkArgument(node != null, "Unknown nodeId: %s", toNodeId);
171 Endpoint nodeEp = new Endpoint(node.ip(), node.tcpPort()); 153 Endpoint nodeEp = new Endpoint(node.ip(), node.tcpPort());
172 try { 154 try {
173 - return messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message)); 155 + return messagingService.sendAndReceive(nodeEp, message.subject().value(), message.getBytes());
174 156
175 } catch (IOException e) { 157 } catch (IOException e) {
176 log.trace("Failed interaction with remote nodeId: " + toNodeId, e); 158 log.trace("Failed interaction with remote nodeId: " + toNodeId, e);
...@@ -209,7 +191,7 @@ public class ClusterCommunicationManager ...@@ -209,7 +191,7 @@ public class ClusterCommunicationManager
209 public void handle(Message message) { 191 public void handle(Message message) {
210 final ClusterMessage clusterMessage; 192 final ClusterMessage clusterMessage;
211 try { 193 try {
212 - clusterMessage = SERIALIZER.decode(message.payload()); 194 + clusterMessage = ClusterMessage.fromBytes(message.payload());
213 } catch (Exception e) { 195 } catch (Exception e) {
214 log.error("Failed decoding {}", message, e); 196 log.error("Failed decoding {}", message, e);
215 throw e; 197 throw e;
......
...@@ -87,9 +87,7 @@ public class NettyMessagingService implements MessagingService { ...@@ -87,9 +87,7 @@ public class NettyMessagingService implements MessagingService {
87 .build(); 87 .build();
88 88
89 private final LoadingCache<String, Long> messageTypeLookupCache = CacheBuilder.newBuilder() 89 private final LoadingCache<String, Long> messageTypeLookupCache = CacheBuilder.newBuilder()
90 - .softValues()
91 .build(new CacheLoader<String, Long>() { 90 .build(new CacheLoader<String, Long>() {
92 -
93 @Override 91 @Override
94 public Long load(String type) { 92 public Long load(String type) {
95 return hashToLong(type); 93 return hashToLong(type);
...@@ -171,6 +169,10 @@ public class NettyMessagingService implements MessagingService { ...@@ -171,6 +169,10 @@ public class NettyMessagingService implements MessagingService {
171 } 169 }
172 170
173 protected void sendAsync(Endpoint ep, InternalMessage message) throws IOException { 171 protected void sendAsync(Endpoint ep, InternalMessage message) throws IOException {
172 + if (ep.equals(localEp)) {
173 + dispatchLocally(message);
174 + return;
175 + }
174 Channel channel = null; 176 Channel channel = null;
175 try { 177 try {
176 try { 178 try {
...@@ -329,29 +331,7 @@ public class NettyMessagingService implements MessagingService { ...@@ -329,29 +331,7 @@ public class NettyMessagingService implements MessagingService {
329 331
330 @Override 332 @Override
331 protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception { 333 protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception {
332 - long type = message.type(); 334 + dispatchLocally(message);
333 - if (type == InternalMessage.REPLY_MESSAGE_TYPE) {
334 - try {
335 - SettableFuture<byte[]> futureResponse =
336 - NettyMessagingService.this.responseFutures.getIfPresent(message.id());
337 - if (futureResponse != null) {
338 - futureResponse.set(message.payload());
339 - } else {
340 - log.warn("Received a reply for message id:[{}]. "
341 - + " from {}. But was unable to locate the"
342 - + " request handle", message.id(), message.sender());
343 - }
344 - } finally {
345 - NettyMessagingService.this.responseFutures.invalidate(message.id());
346 - }
347 - return;
348 - }
349 - MessageHandler handler = NettyMessagingService.this.getMessageHandler(type);
350 - if (handler != null) {
351 - handler.handle(message);
352 - } else {
353 - log.debug("No handler registered for {}", type);
354 - }
355 } 335 }
356 336
357 @Override 337 @Override
...@@ -361,6 +341,32 @@ public class NettyMessagingService implements MessagingService { ...@@ -361,6 +341,32 @@ public class NettyMessagingService implements MessagingService {
361 } 341 }
362 } 342 }
363 343
344 + private void dispatchLocally(InternalMessage message) throws IOException {
345 + long type = message.type();
346 + if (type == InternalMessage.REPLY_MESSAGE_TYPE) {
347 + try {
348 + SettableFuture<byte[]> futureResponse =
349 + NettyMessagingService.this.responseFutures.getIfPresent(message.id());
350 + if (futureResponse != null) {
351 + futureResponse.set(message.payload());
352 + } else {
353 + log.warn("Received a reply for message id:[{}]. "
354 + + " from {}. But was unable to locate the"
355 + + " request handle", message.id(), message.sender());
356 + }
357 + } finally {
358 + NettyMessagingService.this.responseFutures.invalidate(message.id());
359 + }
360 + return;
361 + }
362 + MessageHandler handler = NettyMessagingService.this.getMessageHandler(type);
363 + if (handler != null) {
364 + handler.handle(message);
365 + } else {
366 + log.debug("No handler registered for {}", type);
367 + }
368 + }
369 +
364 /** 370 /**
365 * Returns the md5 hash of the specified input string as a long. 371 * Returns the md5 hash of the specified input string as a long.
366 * @param input input string. 372 * @param input input string.
......