Limit the amont of work that happens on netty event loop threads.
Currently we are kryo serializing/deserializing the message envelope which can potentially limit throughput. Change-Id: I0ae9dab53bbb765b7618ceaefda1edf4f77b0b59
Showing
9 changed files
with
126 additions
and
179 deletions
... | @@ -76,7 +76,7 @@ public class ClusterCommunicationManager | ... | @@ -76,7 +76,7 @@ public class ClusterCommunicationManager |
76 | @Activate | 76 | @Activate |
77 | public void activate() { | 77 | public void activate() { |
78 | ControllerNode localNode = clusterService.getLocalNode(); | 78 | ControllerNode localNode = clusterService.getLocalNode(); |
79 | - NettyMessagingService netty = new NettyMessagingService(localNode.ip().toString(), localNode.tcpPort()); | 79 | + NettyMessagingService netty = new NettyMessagingService(localNode.ip(), localNode.tcpPort()); |
80 | // FIXME: workaround until it becomes a service. | 80 | // FIXME: workaround until it becomes a service. |
81 | try { | 81 | try { |
82 | netty.activate(); | 82 | netty.activate(); |
... | @@ -143,7 +143,7 @@ public class ClusterCommunicationManager | ... | @@ -143,7 +143,7 @@ public class ClusterCommunicationManager |
143 | private boolean unicast(MessageSubject subject, byte[] payload, NodeId toNodeId) throws IOException { | 143 | private boolean unicast(MessageSubject subject, byte[] payload, NodeId toNodeId) throws IOException { |
144 | ControllerNode node = clusterService.getNode(toNodeId); | 144 | ControllerNode node = clusterService.getNode(toNodeId); |
145 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); | 145 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); |
146 | - Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort()); | 146 | + Endpoint nodeEp = new Endpoint(node.ip(), node.tcpPort()); |
147 | try { | 147 | try { |
148 | messagingService.sendAsync(nodeEp, subject.value(), payload); | 148 | messagingService.sendAsync(nodeEp, subject.value(), payload); |
149 | return true; | 149 | return true; |
... | @@ -166,7 +166,7 @@ public class ClusterCommunicationManager | ... | @@ -166,7 +166,7 @@ public class ClusterCommunicationManager |
166 | public ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException { | 166 | public ListenableFuture<byte[]> sendAndReceive(ClusterMessage message, NodeId toNodeId) throws IOException { |
167 | ControllerNode node = clusterService.getNode(toNodeId); | 167 | ControllerNode node = clusterService.getNode(toNodeId); |
168 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); | 168 | checkArgument(node != null, "Unknown nodeId: %s", toNodeId); |
169 | - Endpoint nodeEp = new Endpoint(node.ip().toString(), node.tcpPort()); | 169 | + Endpoint nodeEp = new Endpoint(node.ip(), node.tcpPort()); |
170 | try { | 170 | try { |
171 | return messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message)); | 171 | return messagingService.sendAndReceive(nodeEp, message.subject().value(), SERIALIZER.encode(message)); |
172 | 172 | ... | ... |
... | @@ -19,9 +19,11 @@ package org.onlab.netty; | ... | @@ -19,9 +19,11 @@ package org.onlab.netty; |
19 | * State transitions a decoder goes through as it is decoding an incoming message. | 19 | * State transitions a decoder goes through as it is decoding an incoming message. |
20 | */ | 20 | */ |
21 | public enum DecoderState { | 21 | public enum DecoderState { |
22 | - READ_HEADER_VERSION, | 22 | + READ_MESSAGE_ID, |
23 | - READ_PREAMBLE, | 23 | + READ_SENDER_IP_VERSION, |
24 | + READ_SENDER_IP, | ||
25 | + READ_SENDER_PORT, | ||
26 | + READ_MESSAGE_TYPE, | ||
24 | READ_CONTENT_LENGTH, | 27 | READ_CONTENT_LENGTH, |
25 | - READ_SERIALIZER_VERSION, | ||
26 | READ_CONTENT | 28 | READ_CONTENT |
27 | } | 29 | } | ... | ... |
... | @@ -15,8 +15,12 @@ | ... | @@ -15,8 +15,12 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.netty; | 16 | package org.onlab.netty; |
17 | 17 | ||
18 | +import static com.google.common.base.Preconditions.*; | ||
19 | + | ||
18 | import java.util.Objects; | 20 | import java.util.Objects; |
19 | 21 | ||
22 | +import org.onlab.packet.IpAddress; | ||
23 | + | ||
20 | import com.google.common.base.MoreObjects; | 24 | import com.google.common.base.MoreObjects; |
21 | 25 | ||
22 | /** | 26 | /** |
... | @@ -25,15 +29,15 @@ import com.google.common.base.MoreObjects; | ... | @@ -25,15 +29,15 @@ import com.google.common.base.MoreObjects; |
25 | public final class Endpoint { | 29 | public final class Endpoint { |
26 | 30 | ||
27 | private final int port; | 31 | private final int port; |
28 | - private final String host; | 32 | + private final IpAddress ip; |
29 | 33 | ||
30 | - public Endpoint(String host, int port) { | 34 | + public Endpoint(IpAddress host, int port) { |
31 | - this.host = host; | 35 | + this.ip = checkNotNull(host); |
32 | this.port = port; | 36 | this.port = port; |
33 | } | 37 | } |
34 | 38 | ||
35 | - public String host() { | 39 | + public IpAddress host() { |
36 | - return host; | 40 | + return ip; |
37 | } | 41 | } |
38 | 42 | ||
39 | public int port() { | 43 | public int port() { |
... | @@ -43,14 +47,14 @@ public final class Endpoint { | ... | @@ -43,14 +47,14 @@ public final class Endpoint { |
43 | @Override | 47 | @Override |
44 | public String toString() { | 48 | public String toString() { |
45 | return MoreObjects.toStringHelper(getClass()) | 49 | return MoreObjects.toStringHelper(getClass()) |
46 | - .add("host", host) | 50 | + .add("ip", ip) |
47 | .add("port", port) | 51 | .add("port", port) |
48 | .toString(); | 52 | .toString(); |
49 | } | 53 | } |
50 | 54 | ||
51 | @Override | 55 | @Override |
52 | public int hashCode() { | 56 | public int hashCode() { |
53 | - return Objects.hash(host, port); | 57 | + return Objects.hash(ip, port); |
54 | } | 58 | } |
55 | 59 | ||
56 | @Override | 60 | @Override |
... | @@ -66,6 +70,6 @@ public final class Endpoint { | ... | @@ -66,6 +70,6 @@ public final class Endpoint { |
66 | } | 70 | } |
67 | Endpoint that = (Endpoint) obj; | 71 | Endpoint that = (Endpoint) obj; |
68 | return Objects.equals(this.port, that.port) && | 72 | return Objects.equals(this.port, that.port) && |
69 | - Objects.equals(this.host, that.host); | 73 | + Objects.equals(this.ip, that.ip); |
70 | } | 74 | } |
71 | } | 75 | } | ... | ... |
... | @@ -27,18 +27,19 @@ import com.google.common.base.MoreObjects; | ... | @@ -27,18 +27,19 @@ import com.google.common.base.MoreObjects; |
27 | */ | 27 | */ |
28 | public final class InternalMessage implements Message { | 28 | public final class InternalMessage implements Message { |
29 | 29 | ||
30 | - public static final String REPLY_MESSAGE_TYPE = "NETTY_MESSAGING_REQUEST_REPLY"; | 30 | + public static final long REPLY_MESSAGE_TYPE = |
31 | + NettyMessagingService.hashToLong("NETTY_MESSAGING_REQUEST_REPLY"); | ||
31 | 32 | ||
32 | private long id; | 33 | private long id; |
33 | private Endpoint sender; | 34 | private Endpoint sender; |
34 | - private String type; | 35 | + private long type; |
35 | private byte[] payload; | 36 | private byte[] payload; |
36 | private transient NettyMessagingService messagingService; | 37 | private transient NettyMessagingService messagingService; |
37 | 38 | ||
38 | // Must be created using the Builder. | 39 | // Must be created using the Builder. |
39 | private InternalMessage() {} | 40 | private InternalMessage() {} |
40 | 41 | ||
41 | - InternalMessage(long id, Endpoint sender, String type, byte[] payload) { | 42 | + InternalMessage(long id, Endpoint sender, long type, byte[] payload) { |
42 | this.id = id; | 43 | this.id = id; |
43 | this.sender = sender; | 44 | this.sender = sender; |
44 | this.type = type; | 45 | this.type = type; |
... | @@ -49,7 +50,7 @@ public final class InternalMessage implements Message { | ... | @@ -49,7 +50,7 @@ public final class InternalMessage implements Message { |
49 | return id; | 50 | return id; |
50 | } | 51 | } |
51 | 52 | ||
52 | - public String type() { | 53 | + public long type() { |
53 | return type; | 54 | return type; |
54 | } | 55 | } |
55 | 56 | ||
... | @@ -103,7 +104,7 @@ public final class InternalMessage implements Message { | ... | @@ -103,7 +104,7 @@ public final class InternalMessage implements Message { |
103 | return this; | 104 | return this; |
104 | } | 105 | } |
105 | 106 | ||
106 | - public Builder withType(String type) { | 107 | + public Builder withType(long type) { |
107 | message.type = type; | 108 | message.type = type; |
108 | return this; | 109 | return this; |
109 | } | 110 | } | ... | ... |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.netty; | ||
17 | - | ||
18 | -import org.onlab.util.KryoNamespace; | ||
19 | - | ||
20 | -import com.esotericsoftware.kryo.Kryo; | ||
21 | -import com.esotericsoftware.kryo.Serializer; | ||
22 | -import com.esotericsoftware.kryo.io.Input; | ||
23 | -import com.esotericsoftware.kryo.io.Output; | ||
24 | - | ||
25 | -import java.nio.ByteBuffer; | ||
26 | - | ||
27 | -/** | ||
28 | - * Kryo Serializer. | ||
29 | - */ | ||
30 | -public class KryoSerializer { | ||
31 | - | ||
32 | - private KryoNamespace serializerPool; | ||
33 | - | ||
34 | - public KryoSerializer() { | ||
35 | - setupKryoPool(); | ||
36 | - } | ||
37 | - | ||
38 | - /** | ||
39 | - * Sets up the common serialzers pool. | ||
40 | - */ | ||
41 | - protected void setupKryoPool() { | ||
42 | - serializerPool = KryoNamespace.newBuilder() | ||
43 | - .register(byte[].class) | ||
44 | - .register(new InternalMessageSerializer(), InternalMessage.class) | ||
45 | - .register(new EndPointSerializer(), Endpoint.class) | ||
46 | - .build(); | ||
47 | - } | ||
48 | - | ||
49 | - | ||
50 | - public <T> T decode(byte[] data) { | ||
51 | - return serializerPool.deserialize(data); | ||
52 | - } | ||
53 | - | ||
54 | - public byte[] encode(Object payload) { | ||
55 | - return serializerPool.serialize(payload); | ||
56 | - } | ||
57 | - | ||
58 | - public <T> T decode(ByteBuffer buffer) { | ||
59 | - return serializerPool.deserialize(buffer); | ||
60 | - } | ||
61 | - | ||
62 | - public void encode(Object obj, ByteBuffer buffer) { | ||
63 | - serializerPool.serialize(obj, buffer); | ||
64 | - } | ||
65 | - | ||
66 | - public static final class InternalMessageSerializer | ||
67 | - extends Serializer<InternalMessage> { | ||
68 | - | ||
69 | - @Override | ||
70 | - public void write(Kryo kryo, Output output, InternalMessage object) { | ||
71 | - output.writeLong(object.id()); | ||
72 | - kryo.writeClassAndObject(output, object.sender()); | ||
73 | - output.writeString(object.type()); | ||
74 | - output.writeInt(object.payload().length, true); | ||
75 | - output.writeBytes(object.payload()); | ||
76 | - } | ||
77 | - | ||
78 | - @Override | ||
79 | - public InternalMessage read(Kryo kryo, Input input, | ||
80 | - Class<InternalMessage> type) { | ||
81 | - long id = input.readLong(); | ||
82 | - Endpoint sender = (Endpoint) kryo.readClassAndObject(input); | ||
83 | - String msgtype = input.readString(); | ||
84 | - int length = input.readInt(true); | ||
85 | - byte[] payload = input.readBytes(length); | ||
86 | - return new InternalMessage(id, sender, msgtype, payload); | ||
87 | - } | ||
88 | - | ||
89 | - } | ||
90 | - | ||
91 | - public static final class EndPointSerializer extends Serializer<Endpoint> { | ||
92 | - | ||
93 | - @Override | ||
94 | - public void write(Kryo kryo, Output output, Endpoint object) { | ||
95 | - output.writeString(object.host()); | ||
96 | - output.writeInt(object.port()); | ||
97 | - } | ||
98 | - | ||
99 | - @Override | ||
100 | - public Endpoint read(Kryo kryo, Input input, Class<Endpoint> type) { | ||
101 | - String host = input.readString(); | ||
102 | - int port = input.readInt(); | ||
103 | - return new Endpoint(host, port); | ||
104 | - } | ||
105 | - } | ||
106 | -} |
... | @@ -20,9 +20,10 @@ import io.netty.buffer.ByteBuf; | ... | @@ -20,9 +20,10 @@ import io.netty.buffer.ByteBuf; |
20 | import io.netty.channel.ChannelHandlerContext; | 20 | import io.netty.channel.ChannelHandlerContext; |
21 | import io.netty.handler.codec.ReplayingDecoder; | 21 | import io.netty.handler.codec.ReplayingDecoder; |
22 | 22 | ||
23 | -import java.util.Arrays; | ||
24 | import java.util.List; | 23 | import java.util.List; |
25 | 24 | ||
25 | +import org.onlab.packet.IpAddress; | ||
26 | +import org.onlab.packet.IpAddress.Version; | ||
26 | import org.slf4j.Logger; | 27 | import org.slf4j.Logger; |
27 | import org.slf4j.LoggerFactory; | 28 | import org.slf4j.LoggerFactory; |
28 | 29 | ||
... | @@ -35,12 +36,15 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -35,12 +36,15 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
35 | 36 | ||
36 | private final NettyMessagingService messagingService; | 37 | private final NettyMessagingService messagingService; |
37 | 38 | ||
38 | - private static final KryoSerializer SERIALIZER = new KryoSerializer(); | 39 | + private long messageId; |
39 | - | 40 | + private Version ipVersion; |
41 | + private IpAddress senderIp; | ||
42 | + private int senderPort; | ||
40 | private int contentLength; | 43 | private int contentLength; |
44 | + private long messageType; | ||
41 | 45 | ||
42 | public MessageDecoder(NettyMessagingService messagingService) { | 46 | public MessageDecoder(NettyMessagingService messagingService) { |
43 | - super(DecoderState.READ_HEADER_VERSION); | 47 | + super(DecoderState.READ_MESSAGE_ID); |
44 | this.messagingService = messagingService; | 48 | this.messagingService = messagingService; |
45 | } | 49 | } |
46 | 50 | ||
... | @@ -51,27 +55,37 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { | ... | @@ -51,27 +55,37 @@ public class MessageDecoder extends ReplayingDecoder<DecoderState> { |
51 | List<Object> out) throws Exception { | 55 | List<Object> out) throws Exception { |
52 | 56 | ||
53 | switch (state()) { | 57 | switch (state()) { |
54 | - case READ_HEADER_VERSION: | 58 | + case READ_MESSAGE_ID: |
55 | - int headerVersion = buffer.readInt(); | 59 | + messageId = buffer.readLong(); |
56 | - checkState(headerVersion == MessageEncoder.HEADER_VERSION, "Unexpected header version"); | 60 | + checkpoint(DecoderState.READ_SENDER_IP_VERSION); |
57 | - checkpoint(DecoderState.READ_PREAMBLE); | 61 | + case READ_SENDER_IP_VERSION: |
58 | - case READ_PREAMBLE: | 62 | + ipVersion = buffer.readByte() == 0x0 ? Version.INET : Version.INET6; |
59 | - byte[] preamble = new byte[MessageEncoder.PREAMBLE.length]; | 63 | + checkpoint(DecoderState.READ_SENDER_IP); |
60 | - buffer.readBytes(preamble); | 64 | + case READ_SENDER_IP: |
61 | - checkState(Arrays.equals(MessageEncoder.PREAMBLE, preamble), "Message has wrong preamble"); | 65 | + byte[] octects = new byte[IpAddress.byteLength(ipVersion)]; |
66 | + buffer.readBytes(octects); | ||
67 | + senderIp = IpAddress.valueOf(ipVersion, octects); | ||
68 | + checkpoint(DecoderState.READ_SENDER_PORT); | ||
69 | + case READ_SENDER_PORT: | ||
70 | + senderPort = buffer.readInt(); | ||
71 | + checkpoint(DecoderState.READ_MESSAGE_TYPE); | ||
72 | + case READ_MESSAGE_TYPE: | ||
73 | + messageType = buffer.readLong(); | ||
62 | checkpoint(DecoderState.READ_CONTENT_LENGTH); | 74 | checkpoint(DecoderState.READ_CONTENT_LENGTH); |
63 | case READ_CONTENT_LENGTH: | 75 | case READ_CONTENT_LENGTH: |
64 | contentLength = buffer.readInt(); | 76 | contentLength = buffer.readInt(); |
65 | - checkpoint(DecoderState.READ_SERIALIZER_VERSION); | ||
66 | - case READ_SERIALIZER_VERSION: | ||
67 | - int serializerVersion = buffer.readInt(); | ||
68 | - checkState(serializerVersion == MessageEncoder.SERIALIZER_VERSION, "Unexpected serializer version"); | ||
69 | checkpoint(DecoderState.READ_CONTENT); | 77 | checkpoint(DecoderState.READ_CONTENT); |
70 | case READ_CONTENT: | 78 | case READ_CONTENT: |
71 | - InternalMessage message = SERIALIZER.decode(buffer.readBytes(contentLength).nioBuffer()); | 79 | + byte[] payload = new byte[contentLength]; |
80 | + buffer.readBytes(payload); | ||
81 | + InternalMessage message = new InternalMessage( | ||
82 | + messageId, | ||
83 | + new Endpoint(senderIp, senderPort), | ||
84 | + messageType, | ||
85 | + payload); | ||
72 | message.setMessagingService(messagingService); | 86 | message.setMessagingService(messagingService); |
73 | out.add(message); | 87 | out.add(message); |
74 | - checkpoint(DecoderState.READ_HEADER_VERSION); | 88 | + checkpoint(DecoderState.READ_MESSAGE_ID); |
75 | break; | 89 | break; |
76 | default: | 90 | default: |
77 | checkState(false, "Must not be here"); | 91 | checkState(false, "Must not be here"); | ... | ... |
... | @@ -15,17 +15,18 @@ | ... | @@ -15,17 +15,18 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.netty; | 16 | package org.onlab.netty; |
17 | 17 | ||
18 | -import java.io.IOException; | ||
19 | -import java.nio.charset.StandardCharsets; | ||
20 | - | ||
21 | -import org.slf4j.Logger; | ||
22 | -import org.slf4j.LoggerFactory; | ||
23 | - | ||
24 | import io.netty.buffer.ByteBuf; | 18 | import io.netty.buffer.ByteBuf; |
25 | import io.netty.channel.ChannelHandler.Sharable; | 19 | import io.netty.channel.ChannelHandler.Sharable; |
26 | import io.netty.channel.ChannelHandlerContext; | 20 | import io.netty.channel.ChannelHandlerContext; |
27 | import io.netty.handler.codec.MessageToByteEncoder; | 21 | import io.netty.handler.codec.MessageToByteEncoder; |
28 | 22 | ||
23 | +import java.io.IOException; | ||
24 | + | ||
25 | +import org.onlab.packet.IpAddress; | ||
26 | +import org.onlab.packet.IpAddress.Version; | ||
27 | +import org.slf4j.Logger; | ||
28 | +import org.slf4j.LoggerFactory; | ||
29 | + | ||
29 | /** | 30 | /** |
30 | * Encode InternalMessage out into a byte buffer. | 31 | * Encode InternalMessage out into a byte buffer. |
31 | */ | 32 | */ |
... | @@ -34,34 +35,36 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { | ... | @@ -34,34 +35,36 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { |
34 | 35 | ||
35 | private final Logger log = LoggerFactory.getLogger(getClass()); | 36 | private final Logger log = LoggerFactory.getLogger(getClass()); |
36 | 37 | ||
37 | - // onosiscool in ascii | ||
38 | - static final byte[] PREAMBLE = "onosiscool".getBytes(StandardCharsets.US_ASCII); | ||
39 | - public static final int HEADER_VERSION = 1; | ||
40 | - public static final int SERIALIZER_VERSION = 1; | ||
41 | - | ||
42 | - | ||
43 | - private static final KryoSerializer SERIALIZER = new KryoSerializer(); | ||
44 | - | ||
45 | @Override | 38 | @Override |
46 | protected void encode( | 39 | protected void encode( |
47 | ChannelHandlerContext context, | 40 | ChannelHandlerContext context, |
48 | InternalMessage message, | 41 | InternalMessage message, |
49 | ByteBuf out) throws Exception { | 42 | ByteBuf out) throws Exception { |
50 | 43 | ||
51 | - // write version | 44 | + // write message id |
52 | - out.writeInt(HEADER_VERSION); | 45 | + out.writeLong(message.id()); |
53 | 46 | ||
54 | - // write preamble | 47 | + Endpoint sender = message.sender(); |
55 | - out.writeBytes(PREAMBLE); | ||
56 | 48 | ||
57 | - byte[] payload = SERIALIZER.encode(message); | 49 | + IpAddress senderIp = sender.host(); |
50 | + if (senderIp.version() == Version.INET) { | ||
51 | + out.writeByte(0); | ||
52 | + } else { | ||
53 | + out.writeByte(1); | ||
54 | + } | ||
55 | + out.writeBytes(senderIp.toOctets()); | ||
56 | + | ||
57 | + // write sender port | ||
58 | + out.writeInt(sender.port()); | ||
59 | + | ||
60 | + // write message type. | ||
61 | + out.writeLong(message.type()); | ||
62 | + | ||
63 | + byte[] payload = message.payload(); | ||
58 | 64 | ||
59 | // write payload length | 65 | // write payload length |
60 | out.writeInt(payload.length); | 66 | out.writeInt(payload.length); |
61 | 67 | ||
62 | - // write payloadSerializer version | ||
63 | - out.writeInt(SERIALIZER_VERSION); | ||
64 | - | ||
65 | // write payload. | 68 | // write payload. |
66 | out.writeBytes(payload); | 69 | out.writeBytes(payload); |
67 | } | 70 | } | ... | ... |
... | @@ -37,6 +37,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; | ... | @@ -37,6 +37,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; |
37 | import io.netty.channel.socket.nio.NioSocketChannel; | 37 | import io.netty.channel.socket.nio.NioSocketChannel; |
38 | 38 | ||
39 | import java.io.IOException; | 39 | import java.io.IOException; |
40 | +import java.net.InetAddress; | ||
40 | import java.net.UnknownHostException; | 41 | import java.net.UnknownHostException; |
41 | import java.util.concurrent.ConcurrentHashMap; | 42 | import java.util.concurrent.ConcurrentHashMap; |
42 | import java.util.concurrent.ConcurrentMap; | 43 | import java.util.concurrent.ConcurrentMap; |
... | @@ -46,13 +47,18 @@ import java.util.concurrent.atomic.AtomicLong; | ... | @@ -46,13 +47,18 @@ import java.util.concurrent.atomic.AtomicLong; |
46 | 47 | ||
47 | import org.apache.commons.pool.KeyedPoolableObjectFactory; | 48 | import org.apache.commons.pool.KeyedPoolableObjectFactory; |
48 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; | 49 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; |
50 | +import org.onlab.packet.IpAddress; | ||
49 | import org.slf4j.Logger; | 51 | import org.slf4j.Logger; |
50 | import org.slf4j.LoggerFactory; | 52 | import org.slf4j.LoggerFactory; |
51 | 53 | ||
54 | +import com.google.common.base.Charsets; | ||
52 | import com.google.common.cache.Cache; | 55 | import com.google.common.cache.Cache; |
53 | import com.google.common.cache.CacheBuilder; | 56 | import com.google.common.cache.CacheBuilder; |
57 | +import com.google.common.cache.CacheLoader; | ||
58 | +import com.google.common.cache.LoadingCache; | ||
54 | import com.google.common.cache.RemovalListener; | 59 | import com.google.common.cache.RemovalListener; |
55 | import com.google.common.cache.RemovalNotification; | 60 | import com.google.common.cache.RemovalNotification; |
61 | +import com.google.common.hash.Hashing; | ||
56 | import com.google.common.util.concurrent.ListenableFuture; | 62 | import com.google.common.util.concurrent.ListenableFuture; |
57 | import com.google.common.util.concurrent.SettableFuture; | 63 | import com.google.common.util.concurrent.SettableFuture; |
58 | 64 | ||
... | @@ -64,7 +70,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -64,7 +70,7 @@ public class NettyMessagingService implements MessagingService { |
64 | private final Logger log = LoggerFactory.getLogger(getClass()); | 70 | private final Logger log = LoggerFactory.getLogger(getClass()); |
65 | 71 | ||
66 | private final Endpoint localEp; | 72 | private final Endpoint localEp; |
67 | - private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>(); | 73 | + private final ConcurrentMap<Long, MessageHandler> handlers = new ConcurrentHashMap<>(); |
68 | private final AtomicLong messageIdGenerator = new AtomicLong(0); | 74 | private final AtomicLong messageIdGenerator = new AtomicLong(0); |
69 | private final Cache<Long, SettableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() | 75 | private final Cache<Long, SettableFuture<byte[]>> responseFutures = CacheBuilder.newBuilder() |
70 | .maximumSize(100000) | 76 | .maximumSize(100000) |
... | @@ -78,6 +84,17 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -78,6 +84,17 @@ public class NettyMessagingService implements MessagingService { |
78 | } | 84 | } |
79 | }) | 85 | }) |
80 | .build(); | 86 | .build(); |
87 | + | ||
88 | + private final LoadingCache<String, Long> messageTypeLookupCache = CacheBuilder.newBuilder() | ||
89 | + .softValues() | ||
90 | + .build(new CacheLoader<String, Long>() { | ||
91 | + | ||
92 | + @Override | ||
93 | + public Long load(String type) { | ||
94 | + return hashToLong(type); | ||
95 | + } | ||
96 | + }); | ||
97 | + | ||
81 | private final GenericKeyedObjectPool<Endpoint, Channel> channels | 98 | private final GenericKeyedObjectPool<Endpoint, Channel> channels |
82 | = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory()); | 99 | = new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory()); |
83 | 100 | ||
... | @@ -103,7 +120,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -103,7 +120,7 @@ public class NettyMessagingService implements MessagingService { |
103 | clientChannelClass = NioSocketChannel.class; | 120 | clientChannelClass = NioSocketChannel.class; |
104 | } | 121 | } |
105 | 122 | ||
106 | - public NettyMessagingService(String ip, int port) { | 123 | + public NettyMessagingService(IpAddress ip, int port) { |
107 | localEp = new Endpoint(ip, port); | 124 | localEp = new Endpoint(ip, port); |
108 | } | 125 | } |
109 | 126 | ||
... | @@ -113,7 +130,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -113,7 +130,7 @@ public class NettyMessagingService implements MessagingService { |
113 | 130 | ||
114 | public NettyMessagingService(int port) { | 131 | public NettyMessagingService(int port) { |
115 | try { | 132 | try { |
116 | - localEp = new Endpoint(java.net.InetAddress.getLocalHost().getHostName(), port); | 133 | + localEp = new Endpoint(IpAddress.valueOf(InetAddress.getLocalHost()), port); |
117 | } catch (UnknownHostException e) { | 134 | } catch (UnknownHostException e) { |
118 | // Cannot resolve the local host, something is very wrong. Bailing out. | 135 | // Cannot resolve the local host, something is very wrong. Bailing out. |
119 | throw new IllegalStateException("Cannot resolve local host", e); | 136 | throw new IllegalStateException("Cannot resolve local host", e); |
... | @@ -146,7 +163,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -146,7 +163,7 @@ public class NettyMessagingService implements MessagingService { |
146 | InternalMessage message = new InternalMessage.Builder(this) | 163 | InternalMessage message = new InternalMessage.Builder(this) |
147 | .withId(messageIdGenerator.incrementAndGet()) | 164 | .withId(messageIdGenerator.incrementAndGet()) |
148 | .withSender(localEp) | 165 | .withSender(localEp) |
149 | - .withType(type) | 166 | + .withType(messageTypeLookupCache.getUnchecked(type)) |
150 | .withPayload(payload) | 167 | .withPayload(payload) |
151 | .build(); | 168 | .build(); |
152 | sendAsync(ep, message); | 169 | sendAsync(ep, message); |
... | @@ -178,7 +195,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -178,7 +195,7 @@ public class NettyMessagingService implements MessagingService { |
178 | InternalMessage message = new InternalMessage.Builder(this) | 195 | InternalMessage message = new InternalMessage.Builder(this) |
179 | .withId(messageId) | 196 | .withId(messageId) |
180 | .withSender(localEp) | 197 | .withSender(localEp) |
181 | - .withType(type) | 198 | + .withType(messageTypeLookupCache.getUnchecked(type)) |
182 | .withPayload(payload) | 199 | .withPayload(payload) |
183 | .build(); | 200 | .build(); |
184 | try { | 201 | try { |
... | @@ -192,7 +209,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -192,7 +209,7 @@ public class NettyMessagingService implements MessagingService { |
192 | 209 | ||
193 | @Override | 210 | @Override |
194 | public void registerHandler(String type, MessageHandler handler) { | 211 | public void registerHandler(String type, MessageHandler handler) { |
195 | - handlers.putIfAbsent(type, handler); | 212 | + handlers.putIfAbsent(hashToLong(type), handler); |
196 | } | 213 | } |
197 | 214 | ||
198 | @Override | 215 | @Override |
... | @@ -200,7 +217,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -200,7 +217,7 @@ public class NettyMessagingService implements MessagingService { |
200 | handlers.remove(type); | 217 | handlers.remove(type); |
201 | } | 218 | } |
202 | 219 | ||
203 | - private MessageHandler getMessageHandler(String type) { | 220 | + private MessageHandler getMessageHandler(long type) { |
204 | return handlers.get(type); | 221 | return handlers.get(type); |
205 | } | 222 | } |
206 | 223 | ||
... | @@ -245,7 +262,7 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -245,7 +262,7 @@ public class NettyMessagingService implements MessagingService { |
245 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); | 262 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); |
246 | bootstrap.handler(new OnosCommunicationChannelInitializer()); | 263 | bootstrap.handler(new OnosCommunicationChannelInitializer()); |
247 | // Start the client. | 264 | // Start the client. |
248 | - ChannelFuture f = bootstrap.connect(ep.host(), ep.port()).sync(); | 265 | + ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); |
249 | return f.channel(); | 266 | return f.channel(); |
250 | } | 267 | } |
251 | 268 | ||
... | @@ -295,8 +312,8 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -295,8 +312,8 @@ public class NettyMessagingService implements MessagingService { |
295 | 312 | ||
296 | @Override | 313 | @Override |
297 | protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception { | 314 | protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception { |
298 | - String type = message.type(); | 315 | + long type = message.type(); |
299 | - if (type.equals(InternalMessage.REPLY_MESSAGE_TYPE)) { | 316 | + if (type == InternalMessage.REPLY_MESSAGE_TYPE) { |
300 | try { | 317 | try { |
301 | SettableFuture<byte[]> futureResponse = | 318 | SettableFuture<byte[]> futureResponse = |
302 | NettyMessagingService.this.responseFutures.getIfPresent(message.id()); | 319 | NettyMessagingService.this.responseFutures.getIfPresent(message.id()); |
... | @@ -326,4 +343,13 @@ public class NettyMessagingService implements MessagingService { | ... | @@ -326,4 +343,13 @@ public class NettyMessagingService implements MessagingService { |
326 | context.close(); | 343 | context.close(); |
327 | } | 344 | } |
328 | } | 345 | } |
346 | + | ||
347 | + /** | ||
348 | + * Returns the md5 hash of the specified input string as a long. | ||
349 | + * @param input input string. | ||
350 | + * @return md5 hash as long. | ||
351 | + */ | ||
352 | + public static long hashToLong(String input) { | ||
353 | + return Hashing.md5().hashBytes(input.getBytes(Charsets.UTF_8)).asLong(); | ||
354 | + } | ||
329 | } | 355 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -15,15 +15,16 @@ | ... | @@ -15,15 +15,16 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.netty; | 16 | package org.onlab.netty; |
17 | 17 | ||
18 | +import static org.junit.Assert.assertArrayEquals; | ||
19 | + | ||
20 | +import java.net.InetAddress; | ||
18 | import java.util.concurrent.Future; | 21 | import java.util.concurrent.Future; |
19 | import java.util.concurrent.TimeUnit; | 22 | import java.util.concurrent.TimeUnit; |
20 | 23 | ||
21 | import org.apache.commons.lang3.RandomUtils; | 24 | import org.apache.commons.lang3.RandomUtils; |
22 | - | ||
23 | -import static org.junit.Assert.*; | ||
24 | - | ||
25 | import org.junit.Ignore; | 25 | import org.junit.Ignore; |
26 | import org.junit.Test; | 26 | import org.junit.Test; |
27 | +import org.onlab.packet.IpAddress; | ||
27 | 28 | ||
28 | /** | 29 | /** |
29 | * Simple ping-pong test that exercises NettyMessagingService. | 30 | * Simple ping-pong test that exercises NettyMessagingService. |
... | @@ -40,7 +41,9 @@ public class PingPongTest { | ... | @@ -40,7 +41,9 @@ public class PingPongTest { |
40 | ponger.activate(); | 41 | ponger.activate(); |
41 | ponger.registerHandler("echo", new EchoHandler()); | 42 | ponger.registerHandler("echo", new EchoHandler()); |
42 | byte[] payload = RandomUtils.nextBytes(100); | 43 | byte[] payload = RandomUtils.nextBytes(100); |
43 | - Future<byte[]> responseFuture = pinger.sendAndReceive(new Endpoint("localhost", 9086), "echo", payload); | 44 | + Future<byte[]> responseFuture = |
45 | + pinger.sendAndReceive( | ||
46 | + new Endpoint(IpAddress.valueOf(InetAddress.getLocalHost()), 9086), "echo", payload); | ||
44 | assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS)); | 47 | assertArrayEquals(payload, responseFuture.get(10000, TimeUnit.MILLISECONDS)); |
45 | } finally { | 48 | } finally { |
46 | pinger.deactivate(); | 49 | pinger.deactivate(); | ... | ... |
-
Please register or login to post a comment