From 20aa2e1968501fbb4b0977b91d43fd865b42063e Mon Sep 17 00:00:00 2001 From: "Andrei.Pozolotin" Date: Mon, 7 Jan 2013 09:44:41 -0600 Subject: [PATCH] [#844] [#867] Add UDT transport --- example/.gitignore | 7 + example/pom.xml | 15 +- .../udt/echo/bytes/ByteEchoClient.java | 106 +++++++ .../udt/echo/bytes/ByteEchoClientHandler.java | 87 ++++++ .../udt/echo/bytes/ByteEchoServer.java | 94 ++++++ .../udt/echo/bytes/ByteEchoServerHandler.java | 66 +++++ .../example/udt/echo/bytes/package-info.java | 21 ++ .../udt/echo/message/MsgEchoClient.java | 106 +++++++ .../echo/message/MsgEchoClientHandler.java | 84 ++++++ .../udt/echo/message/MsgEchoServer.java | 94 ++++++ .../echo/message/MsgEchoServerHandler.java | 61 ++++ .../udt/echo/message/package-info.java | 21 ++ .../netty/example/udt/echo/package-info.java | 21 ++ .../example/udt/echo/rendevous/Config.java | 32 +++ .../udt/echo/rendevous/MsgEchoPeerBase.java | 85 ++++++ .../echo/rendevous/MsgEchoPeerHandler.java | 84 ++++++ .../udt/echo/rendevous/MsgEchoPeerOne.java | 52 ++++ .../udt/echo/rendevous/MsgEchoPeerTwo.java | 55 ++++ .../udt/echo/rendevous/package-info.java | 21 ++ .../io/netty/example/udt/package-info.java | 21 ++ .../example/udt/util/UtilConsoleReporter.java | 250 ++++++++++++++++ .../example/udt/util/UtilThreadFactory.java | 40 +++ .../netty/example/udt/util/package-info.java | 21 ++ pom.xml | 7 +- transport-udt/.gitignore | 7 + transport-udt/pom.xml | 101 +++++++ .../udt/DefaultUdtChannelConfig.java | 250 ++++++++++++++++ .../io/netty/transport/udt/UdtChannel.java | 34 +++ .../netty/transport/udt/UdtChannelConfig.java | 185 ++++++++++++ .../io/netty/transport/udt/UdtMessage.java | 40 +++ .../udt/nio/NioUdtAcceptorChannel.java | 128 +++++++++ .../udt/nio/NioUdtByteAcceptorChannel.java | 59 ++++ .../udt/nio/NioUdtByteConnectorChannel.java | 194 +++++++++++++ .../udt/nio/NioUdtByteRendezvousChannel.java | 37 +++ .../udt/nio/NioUdtMessageAcceptorChannel.java | 59 ++++ .../nio/NioUdtMessageConnectorChannel.java | 249 ++++++++++++++++ .../nio/NioUdtMessageRendezvousChannel.java | 40 +++ .../transport/udt/nio/NioUdtProvider.java | 247 ++++++++++++++++ .../netty/transport/udt/nio/package-info.java | 22 ++ .../netty/transport/udt/oio/package-info.java | 22 ++ .../io/netty/transport/udt/package-info.java | 22 ++ .../netty/transport/udt/bench/BenchXfer.java | 50 ++++ .../transport/udt/bench/package-info.java | 21 ++ .../transport/udt/bench/xfer/TcpNative.java | 66 +++++ .../transport/udt/bench/xfer/UdtNative.java | 270 ++++++++++++++++++ .../transport/udt/bench/xfer/UdtNetty.java | 137 +++++++++ .../udt/bench/xfer/package-info.java | 21 ++ .../io/netty/transport/udt/nio/TestAny.java | 42 +++ .../nio/TestNioUdtByteAcceptorChannel.java | 37 +++ .../nio/TestNioUdtByteConnectorChannel.java | 37 +++ .../nio/TestNioUdtByteRendezvousChannel.java | 103 +++++++ .../nio/TestNioUdtMessageAcceptorChannel.java | 37 +++ .../TestNioUdtMessageConnectorChannel.java | 37 +++ .../TestNioUdtMessageRendezvousChannel.java | 107 +++++++ .../transport/udt/nio/TestNioUdtProvider.java | 43 +++ .../io/netty/transport/udt/util/BootHelp.java | 73 +++++ .../transport/udt/util/CaliperBench.java | 112 ++++++++ .../transport/udt/util/CaliperMeasure.java | 224 +++++++++++++++ .../transport/udt/util/CaliperRunner.java | 245 ++++++++++++++++ .../transport/udt/util/CustomReporter.java | 250 ++++++++++++++++ .../transport/udt/util/EchoByteHandler.java | 110 +++++++ .../udt/util/EchoMessageHandler.java | 108 +++++++ .../transport/udt/util/TrafficControl.java | 80 ++++++ .../io/netty/transport/udt/util/UnitHelp.java | 262 +++++++++++++++++ .../transport/udt/util/UtilThreadFactory.java | 40 +++ .../transport/udt/util/package-info.java | 21 ++ .../src/test/resources/logback-test.xml | 16 ++ 67 files changed, 5691 insertions(+), 5 deletions(-) create mode 100644 example/.gitignore create mode 100644 example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClient.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServer.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/bytes/package-info.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClient.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServer.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/message/package-info.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/package-info.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/Config.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerBase.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerHandler.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerOne.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerTwo.java create mode 100644 example/src/main/java/io/netty/example/udt/echo/rendevous/package-info.java create mode 100644 example/src/main/java/io/netty/example/udt/package-info.java create mode 100644 example/src/main/java/io/netty/example/udt/util/UtilConsoleReporter.java create mode 100644 example/src/main/java/io/netty/example/udt/util/UtilThreadFactory.java create mode 100644 example/src/main/java/io/netty/example/udt/util/package-info.java create mode 100644 transport-udt/.gitignore create mode 100644 transport-udt/pom.xml create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/DefaultUdtChannelConfig.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/UdtChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/UdtChannelConfig.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/UdtMessage.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtAcceptorChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteAcceptorChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteConnectorChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteRendezvousChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageAcceptorChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageConnectorChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageRendezvousChannel.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtProvider.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/nio/package-info.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/oio/package-info.java create mode 100644 transport-udt/src/main/java/io/netty/transport/udt/package-info.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/BenchXfer.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/package-info.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/TcpNative.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNative.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNetty.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/package-info.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestAny.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteAcceptorChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteConnectorChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteRendezvousChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageAcceptorChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageConnectorChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageRendezvousChannel.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtProvider.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/BootHelp.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/CaliperBench.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/CaliperMeasure.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/CaliperRunner.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/CustomReporter.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/EchoByteHandler.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/EchoMessageHandler.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/TrafficControl.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/UnitHelp.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/UtilThreadFactory.java create mode 100644 transport-udt/src/test/java/io/netty/transport/udt/util/package-info.java create mode 100644 transport-udt/src/test/resources/logback-test.xml diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 000000000000..02e33e7a9d0c --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,7 @@ + +# +# native udt library extract location +# + +/lib + diff --git a/example/pom.xml b/example/pom.xml index 7755f2afdb77..24c22d7e502f 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -17,6 +17,7 @@ 4.0.0 + io.netty netty-parent @@ -54,7 +55,6 @@ netty-codec-socks ${project.version} - com.google.protobuf protobuf-java @@ -64,6 +64,17 @@ netty-metrics-yammer ${project.version} + + + com.yammer.metrics + metrics-core + 2.2.0 + + + ${project.groupId} + netty-transport-udt + ${project.version} + + - diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClient.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClient.java new file mode 100644 index 000000000000..2f6a27b13748 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClient.java @@ -0,0 +1,106 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.bytes; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.example.udt.util.UtilConsoleReporter; +import io.netty.example.udt.util.UtilThreadFactory; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.net.InetSocketAddress; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * UDT Byte Stream Client + *

+ * Sends one message when a connection is open and echoes back any received data + * to the server. Simply put, the echo client initiates the ping-pong traffic + * between the echo client and server by sending the first message to the + * server. + */ +public class ByteEchoClient { + + private static final Logger log = LoggerFactory + .getLogger(ByteEchoClient.class); + + private final String host; + private final int port; + private final int messageSize; + + public ByteEchoClient(final String host, final int port, + final int messageSize) { + this.host = host; + this.port = port; + this.messageSize = messageSize; + } + + public void run() throws Exception { + // Configure the client. + final Bootstrap boot = new Bootstrap(); + final ThreadFactory connectFactory = new UtilThreadFactory("connect"); + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.BYTE_PROVIDER); + try { + boot.group(connectGroup) + .channelFactory(NioUdtProvider.BYTE_CONNECTOR) + .localAddress("localhost", 0) + .remoteAddress(new InetSocketAddress(host, port)) + .handler(new ChannelInitializer() { + @Override + public void initChannel(final UdtChannel ch) + throws Exception { + ch.pipeline().addLast( + new LoggingHandler(LogLevel.INFO), + new ByteEchoClientHandler(messageSize)); + } + }); + // Start the client. + final ChannelFuture f = boot.connect().sync(); + // Wait until the connection is closed. + f.channel().closeFuture().sync(); + } finally { + // Shut down the event loop to terminate all threads. + boot.shutdown(); + } + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + // client is reporting metrics + UtilConsoleReporter.enable(3, TimeUnit.SECONDS); + + final String host = "localhost"; + final int port = 1234; + + final int messageSize = 64 * 1024; + + new ByteEchoClient(host, port, messageSize).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java new file mode 100644 index 000000000000..c157a7d7febc --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoClientHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.bytes; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelOption; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Meter; + +/** + * Handler implementation for the echo client. It initiates the ping-pong + * traffic between the echo client and server by sending the first message to + * the server on activation. + */ +public class ByteEchoClientHandler extends ChannelInboundByteHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(ByteEchoClientHandler.class.getName()); + + private final ByteBuf message; + + final Meter meter = Metrics.newMeter(ByteEchoClientHandler.class, "rate", + "bytes", TimeUnit.SECONDS); + + public ByteEchoClientHandler(final int messageSize) { + message = Unpooled.buffer(messageSize); + + for (int i = 0; i < message.capacity(); i++) { + message.writeByte((byte) i); + } + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + ctx.write(message); + } + + @Override + public void inboundBufferUpdated(final ChannelHandlerContext ctx, + final ByteBuf in) { + meter.mark(in.readableBytes()); + final ByteBuf out = ctx.nextOutboundByteBuffer(); + out.discardReadBytes(); + out.writeBytes(in); + ctx.flush(); + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable cause) { + log.error("close the connection when an exception is raised", cause); + ctx.close(); + } + + @Override + public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) + throws Exception { + return ctx.alloc().directBuffer( + ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServer.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServer.java new file mode 100644 index 000000000000..a20f045608f9 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.bytes; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.example.udt.util.UtilThreadFactory; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.util.concurrent.ThreadFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * UDT Byte Stream Server + *

+ * Echoes back any received data from a client. + */ +public class ByteEchoServer { + + private static final Logger log = LoggerFactory + .getLogger(ByteEchoServer.class); + + private final int port; + + public ByteEchoServer(final int port) { + this.port = port; + } + + public void run() throws Exception { + final ThreadFactory acceptFactory = new UtilThreadFactory("accept"); + final ThreadFactory connectFactory = new UtilThreadFactory("connect"); + final NioEventLoopGroup acceptGroup = new NioEventLoopGroup(1, + acceptFactory, NioUdtProvider.BYTE_PROVIDER); + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.BYTE_PROVIDER); + // Configure the server. + final ServerBootstrap boot = new ServerBootstrap(); + try { + boot.group(acceptGroup, connectGroup) + .channelFactory(NioUdtProvider.BYTE_ACCEPTOR) + .option(ChannelOption.SO_BACKLOG, 10) + .localAddress("localhost", port) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(final UdtChannel ch) + throws Exception { + ch.pipeline().addLast( + new LoggingHandler(LogLevel.INFO), + new ByteEchoServerHandler()); + } + }); + // Start the server. + final ChannelFuture future = boot.bind().sync(); + // Wait until the server socket is closed. + future.channel().closeFuture().sync(); + } finally { + // Shut down all event loops to terminate all threads. + boot.shutdown(); + } + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + final int port = 1234; + + new ByteEchoServer(port).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java new file mode 100644 index 000000000000..6a5bd0f7a1fe --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/ByteEchoServerHandler.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.bytes; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelOption; +import io.netty.transport.udt.nio.NioUdtProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler implementation for the echo server. + */ +@Sharable +public class ByteEchoServerHandler extends ChannelInboundByteHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(ByteEchoServerHandler.class.getName()); + + @Override + public void inboundBufferUpdated(final ChannelHandlerContext ctx, + final ByteBuf in) { + final ByteBuf out = ctx.nextOutboundByteBuffer(); + out.discardReadBytes(); + out.writeBytes(in); + ctx.flush(); + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable cause) { + log.error("close the connection when an exception is raised", cause); + ctx.close(); + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + } + + @Override + public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) + throws Exception { + return ctx.alloc().directBuffer( + ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/bytes/package-info.java b/example/src/main/java/io/netty/example/udt/echo/bytes/package-info.java new file mode 100644 index 000000000000..8d61902dab02 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/bytes/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Examples show how to use UDT Byte Streams. + */ +package io.netty.example.udt.echo.bytes; + diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClient.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClient.java new file mode 100644 index 000000000000..d7c80efb0772 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClient.java @@ -0,0 +1,106 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.message; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.example.udt.util.UtilConsoleReporter; +import io.netty.example.udt.util.UtilThreadFactory; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.net.InetSocketAddress; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * UDT Message Flow client + *

+ * Sends one message when a connection is open and echoes back any received data + * to the server. Simply put, the echo client initiates the ping-pong traffic + * between the echo client and server by sending the first message to the + * server. + */ +public class MsgEchoClient { + + private static final Logger log = LoggerFactory + .getLogger(MsgEchoClient.class); + + private final String host; + private final int port; + private final int messageSize; + + public MsgEchoClient(final String host, final int port, + final int messageSize) { + this.host = host; + this.port = port; + this.messageSize = messageSize; + } + + public void run() throws Exception { + // Configure the client. + final Bootstrap boot = new Bootstrap(); + final ThreadFactory connectFactory = new UtilThreadFactory("connect"); + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.MESSAGE_PROVIDER); + try { + boot.group(connectGroup) + .channelFactory(NioUdtProvider.MESSAGE_CONNECTOR) + .localAddress("localhost", 0) + .remoteAddress(new InetSocketAddress(host, port)) + .handler(new ChannelInitializer() { + @Override + public void initChannel(final UdtChannel ch) + throws Exception { + ch.pipeline().addLast( + new LoggingHandler(LogLevel.INFO), + new MsgEchoClientHandler(messageSize)); + } + }); + // Start the client. + final ChannelFuture f = boot.connect().sync(); + // Wait until the connection is closed. + f.channel().closeFuture().sync(); + } finally { + // Shut down the event loop to terminate all threads. + boot.shutdown(); + } + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + // client is reporting metrics + UtilConsoleReporter.enable(3, TimeUnit.SECONDS); + + final String host = "localhost"; + + final int port = 1234; + final int messageSize = 64 * 1024; + + new MsgEchoClient(host, port, messageSize).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java new file mode 100644 index 000000000000..4129cfc63d8f --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoClientHandler.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.message; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.MessageBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.transport.udt.UdtMessage; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Meter; + +/** + * Handler implementation for the echo client. It initiates the ping-pong + * traffic between the echo client and server by sending the first message to + * the server on activation. + */ +public class MsgEchoClientHandler extends + ChannelInboundMessageHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(MsgEchoClientHandler.class.getName()); + + private final UdtMessage message; + + public MsgEchoClientHandler(final int messageSize) { + final ByteBuf byteBuf = Unpooled.buffer(messageSize); + for (int i = 0; i < byteBuf.capacity(); i++) { + byteBuf.writeByte((byte) i); + } + message = new UdtMessage(byteBuf); + } + + final Meter meter = Metrics.newMeter(MsgEchoClientHandler.class, "rate", + "bytes", TimeUnit.SECONDS); + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + out.add(message); + ctx.flush(); + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable cause) { + log.error("close the connection when an exception is raised", cause); + ctx.close(); + } + + @Override + protected void messageReceived(final ChannelHandlerContext ctx, + final UdtMessage message) throws Exception { + final ByteBuf byteBuf = message.data(); + meter.mark(byteBuf.readableBytes()); + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + out.add(message); + ctx.flush(); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServer.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServer.java new file mode 100644 index 000000000000..38ae00c9ee8b --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.message; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.example.udt.util.UtilThreadFactory; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.util.concurrent.ThreadFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * UDT Message Flow Server + *

+ * Echoes back any received data from a client. + */ +public class MsgEchoServer { + + private static final Logger log = LoggerFactory + .getLogger(MsgEchoServer.class); + + private final int port; + + public MsgEchoServer(final int port) { + this.port = port; + } + + public void run() throws Exception { + final ThreadFactory acceptFactory = new UtilThreadFactory("accept"); + final ThreadFactory connectFactory = new UtilThreadFactory("connect"); + final NioEventLoopGroup acceptGroup = new NioEventLoopGroup(1, + acceptFactory, NioUdtProvider.MESSAGE_PROVIDER); + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.MESSAGE_PROVIDER); + // Configure the server. + final ServerBootstrap boot = new ServerBootstrap(); + try { + boot.group(acceptGroup, connectGroup) + .channelFactory(NioUdtProvider.MESSAGE_ACCEPTOR) + .option(ChannelOption.SO_BACKLOG, 10) + .localAddress("localhost", port) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(final UdtChannel ch) + throws Exception { + ch.pipeline().addLast( + new LoggingHandler(LogLevel.INFO), + new MsgEchoServerHandler()); + } + }); + // Start the server. + final ChannelFuture future = boot.bind().sync(); + // Wait until the server socket is closed. + future.channel().closeFuture().sync(); + } finally { + // Shut down all event loops to terminate all threads. + boot.shutdown(); + } + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + final int port = 1234; + + new MsgEchoServer(port).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java new file mode 100644 index 000000000000..8042ae72605f --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/message/MsgEchoServerHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.message; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.MessageBuf; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.transport.udt.UdtMessage; +import io.netty.transport.udt.nio.NioUdtProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler implementation for the echo server. + */ +@Sharable +public class MsgEchoServerHandler extends + ChannelInboundMessageHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(MsgEchoServerHandler.class.getName()); + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable cause) { + log.error("close the connection when an exception is raised", cause); + ctx.close(); + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + } + + @Override + protected void messageReceived(final ChannelHandlerContext ctx, + final UdtMessage message) throws Exception { + final ByteBuf byteBuf = message.data(); + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + out.add(message); + ctx.flush(); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/message/package-info.java b/example/src/main/java/io/netty/example/udt/echo/message/package-info.java new file mode 100644 index 000000000000..347ec265ae76 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/message/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Examples show how to use UDT Message Flows. + */ +package io.netty.example.udt.echo.message; + diff --git a/example/src/main/java/io/netty/example/udt/echo/package-info.java b/example/src/main/java/io/netty/example/udt/echo/package-info.java new file mode 100644 index 000000000000..7646e5975a7c --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Examples show how to use UDT with simple Echo Handlers. + */ +package io.netty.example.udt.echo; + diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/Config.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/Config.java new file mode 100644 index 000000000000..4e48674cab5e --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/Config.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.rendevous; + +/** + * Peer to Peer Config + */ +public final class Config { + + private Config() { + } + + public static final String hostOne = "localhost"; + public static final int portOne = 1231; + + public static final String hostTwo = "localhost"; + public static final int portTwo = 1232; + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerBase.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerBase.java new file mode 100644 index 000000000000..744a94db26d7 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerBase.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.rendevous; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.example.udt.util.UtilThreadFactory; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.net.InetSocketAddress; +import java.util.concurrent.ThreadFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * UDT Message Flow Peer + *

+ * Sends one message when a connection is open and echoes back any received data + * to the other peer. + */ +public abstract class MsgEchoPeerBase { + + protected static final Logger log = LoggerFactory + .getLogger(MsgEchoPeerBase.class); + + protected final int messageSize; + protected final InetSocketAddress self; + protected final InetSocketAddress peer; + + public MsgEchoPeerBase(final InetSocketAddress self, + final InetSocketAddress peer, final int messageSize) { + this.messageSize = messageSize; + this.self = self; + this.peer = peer; + } + + public void run() throws Exception { + // Configure the peer. + final Bootstrap boot = new Bootstrap(); + final ThreadFactory connectFactory = new UtilThreadFactory("rendezvous"); + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.MESSAGE_PROVIDER); + try { + boot.group(connectGroup) + .channelFactory(NioUdtProvider.MESSAGE_RENDEZVOUS) + .localAddress(self).remoteAddress(peer) + .handler(new ChannelInitializer() { + @Override + public void initChannel(final UdtChannel ch) + throws Exception { + ch.pipeline().addLast( + new LoggingHandler(LogLevel.INFO), + new MsgEchoPeerHandler(messageSize)); + } + }); + // Start the peer. + final ChannelFuture f = boot.connect().sync(); + // Wait until the connection is closed. + f.channel().closeFuture().sync(); + } finally { + // Shut down the event loop to terminate all threads. + boot.shutdown(); + } + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerHandler.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerHandler.java new file mode 100644 index 000000000000..3b830b6f7dd2 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerHandler.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.rendevous; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.MessageBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.transport.udt.UdtMessage; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Meter; + +/** + * Handler implementation for the echo peer. It initiates the ping-pong traffic + * between the echo peers by sending the first message to the other peer on + * activation. + */ +public class MsgEchoPeerHandler extends + ChannelInboundMessageHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(MsgEchoPeerHandler.class.getName()); + + private final UdtMessage message; + + public MsgEchoPeerHandler(final int messageSize) { + final ByteBuf byteBuf = Unpooled.buffer(messageSize); + for (int i = 0; i < byteBuf.capacity(); i++) { + byteBuf.writeByte((byte) i); + } + message = new UdtMessage(byteBuf); + } + + final Meter meter = Metrics.newMeter(MsgEchoPeerHandler.class, "rate", + "bytes", TimeUnit.SECONDS); + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + out.add(message); + ctx.flush(); + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable cause) { + log.error("close the connection when an exception is raised", cause); + ctx.close(); + } + + @Override + protected void messageReceived(final ChannelHandlerContext ctx, + final UdtMessage message) throws Exception { + final ByteBuf byteBuf = message.data(); + meter.mark(byteBuf.readableBytes()); + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + out.add(message); + ctx.flush(); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerOne.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerOne.java new file mode 100644 index 000000000000..b5b7889aa20e --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerOne.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.rendevous; + +import java.net.InetSocketAddress; + +/** + * UDT Message Flow Peer + *

+ * Sends one message when a connection is open and echoes back any received data + * to the other peer. + */ +public class MsgEchoPeerOne extends MsgEchoPeerBase { + + public MsgEchoPeerOne(final InetSocketAddress self, + final InetSocketAddress peer, final int messageSize) { + super(self, peer, messageSize); + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + // peer one is not reporting metrics + // ConsoleReporterUDT.enable(3, TimeUnit.SECONDS); + + final int messageSize = 64 * 1024; + + final InetSocketAddress self = new InetSocketAddress(Config.hostOne, + Config.portOne); + + final InetSocketAddress peer = new InetSocketAddress(Config.hostTwo, + Config.portTwo); + + new MsgEchoPeerOne(self, peer, messageSize).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerTwo.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerTwo.java new file mode 100644 index 000000000000..4dfdcdebfe2a --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/MsgEchoPeerTwo.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.echo.rendevous; + +import io.netty.example.udt.util.UtilConsoleReporter; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +/** + * UDT Message Flow Peer + *

+ * Sends one message when a connection is open and echoes back any received data + * to the other peer. + */ +public class MsgEchoPeerTwo extends MsgEchoPeerBase { + + public MsgEchoPeerTwo(final InetSocketAddress self, + final InetSocketAddress peer, final int messageSize) { + super(self, peer, messageSize); + } + + public static void main(final String[] args) throws Exception { + log.info("init"); + + // peer two is reporting metrics + UtilConsoleReporter.enable(3, TimeUnit.SECONDS); + + final int messageSize = 64 * 1024; + + final InetSocketAddress self = new InetSocketAddress(Config.hostTwo, + Config.portTwo); + + final InetSocketAddress peer = new InetSocketAddress(Config.hostOne, + Config.portOne); + + new MsgEchoPeerTwo(self, peer, messageSize).run(); + + log.info("done"); + } + +} diff --git a/example/src/main/java/io/netty/example/udt/echo/rendevous/package-info.java b/example/src/main/java/io/netty/example/udt/echo/rendevous/package-info.java new file mode 100644 index 000000000000..72fbb38e0745 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/echo/rendevous/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Examples show how to use UDT Message Rendezvous. + */ +package io.netty.example.udt.echo.rendevous; + diff --git a/example/src/main/java/io/netty/example/udt/package-info.java b/example/src/main/java/io/netty/example/udt/package-info.java new file mode 100644 index 000000000000..ef31fce91c5a --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Examples show how to use UDT. + */ +package io.netty.example.udt; + diff --git a/example/src/main/java/io/netty/example/udt/util/UtilConsoleReporter.java b/example/src/main/java/io/netty/example/udt/util/UtilConsoleReporter.java new file mode 100644 index 000000000000..6492041700a2 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/util/UtilConsoleReporter.java @@ -0,0 +1,250 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.util; + +import java.io.PrintStream; +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Clock; +import com.yammer.metrics.core.Counter; +import com.yammer.metrics.core.Gauge; +import com.yammer.metrics.core.Histogram; +import com.yammer.metrics.core.Metered; +import com.yammer.metrics.core.Metric; +import com.yammer.metrics.core.MetricName; +import com.yammer.metrics.core.MetricPredicate; +import com.yammer.metrics.core.MetricProcessor; +import com.yammer.metrics.core.MetricsRegistry; +import com.yammer.metrics.core.Timer; +import com.yammer.metrics.reporting.AbstractPollingReporter; +import com.yammer.metrics.stats.Snapshot; + +/** + * A simple reporters which prints out application metrics to a + * {@link PrintStream} periodically. + */ +public class UtilConsoleReporter extends AbstractPollingReporter implements + MetricProcessor { + private static final int CONSOLE_WIDTH = 80; + + /** + * Enables the console reporter for the default metrics registry, and causes + * it to print to STDOUT with the specified period. + */ + public static void enable(final long period, final TimeUnit unit) { + enable(Metrics.defaultRegistry(), period, unit); + } + + /** + * Enables the console reporter for the given metrics registry, and causes + * it to print to STDOUT with the specified period and unrestricted output. + */ + public static void enable(final MetricsRegistry metricsRegistry, + final long period, final TimeUnit unit) { + final UtilConsoleReporter reporter = new UtilConsoleReporter( + metricsRegistry, System.out, MetricPredicate.ALL); + reporter.start(period, unit); + } + + private final PrintStream out; + private final MetricPredicate predicate; + private final Clock clock; + private final TimeZone timeZone; + private final Locale locale; + + /** + * Creates a new {@link UtilConsoleReporter} for the default metrics + * registry, with unrestricted output. + */ + public UtilConsoleReporter(final PrintStream out) { + this(Metrics.defaultRegistry(), out, MetricPredicate.ALL); + } + + /** + * Creates a new {@link UtilConsoleReporter} for a given metrics registry. + */ + public UtilConsoleReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate) { + this(metricsRegistry, out, predicate, Clock.defaultClock(), TimeZone + .getDefault()); + } + + /** + * Creates a new {@link UtilConsoleReporter} for a given metrics registry. + */ + public UtilConsoleReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate, + final Clock clock, final TimeZone timeZone) { + this(metricsRegistry, out, predicate, clock, timeZone, Locale + .getDefault()); + } + + /** + * Creates a new {@link UtilConsoleReporter} for a given metrics registry. + */ + public UtilConsoleReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate, + final Clock clock, final TimeZone timeZone, final Locale locale) { + super(metricsRegistry, "console-reporter"); + this.out = out; + this.predicate = predicate; + this.clock = clock; + this.timeZone = timeZone; + this.locale = locale; + } + + @Override + public void run() { + try { + final DateFormat format = DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.MEDIUM, locale); + format.setTimeZone(timeZone); + final String dateTime = format.format(new Date(clock.time())); + out.print(dateTime); + out.print(' '); + for (int i = 0; i < (CONSOLE_WIDTH - dateTime.length() - 1); i++) { + out.print('='); + } + out.println(); + for (final Entry> entry : getMetricsRegistry() + .groupedMetrics(predicate).entrySet()) { + out.print(entry.getKey()); + out.println(':'); + for (final Entry subEntry : entry + .getValue().entrySet()) { + out.print(" "); + out.print(subEntry.getKey().getName()); + out.println(':'); + subEntry.getValue().processWith(this, subEntry.getKey(), + out); + out.println(); + } + out.println(); + } + out.println(); + out.flush(); + } catch (final Exception e) { + e.printStackTrace(out); + } + } + + @Override + public void processGauge(final MetricName name, final Gauge gauge, + final PrintStream stream) { + stream.printf(locale, " value = %s\n", gauge.value()); + } + + @Override + public void processCounter(final MetricName name, final Counter counter, + final PrintStream stream) { + stream.printf(locale, " count = %,d\n", counter.count()); + } + + @Override + public void processMeter(final MetricName name, final Metered meter, + final PrintStream stream) { + final String unit = abbrev(meter.rateUnit()); + stream.printf(locale, " count = %,d\n", meter.count()); + stream.printf(locale, " mean rate = %,2.2f %s/%s\n", + meter.meanRate(), meter.eventType(), unit); + stream.printf(locale, " 1-minute rate = %,2.2f %s/%s\n", + meter.oneMinuteRate(), meter.eventType(), unit); + stream.printf(locale, " 5-minute rate = %,2.2f %s/%s\n", + meter.fiveMinuteRate(), meter.eventType(), unit); + stream.printf(locale, " 15-minute rate = %,2.2f %s/%s\n", + meter.fifteenMinuteRate(), meter.eventType(), unit); + } + + @Override + public void processHistogram(final MetricName name, + final Histogram histogram, final PrintStream stream) { + final Snapshot snapshot = histogram.getSnapshot(); + stream.printf(locale, " min = %,2.2f\n", histogram.min()); + stream.printf(locale, " max = %,2.2f\n", histogram.max()); + stream.printf(locale, " mean = %,2.2f\n", histogram.mean()); + stream.printf(locale, " stddev = %,2.2f\n", + histogram.stdDev()); + stream.printf(locale, " median = %,2.2f\n", + snapshot.getMedian()); + stream.printf(locale, " 75%% <= %,2.2f\n", + snapshot.get75thPercentile()); + stream.printf(locale, " 95%% <= %,2.2f\n", + snapshot.get95thPercentile()); + stream.printf(locale, " 98%% <= %,2.2f\n", + snapshot.get98thPercentile()); + stream.printf(locale, " 99%% <= %,2.2f\n", + snapshot.get99thPercentile()); + stream.printf(locale, " 99.9%% <= %,2.2f\n", + snapshot.get999thPercentile()); + } + + @Override + public void processTimer(final MetricName name, final Timer timer, + final PrintStream stream) { + processMeter(name, timer, stream); + final String durationUnit = abbrev(timer.durationUnit()); + final Snapshot snapshot = timer.getSnapshot(); + stream.printf(locale, " min = %,2.2f %s\n", timer.min(), + durationUnit); + stream.printf(locale, " max = %,2.2f %s\n", timer.max(), + durationUnit); + stream.printf(locale, " mean = %,2.2f %s\n", timer.mean(), + durationUnit); + stream.printf(locale, " stddev = %,2.2f %s\n", + timer.stdDev(), durationUnit); + stream.printf(locale, " median = %,2.2f %s\n", + snapshot.getMedian(), durationUnit); + stream.printf(locale, " 75%% <= %,2.2f %s\n", + snapshot.get75thPercentile(), durationUnit); + stream.printf(locale, " 95%% <= %,2.2f %s\n", + snapshot.get95thPercentile(), durationUnit); + stream.printf(locale, " 98%% <= %,2.2f %s\n", + snapshot.get98thPercentile(), durationUnit); + stream.printf(locale, " 99%% <= %,2.2f %s\n", + snapshot.get99thPercentile(), durationUnit); + stream.printf(locale, " 99.9%% <= %,2.2f %s\n", + snapshot.get999thPercentile(), durationUnit); + } + + private String abbrev(final TimeUnit unit) { + switch (unit) { + case NANOSECONDS: + return "ns"; + case MICROSECONDS: + return "us"; + case MILLISECONDS: + return "ms"; + case SECONDS: + return "s"; + case MINUTES: + return "m"; + case HOURS: + return "h"; + case DAYS: + return "d"; + default: + throw new IllegalArgumentException("Unrecognized TimeUnit: " + unit); + } + } +} diff --git a/example/src/main/java/io/netty/example/udt/util/UtilThreadFactory.java b/example/src/main/java/io/netty/example/udt/util/UtilThreadFactory.java new file mode 100644 index 000000000000..c5ea0e162cdf --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/util/UtilThreadFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.example.udt.util; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Custom thread factory to use with examples. + */ +public class UtilThreadFactory implements ThreadFactory { + + private static final AtomicInteger counter = new AtomicInteger(); + + private final String name; + + public UtilThreadFactory(final String name) { + this.name = name; + } + + @Override + public Thread newThread(final Runnable runnable) { + return new Thread(runnable, name + "-" + counter.getAndIncrement()); + }; + +} diff --git a/example/src/main/java/io/netty/example/udt/util/package-info.java b/example/src/main/java/io/netty/example/udt/util/package-info.java new file mode 100644 index 000000000000..d07010325b72 --- /dev/null +++ b/example/src/main/java/io/netty/example/udt/util/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * Utilities for UDT examples. + */ +package io.netty.example.udt.util; + diff --git a/pom.xml b/pom.xml index 9bad5c41cc5c..ea635cef2187 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,7 @@ codec-socks transport transport-sctp + transport-udt handler metrics-yammer example @@ -220,9 +221,9 @@ test - org.slf4j - slf4j-simple - 1.6.6 + ch.qos.logback + logback-classic + 1.0.9 test diff --git a/transport-udt/.gitignore b/transport-udt/.gitignore new file mode 100644 index 000000000000..02e33e7a9d0c --- /dev/null +++ b/transport-udt/.gitignore @@ -0,0 +1,7 @@ + +# +# native udt library extract location +# + +/lib + diff --git a/transport-udt/pom.xml b/transport-udt/pom.xml new file mode 100644 index 000000000000..3403fc106d40 --- /dev/null +++ b/transport-udt/pom.xml @@ -0,0 +1,101 @@ + + + + + 4.0.0 + + + io.netty + netty-parent + 4.0.0.Beta1-SNAPSHOT + + + netty-transport-udt + jar + + Netty/Transport/UDT + + + + + + + ${project.groupId} + netty-buffer + ${project.version} + + + + ${project.groupId} + netty-transport + ${project.version} + + + + com.barchart.udt + barchart-udt-bundle + 2.2.0 + + + + + + + com.yammer.metrics + metrics-core + 2.2.0 + test + + + + org.slf4j + slf4j-api + 1.7.2 + compile + + + ch.qos.logback + logback-classic + 1.0.9 + test + + + + com.google.caliper + caliper + 0.5-rc1 + test + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + always + + + + + + + diff --git a/transport-udt/src/main/java/io/netty/transport/udt/DefaultUdtChannelConfig.java b/transport-udt/src/main/java/io/netty/transport/udt/DefaultUdtChannelConfig.java new file mode 100644 index 000000000000..13d8bdf37bb5 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/DefaultUdtChannelConfig.java @@ -0,0 +1,250 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt; + +import static io.netty.channel.ChannelOption.*; +import io.netty.channel.ChannelOption; +import io.netty.channel.DefaultChannelConfig; + +import java.io.IOException; +import java.util.Map; + +import com.barchart.udt.OptionUDT; +import com.barchart.udt.SocketUDT; +import com.barchart.udt.nio.ChannelUDT; + +/** + * The default {@link UdtChannelConfig} implementation. + */ +public class DefaultUdtChannelConfig extends DefaultChannelConfig implements + UdtChannelConfig { + + private static final int K = 1024; + private static final int M = K * K; + + private volatile int protocolReceiveBuferSize = 10 * M; + private volatile int protocolSendBuferSize = 10 * M; + + private volatile int systemReceiveBufferSize = 1 * M; + private volatile int systemSendBuferSize = 1 * M; + + private volatile int allocatorReceiveBufferSize = 128 * K; + private volatile int allocatorSendBufferSize = 128 * K; + + private volatile int backlog = 64; + private volatile int soLinger; + + private volatile boolean reuseAddress = true; + + public DefaultUdtChannelConfig(final UdtChannel channel, + final ChannelUDT channelUDT, final boolean apply) + throws IOException { + super(channel); + if (apply) { + apply(channelUDT); + } + } + + protected void apply(final ChannelUDT channelUDT) throws IOException { + final SocketUDT socketUDT = channelUDT.socketUDT(); + socketUDT.setReuseAddress(isReuseAddress()); + socketUDT.setSendBufferSize(getSendBufferSize()); + if (getSoLinger() <= 0) { + socketUDT.setSoLinger(false, 0); + } else { + socketUDT.setSoLinger(true, getSoLinger()); + } + socketUDT.setOption(OptionUDT.Protocol_Receive_Buffer_Size, + getProtocolReceiveBufferSize()); + socketUDT.setOption(OptionUDT.Protocol_Send_Buffer_Size, + getProtocolSendBufferSize()); + socketUDT.setOption(OptionUDT.System_Receive_Buffer_Size, + getSystemReceiveBufferSize()); + socketUDT.setOption(OptionUDT.System_Send_Buffer_Size, + getSystemSendBufferSize()); + } + + @Override + public int getProtocolReceiveBufferSize() { + return protocolReceiveBuferSize; + } + + @Override + public int getBacklog() { + return backlog; + } + + @SuppressWarnings("unchecked") + @Override + public T getOption(final ChannelOption option) { + if (option == PROTOCOL_RECEIVE_BUFFER_SIZE) { + return (T) Integer.valueOf(getProtocolReceiveBufferSize()); + } + if (option == PROTOCOL_SEND_BUFFER_SIZE) { + return (T) Integer.valueOf(getProtocolSendBufferSize()); + } + if (option == SYSTEM_RECEIVE_BUFFER_SIZE) { + return (T) Integer.valueOf(getSystemReceiveBufferSize()); + } + if (option == SYSTEM_SEND_BUFFER_SIZE) { + return (T) Integer.valueOf(getSystemSendBufferSize()); + } + if (option == SO_RCVBUF) { + return (T) Integer.valueOf(getReceiveBufferSize()); + } + if (option == SO_SNDBUF) { + return (T) Integer.valueOf(getSendBufferSize()); + } + if (option == SO_REUSEADDR) { + return (T) Boolean.valueOf(isReuseAddress()); + } + if (option == SO_LINGER) { + return (T) Integer.valueOf(getSoLinger()); + } + if (option == SO_BACKLOG) { + return (T) Integer.valueOf(getBacklog()); + } + return super.getOption(option); + } + + @Override + public Map, Object> getOptions() { + return getOptions(super.getOptions(), PROTOCOL_RECEIVE_BUFFER_SIZE, + PROTOCOL_SEND_BUFFER_SIZE, SYSTEM_RECEIVE_BUFFER_SIZE, + SYSTEM_SEND_BUFFER_SIZE, SO_RCVBUF, SO_SNDBUF, SO_REUSEADDR, + SO_LINGER, SO_BACKLOG); + } + + @Override + public int getReceiveBufferSize() { + return allocatorReceiveBufferSize; + } + + @Override + public int getSendBufferSize() { + return allocatorSendBufferSize; + } + + @Override + public int getSoLinger() { + return soLinger; + } + + @Override + public boolean isReuseAddress() { + return reuseAddress; + } + + @Override + public UdtChannelConfig setProtocolReceiveBufferSize(final int allocator) { + this.protocolReceiveBuferSize = allocator; + return this; + } + + @Override + public UdtChannelConfig setBacklog(final int backlog) { + this.backlog = backlog; + return this; + } + + @Override + public boolean setOption(final ChannelOption option, final T value) { + validate(option, value); + if (option == PROTOCOL_RECEIVE_BUFFER_SIZE) { + setProtocolReceiveBufferSize((Integer) value); + } else if (option == PROTOCOL_SEND_BUFFER_SIZE) { + setProtocolSendBufferSize((Integer) value); + } else if (option == SYSTEM_RECEIVE_BUFFER_SIZE) { + setSystemReceiveBufferSize((Integer) value); + } else if (option == SYSTEM_SEND_BUFFER_SIZE) { + setSystemSendBufferSize((Integer) value); + } else if (option == SO_RCVBUF) { + setReceiveBufferSize((Integer) value); + } else if (option == SO_SNDBUF) { + setSendBufferSize((Integer) value); + } else if (option == SO_REUSEADDR) { + setReuseAddress((Boolean) value); + } else if (option == SO_LINGER) { + setSoLinger((Integer) value); + } else if (option == SO_BACKLOG) { + setBacklog((Integer) value); + } else { + return super.setOption(option, value); + } + return true; + } + + @Override + public UdtChannelConfig setReceiveBufferSize(final int receiveBufferSize) { + allocatorReceiveBufferSize = receiveBufferSize; + return this; + } + + @Override + public UdtChannelConfig setReuseAddress(final boolean reuseAddress) { + this.reuseAddress = reuseAddress; + return this; + } + + @Override + public UdtChannelConfig setSendBufferSize(final int sendBufferSize) { + allocatorSendBufferSize = sendBufferSize; + return this; + } + + @Override + public UdtChannelConfig setSoLinger(final int soLinger) { + this.soLinger = soLinger; + return this; + } + + @Override + public int getSystemReceiveBufferSize() { + return systemReceiveBufferSize; + } + + @Override + public UdtChannelConfig setSystemSendBufferSize( + final int systemReceiveBufferSize) { + this.systemReceiveBufferSize = systemReceiveBufferSize; + return this; + } + + @Override + public int getProtocolSendBufferSize() { + return protocolSendBuferSize; + } + + @Override + public UdtChannelConfig setProtocolSendBufferSize( + final int protocolSendBuferSize) { + this.protocolSendBuferSize = protocolSendBuferSize; + return this; + } + + @Override + public UdtChannelConfig setSystemReceiveBufferSize( + final int systemSendBuferSize) { + this.systemSendBuferSize = systemSendBuferSize; + return this; + } + + @Override + public int getSystemSendBufferSize() { + return systemSendBuferSize; + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/UdtChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/UdtChannel.java new file mode 100644 index 000000000000..fffb768fd083 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/UdtChannel.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt; + +import io.netty.channel.Channel; +import io.netty.transport.udt.nio.NioUdtProvider; + +/** + * UDT {@link Channel}. + *

+ * Supported UDT {@link UdtChannel} are available via {@link NioUdtProvider}. + */ +public interface UdtChannel extends Channel { + + /** + * Returns the {@link UdtChannelConfig} of the channel. + */ + @Override + UdtChannelConfig config(); + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/UdtChannelConfig.java b/transport-udt/src/main/java/io/netty/transport/udt/UdtChannelConfig.java new file mode 100644 index 000000000000..da26389cda2f --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/UdtChannelConfig.java @@ -0,0 +1,185 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt; + +import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelOption; + +import com.barchart.udt.OptionUDT; +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.KindUDT; + +/** + * A {@link ChannelConfig} for a {@link UdtChannel}. + *

+ *

Available options

+ * In addition to the options provided by {@link ChannelConfig}, + * {@link UdtChannelConfig} allows the following options in the option map: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
NameAssociated setter method
{@code "reuseAddress"}{@link #setReuseAddress(boolean)}
{@code "soLinger"}{@link #setSoLinger(int)}
{@code "receiveBufferSize"}{@link #setReceiveBufferSize(int)}
{@code "sendBufferSize"}{@link #setSendBufferSize(int)}
{@code "protocolReceiveBuferSize"}{@link #setProtocolBufferSize(int)}
{@code "systemReceiveBufferSize"}{@link #setSystemBufferSize(int)}
+ *

+ * Note that {@link TypeUDT#DATAGRAM} message oriented channels treat + * {@code "receiveBufferSize"} and {@code "sendBufferSize"} as maximum message + * size. If received or sent message does not fit specified sizes, + * {@link ChannelException} will be thrown. + */ +public interface UdtChannelConfig extends ChannelConfig { + + /** + * See {@link OptionUDT#Protocol_Receive_Buffer_Size}. + */ + ChannelOption PROTOCOL_RECEIVE_BUFFER_SIZE = new ChannelOption( + "PROTOCOL_RECEIVE_BUFFER_SIZE"); + + /** + * See {@link OptionUDT#Protocol_Send_Buffer_Size}. + */ + ChannelOption PROTOCOL_SEND_BUFFER_SIZE = new ChannelOption( + "PROTOCOL_SEND_BUFFER_SIZE"); + + /** + * See {@link OptionUDT#System_Receive_Buffer_Size}. + */ + ChannelOption SYSTEM_RECEIVE_BUFFER_SIZE = new ChannelOption( + "SYSTEM_RECEIVE_BUFFER_SIZE"); + + /** + * See {@link OptionUDT#System_Send_Buffer_Size}. + */ + ChannelOption SYSTEM_SEND_BUFFER_SIZE = new ChannelOption( + "SYSTEM_SEND_BUFFER_SIZE"); + + /** + * Gets {@link KindUDT#ACCEPTOR} channel backlog. + */ + int getBacklog(); + + /** + * Gets {@link OptionUDT#Protocol_Receive_Buffer_Size} + */ + int getProtocolReceiveBufferSize(); + + /** + * Gets {@link OptionUDT#Protocol_Send_Buffer_Size} + */ + int getProtocolSendBufferSize(); + + /** + * Gets the {@link ChannelOption#SO_RCVBUF} option. + */ + int getReceiveBufferSize(); + + /** + * Gets the {@link ChannelOption#SO_SNDBUF} option. + */ + int getSendBufferSize(); + + /** + * Gets the {@link ChannelOption#SO_LINGER} option. + */ + int getSoLinger(); + + /** + * Gets {@link OptionUDT#System_Receive_Buffer_Size} + */ + int getSystemReceiveBufferSize(); + + /** + * Gets {@link OptionUDT#System_Send_Buffer_Size} + */ + int getSystemSendBufferSize(); + + /** + * Gets the {@link ChannelOption#SO_REUSEADDR} option. + */ + boolean isReuseAddress(); + + /** + * Sets {@link KindUDT#ACCEPTOR} channel backlog. + */ + UdtChannelConfig setBacklog(int backlog); + + /** + * Sets {@link OptionUDT#Protocol_Receive_Buffer_Size} + */ + UdtChannelConfig setProtocolReceiveBufferSize(int size); + + /** + * Sets {@link OptionUDT#Protocol_Send_Buffer_Size} + */ + UdtChannelConfig setProtocolSendBufferSize(int size); + + /** + * Sets the {@link ChannelOption#SO_RCVBUF} option. + */ + UdtChannelConfig setReceiveBufferSize(int receiveBufferSize); + + /** + * Sets the {@link ChannelOption#SO_REUSEADDR} option. + */ + UdtChannelConfig setReuseAddress(boolean reuseAddress); + + /** + * Sets the {@link ChannelOption#SO_SNDBUF} option. + */ + UdtChannelConfig setSendBufferSize(int sendBufferSize); + + /** + * Sets the {@link ChannelOption#SO_LINGER} option. + */ + UdtChannelConfig setSoLinger(int soLinger); + + /** + * Sets {@link OptionUDT#System_Receive_Buffer_Size} + */ + UdtChannelConfig setSystemReceiveBufferSize(int size); + + /** + * Sets {@link OptionUDT#System_Send_Buffer_Size} + */ + UdtChannelConfig setSystemSendBufferSize(int size); + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/UdtMessage.java b/transport-udt/src/main/java/io/netty/transport/udt/UdtMessage.java new file mode 100644 index 000000000000..ac16733e9f95 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/UdtMessage.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.DefaultByteBufHolder; +import io.netty.transport.udt.nio.NioUdtProvider; + +import com.barchart.udt.TypeUDT; + +/** + * The message container that is used for {@link TypeUDT#DATAGRAM} messages. + * @see {@link NioUdtProvider#MESSAGE_CONNECTOR} + * @see {@link NioUdtProvider#MESSAGE_RENDEZVOUS} + */ +public final class UdtMessage extends DefaultByteBufHolder { + + public UdtMessage(final ByteBuf data) { + super(data); + } + + @Override + public UdtMessage copy() { + return new UdtMessage(data().copy()); + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtAcceptorChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtAcceptorChannel.java new file mode 100644 index 000000000000..1f44a452649b --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtAcceptorChannel.java @@ -0,0 +1,128 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static java.nio.channels.SelectionKey.*; +import io.netty.buffer.MessageBuf; +import io.netty.channel.ChannelException; +import io.netty.channel.socket.nio.AbstractNioMessageChannel; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.DefaultUdtChannelConfig; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.UdtChannelConfig; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.ServerSocketChannelUDT; + +/** + * Common base for Netty Byte/Message UDT Stream/Datagram acceptors. + */ +public abstract class NioUdtAcceptorChannel extends AbstractNioMessageChannel + implements UdtChannel { + + protected static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtAcceptorChannel.class); + + private final UdtChannelConfig config; + + protected NioUdtAcceptorChannel(final ServerSocketChannelUDT channelUDT) { + super(null, channelUDT.socketUDT().id(), channelUDT, OP_ACCEPT); + try { + channelUDT.configureBlocking(false); + config = new DefaultUdtChannelConfig(this, channelUDT, true); + } catch (final Exception e) { + try { + channelUDT.close(); + } catch (final Exception e2) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to close channel.", e2); + } + } + throw new ChannelException("Failed configure channel.", e); + } + } + + protected NioUdtAcceptorChannel(final TypeUDT type) { + this(NioUdtProvider.newAcceptorChannelUDT(type)); + } + + @Override + public UdtChannelConfig config() { + return config; + } + + @Override + protected void doBind(final SocketAddress localAddress) throws Exception { + javaChannel().socket().bind(localAddress, config.getBacklog()); + } + + @Override + protected void doClose() throws Exception { + javaChannel().close(); + } + + @Override + protected boolean doConnect(final SocketAddress remoteAddress, + final SocketAddress localAddress) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + protected void doDisconnect() throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + protected void doFinishConnect() throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + protected int doWriteMessages(final MessageBuf buf, + final boolean lastSpin) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isActive() { + return javaChannel().socket().isBound(); + } + + @Override + protected ServerSocketChannelUDT javaChannel() { + return (ServerSocketChannelUDT) super.javaChannel(); + } + + @Override + protected SocketAddress localAddress0() { + return javaChannel().socket().getLocalSocketAddress(); + } + + @Override + public InetSocketAddress remoteAddress() { + return null; + } + + @Override + protected SocketAddress remoteAddress0() { + return null; + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteAcceptorChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteAcceptorChannel.java new file mode 100644 index 000000000000..7e5d5e989281 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteAcceptorChannel.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.buffer.BufType; +import io.netty.buffer.MessageBuf; +import io.netty.channel.ChannelMetadata; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.SocketChannelUDT; + +/** + * Byte Channel Acceptor for UDT Streams. + */ +public class NioUdtByteAcceptorChannel extends NioUdtAcceptorChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtByteAcceptorChannel.class); + + private static final ChannelMetadata METADATA = new ChannelMetadata( + BufType.BYTE, false); + + public NioUdtByteAcceptorChannel() { + super(TypeUDT.STREAM); + } + + @Override + protected int doReadMessages(final MessageBuf buf) throws Exception { + final SocketChannelUDT channelUDT = javaChannel().accept(); + if (channelUDT == null) { + return 0; + } else { + buf.add(new NioUdtByteConnectorChannel(this, channelUDT.socketUDT() + .id(), channelUDT)); + return 1; + } + } + + @Override + public ChannelMetadata metadata() { + return METADATA; + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteConnectorChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteConnectorChannel.java new file mode 100644 index 000000000000..437e3907e5d4 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteConnectorChannel.java @@ -0,0 +1,194 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static java.nio.channels.SelectionKey.*; +import io.netty.buffer.BufType; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelMetadata; +import io.netty.channel.socket.nio.AbstractNioByteChannel; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.DefaultUdtChannelConfig; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.UdtChannelConfig; + +import java.net.SocketAddress; +import java.nio.channels.SelectionKey; + +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.SocketChannelUDT; + +/** + * Byte Channel Connector for UDT Streams. + */ +public class NioUdtByteConnectorChannel extends AbstractNioByteChannel + implements UdtChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtByteConnectorChannel.class); + + private static final ChannelMetadata METADATA = new ChannelMetadata( + BufType.BYTE, false); + + private final UdtChannelConfig config; + + public NioUdtByteConnectorChannel() { + this(TypeUDT.STREAM); + } + + public NioUdtByteConnectorChannel(final Channel parent, final Integer id, + final SocketChannelUDT channelUDT) { + super(parent, id, channelUDT); + try { + channelUDT.configureBlocking(false); + switch (channelUDT.socketUDT().status()) { + case INIT: + case OPENED: + config = new DefaultUdtChannelConfig(this, channelUDT, true); + break; + default: + config = new DefaultUdtChannelConfig(this, channelUDT, false); + break; + } + } catch (final Exception e) { + try { + channelUDT.close(); + } catch (final Exception e2) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to close channel.", e2); + } + } + throw new ChannelException("Failed to configure channel.", e); + } + } + + public NioUdtByteConnectorChannel(final SocketChannelUDT channelUDT) { + this(null, channelUDT.socketUDT().id(), channelUDT); + } + + public NioUdtByteConnectorChannel(final TypeUDT type) { + this(NioUdtProvider.newConnectorChannelUDT(type)); + } + + @Override + public UdtChannelConfig config() { + return config; + } + + @Override + protected void doBind(final SocketAddress localAddress) throws Exception { + javaChannel().bind(localAddress); + } + + @Override + protected void doClose() throws Exception { + javaChannel().close(); + } + + @Override + protected boolean doConnect(final SocketAddress remoteAddress, + final SocketAddress localAddress) throws Exception { + doBind(localAddress); + boolean success = false; + try { + final boolean connected = javaChannel().connect(remoteAddress); + if (!connected) { + selectionKey().interestOps( + selectionKey().interestOps() | OP_CONNECT); + } + success = true; + return connected; + } finally { + if (!success) { + doClose(); + } + } + } + + @Override + protected void doDisconnect() throws Exception { + doClose(); + } + + @Override + protected void doFinishConnect() throws Exception { + if (javaChannel().finishConnect()) { + selectionKey().interestOps( + selectionKey().interestOps() & ~OP_CONNECT); + } else { + throw new Error( + "Provider error: failed to finish connect. Provider library should be upgraded."); + } + } + + @Override + protected int doReadBytes(final ByteBuf byteBuf) throws Exception { + return byteBuf.writeBytes(javaChannel(), byteBuf.writableBytes()); + } + + @Override + protected int doWriteBytes(final ByteBuf byteBuf, final boolean lastSpin) + throws Exception { + final int pendingBytes = byteBuf.readableBytes(); + final int writtenBytes = byteBuf.readBytes(javaChannel(), pendingBytes); + final SelectionKey key = selectionKey(); + final int interestOps = key.interestOps(); + if (writtenBytes >= pendingBytes) { + // wrote the buffer completely - clear OP_WRITE. + if ((interestOps & OP_WRITE) != 0) { + key.interestOps(interestOps & ~OP_WRITE); + } + } else { + // wrote partial or nothing - ensure OP_WRITE + if (writtenBytes > 0 || lastSpin) { + if ((interestOps & OP_WRITE) == 0) { + key.interestOps(interestOps | OP_WRITE); + } + } + } + return writtenBytes; + } + + @Override + public boolean isActive() { + final SocketChannelUDT channelUDT = javaChannel(); + return channelUDT.isOpen() && channelUDT.isConnectFinished(); + } + + @Override + protected SocketChannelUDT javaChannel() { + return (SocketChannelUDT) super.javaChannel(); + } + + @Override + protected SocketAddress localAddress0() { + return javaChannel().socket().getLocalSocketAddress(); + } + + @Override + public ChannelMetadata metadata() { + return METADATA; + } + + @Override + protected SocketAddress remoteAddress0() { + return javaChannel().socket().getRemoteSocketAddress(); + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteRendezvousChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteRendezvousChannel.java new file mode 100644 index 000000000000..87f80f28c497 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtByteRendezvousChannel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.UdtChannel; + +import com.barchart.udt.TypeUDT; + +/** + * Byte Channel Rendezvous for UDT Streams. + */ +public class NioUdtByteRendezvousChannel extends NioUdtByteConnectorChannel + implements UdtChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtByteRendezvousChannel.class); + + public NioUdtByteRendezvousChannel() { + super(NioUdtProvider.newRendezvousChannelUDT(TypeUDT.STREAM)); + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageAcceptorChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageAcceptorChannel.java new file mode 100644 index 000000000000..a8f83eaac8f4 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageAcceptorChannel.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.buffer.BufType; +import io.netty.buffer.MessageBuf; +import io.netty.channel.ChannelMetadata; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; + +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.SocketChannelUDT; + +/** + * Message Channel Acceptor for UDT Datagrams. + */ +public class NioUdtMessageAcceptorChannel extends NioUdtAcceptorChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtMessageAcceptorChannel.class); + + private static final ChannelMetadata METADATA = new ChannelMetadata( + BufType.MESSAGE, false); + + public NioUdtMessageAcceptorChannel() { + super(TypeUDT.DATAGRAM); + } + + @Override + protected int doReadMessages(final MessageBuf buf) throws Exception { + final SocketChannelUDT channelUDT = javaChannel().accept(); + if (channelUDT == null) { + return 0; + } else { + buf.add(new NioUdtMessageConnectorChannel(this, channelUDT + .socketUDT().id(), channelUDT)); + return 1; + } + } + + @Override + public ChannelMetadata metadata() { + return METADATA; + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageConnectorChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageConnectorChannel.java new file mode 100644 index 000000000000..bbac0b9577e6 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageConnectorChannel.java @@ -0,0 +1,249 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static java.nio.channels.SelectionKey.*; +import io.netty.buffer.BufType; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.MessageBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelMetadata; +import io.netty.channel.socket.nio.AbstractNioMessageChannel; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.DefaultUdtChannelConfig; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.UdtChannelConfig; +import io.netty.transport.udt.UdtMessage; + +import java.net.SocketAddress; +import java.nio.channels.SelectionKey; + +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.SocketChannelUDT; + +/** + * Message Connector for UDT Datagrams. + *

+ * Note: send/receive must use {@link UdtMessage} in the pipeline + */ +public class NioUdtMessageConnectorChannel extends AbstractNioMessageChannel + implements UdtChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtMessageConnectorChannel.class); + + private static final ChannelMetadata METADATA = new ChannelMetadata( + BufType.MESSAGE, false); + + private final UdtChannelConfig config; + + public NioUdtMessageConnectorChannel() { + this(TypeUDT.DATAGRAM); + } + + public NioUdtMessageConnectorChannel(final Channel parent, + final Integer id, final SocketChannelUDT channelUDT) { + super(parent, id, channelUDT, OP_READ); + try { + channelUDT.configureBlocking(false); + switch (channelUDT.socketUDT().status()) { + case INIT: + case OPENED: + config = new DefaultUdtChannelConfig(this, channelUDT, true); + break; + default: + config = new DefaultUdtChannelConfig(this, channelUDT, false); + break; + } + } catch (final Exception e) { + try { + channelUDT.close(); + } catch (final Exception e2) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to close channel.", e2); + } + } + throw new ChannelException("Failed to configure channel.", e); + } + } + + public NioUdtMessageConnectorChannel(final SocketChannelUDT channelUDT) { + this(null, channelUDT.socketUDT().id(), channelUDT); + } + + public NioUdtMessageConnectorChannel(final TypeUDT type) { + this(NioUdtProvider.newConnectorChannelUDT(type)); + } + + @Override + public UdtChannelConfig config() { + return config; + } + + @Override + protected void doBind(final SocketAddress localAddress) throws Exception { + javaChannel().bind(localAddress); + } + + @Override + protected void doClose() throws Exception { + javaChannel().close(); + } + + @Override + protected boolean doConnect(final SocketAddress remoteAddress, + final SocketAddress localAddress) throws Exception { + doBind(localAddress); + boolean success = false; + try { + final boolean connected = javaChannel().connect(remoteAddress); + if (!connected) { + selectionKey().interestOps( + selectionKey().interestOps() | OP_CONNECT); + } + success = true; + return connected; + } finally { + if (!success) { + doClose(); + } + } + } + + @Override + protected void doDisconnect() throws Exception { + doClose(); + } + + @Override + protected void doFinishConnect() throws Exception { + if (javaChannel().finishConnect()) { + selectionKey().interestOps( + selectionKey().interestOps() & ~OP_CONNECT); + } else { + throw new Error( + "Provider error: failed to finish connect. Provider library should be upgraded."); + } + } + + @Override + protected int doReadMessages(final MessageBuf buf) throws Exception { + + final int maximumMessageSize = config.getReceiveBufferSize(); + + final ByteBuf byteBuf = config.getAllocator().directBuffer( + maximumMessageSize); + + final int receivedMessageSize = byteBuf.writeBytes(javaChannel(), + maximumMessageSize); + + if (receivedMessageSize <= 0) { + byteBuf.free(); + return 0; + } + + if (receivedMessageSize >= maximumMessageSize) { + javaChannel().close(); + throw new ChannelException( + "Invalid config : increase receive buffer size to avoid message truncation"); + } + + // delivers a message + buf.add(new UdtMessage(byteBuf)); + + return 1; + } + + @Override + protected int doWriteMessages(final MessageBuf messageQueue, + final boolean lastSpin) throws Exception { + + // expects a message + final UdtMessage message = (UdtMessage) messageQueue.peek(); + + final ByteBuf byteBuf = message.data(); + + final int messageSize = byteBuf.readableBytes(); + + final long writtenBytes; + if (byteBuf.nioBufferCount() == 1) { + writtenBytes = javaChannel().write(byteBuf.nioBuffer()); + } else { + writtenBytes = javaChannel().write(byteBuf.nioBuffers()); + } + + final SelectionKey key = selectionKey(); + final int interestOps = key.interestOps(); + + // did not write the message + if (writtenBytes <= 0 && messageSize > 0) { + if (lastSpin) { + if ((interestOps & OP_WRITE) == 0) { + key.interestOps(interestOps | OP_WRITE); + } + } + return 0; + } + + // wrote message completely + if (writtenBytes != messageSize) { + throw new Error( + "Provider error: failed to write message. Provider library should be upgraded."); + } + + // wrote the message queue completely - clear OP_WRITE. + if (messageQueue.isEmpty()) { + if ((interestOps & OP_WRITE) != 0) { + key.interestOps(interestOps & ~OP_WRITE); + } + } + + messageQueue.remove(); + + message.free(); + + return 1; + } + + @Override + public boolean isActive() { + final SocketChannelUDT channelUDT = javaChannel(); + return channelUDT.isOpen() && channelUDT.isConnectFinished(); + } + + @Override + protected SocketChannelUDT javaChannel() { + return (SocketChannelUDT) super.javaChannel(); + } + + @Override + protected SocketAddress localAddress0() { + return javaChannel().socket().getLocalSocketAddress(); + } + + @Override + public ChannelMetadata metadata() { + return METADATA; + } + + @Override + protected SocketAddress remoteAddress0() { + return javaChannel().socket().getRemoteSocketAddress(); + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageRendezvousChannel.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageRendezvousChannel.java new file mode 100644 index 000000000000..74e8b3c3d402 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtMessageRendezvousChannel.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.UdtChannel; +import io.netty.transport.udt.UdtMessage; + +import com.barchart.udt.TypeUDT; + +/** + * Message Rendezvous for UDT Datagrams. + *

+ * Note: send/receive must use {@link UdtMessage} in the pipeline + */ +public class NioUdtMessageRendezvousChannel extends + NioUdtMessageConnectorChannel implements UdtChannel { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtMessageConnectorChannel.class); + + public NioUdtMessageRendezvousChannel() { + super(NioUdtProvider.newRendezvousChannelUDT(TypeUDT.DATAGRAM)); + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtProvider.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtProvider.java new file mode 100644 index 000000000000..55b18ea4a96f --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/NioUdtProvider.java @@ -0,0 +1,247 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.bootstrap.AbstractBootstrap.ChannelFactory; +import io.netty.channel.Channel; +import io.netty.channel.ChannelException; +import io.netty.logging.InternalLogger; +import io.netty.logging.InternalLoggerFactory; +import io.netty.transport.udt.UdtChannel; + +import java.io.IOException; +import java.nio.channels.spi.SelectorProvider; + +import com.barchart.udt.SocketUDT; +import com.barchart.udt.TypeUDT; +import com.barchart.udt.nio.ChannelUDT; +import com.barchart.udt.nio.KindUDT; +import com.barchart.udt.nio.RendezvousChannelUDT; +import com.barchart.udt.nio.SelectorProviderUDT; +import com.barchart.udt.nio.ServerSocketChannelUDT; +import com.barchart.udt.nio.SocketChannelUDT; + +/** + * UDT NIO components provider: + *

+ * Provides {@link ChannelFactory} for UDT channels. + *

+ * Provides {@link SelectorProvider} for UDT channels. + */ +public final class NioUdtProvider implements ChannelFactory { + + private static final InternalLogger logger = InternalLoggerFactory + .getInstance(NioUdtProvider.class); + + /** + * {@link ChannelFactory} for UDT Byte Acceptor. See {@link TypeUDT#STREAM} + * and {@link KindUDT#ACCEPTOR}. + */ + public static final ChannelFactory BYTE_ACCEPTOR = new NioUdtProvider( + TypeUDT.STREAM, KindUDT.ACCEPTOR); + + /** + * {@link ChannelFactory} for UDT Byte Connector. See {@link TypeUDT#STREAM} + * and {@link KindUDT#CONNECTOR}. + */ + public static final ChannelFactory BYTE_CONNECTOR = new NioUdtProvider( + TypeUDT.STREAM, KindUDT.CONNECTOR); + + /** + * {@link SelectorProvider} for UDT Byte channels. See + * {@link TypeUDT#STREAM}. + */ + public static final SelectorProvider BYTE_PROVIDER = SelectorProviderUDT.STREAM; + + /** + * {@link ChannelFactory} for UDT Byte Rendezvous. See + * {@link TypeUDT#STREAM} and {@link KindUDT#RENDEZVOUS}. + */ + public static final ChannelFactory BYTE_RENDEZVOUS = new NioUdtProvider( + TypeUDT.STREAM, KindUDT.RENDEZVOUS); + + /** + * {@link ChannelFactory} for UDT Message Acceptor. See + * {@link TypeUDT#DATAGRAM} and {@link KindUDT#ACCEPTOR}. + */ + public static final ChannelFactory MESSAGE_ACCEPTOR = new NioUdtProvider( + TypeUDT.DATAGRAM, KindUDT.ACCEPTOR); + + /** + * {@link ChannelFactory} for UDT Message Connector. See + * {@link TypeUDT#DATAGRAM} and {@link KindUDT#CONNECTOR}. + */ + public static final ChannelFactory MESSAGE_CONNECTOR = new NioUdtProvider( + TypeUDT.DATAGRAM, KindUDT.CONNECTOR); + + /** + * {@link SelectorProvider} for UDT Message channels. See + * {@link TypeUDT#DATAGRAM}. + */ + public static final SelectorProvider MESSAGE_PROVIDER = SelectorProviderUDT.DATAGRAM; + + /** + * {@link ChannelFactory} for UDT Message Rendezvous. See + * {@link TypeUDT#DATAGRAM} and {@link KindUDT#RENDEZVOUS}. + */ + public static final ChannelFactory MESSAGE_RENDEZVOUS = new NioUdtProvider( + TypeUDT.DATAGRAM, KindUDT.RENDEZVOUS); + + /** + * Expose underlying {@link ChannelUDT} for debugging and monitoring. + *

+ * @return underlying {@link ChannelUDT} or null, if parameter is not + * {@link UdtChannel} + */ + public static ChannelUDT channelUDT(final Channel channel) { + // bytes + if (channel instanceof NioUdtByteAcceptorChannel) { + return ((NioUdtByteAcceptorChannel) channel).javaChannel(); + } + if (channel instanceof NioUdtByteConnectorChannel) { + return ((NioUdtByteConnectorChannel) channel).javaChannel(); + } + if (channel instanceof NioUdtByteRendezvousChannel) { + return ((NioUdtByteRendezvousChannel) channel).javaChannel(); + } + // message + if (channel instanceof NioUdtMessageAcceptorChannel) { + return ((NioUdtMessageAcceptorChannel) channel).javaChannel(); + } + if (channel instanceof NioUdtMessageConnectorChannel) { + return ((NioUdtMessageConnectorChannel) channel).javaChannel(); + } + if (channel instanceof NioUdtMessageRendezvousChannel) { + return ((NioUdtMessageRendezvousChannel) channel).javaChannel(); + } + return null; + } + + /** + * Convenience factory for {@link KindUDT#ACCEPTOR} channels. + */ + protected static ServerSocketChannelUDT newAcceptorChannelUDT( + final TypeUDT type) { + try { + return SelectorProviderUDT.from(type).openServerSocketChannel(); + } catch (final IOException e) { + throw new ChannelException("Failed to open channel"); + } + } + + /** + * Convenience factory for {@link KindUDT#CONNECTOR} channels. + */ + protected static SocketChannelUDT newConnectorChannelUDT(final TypeUDT type) { + try { + return SelectorProviderUDT.from(type).openSocketChannel(); + } catch (final IOException e) { + throw new ChannelException("Failed to open channel"); + } + } + + /** + * Convenience factory for {@link KindUDT#RENDEZVOUS} channels. + */ + protected static RendezvousChannelUDT newRendezvousChannelUDT( + final TypeUDT type) { + try { + return SelectorProviderUDT.from(type).openRendezvousChannel(); + } catch (final IOException e) { + throw new ChannelException("Failed to open channel"); + } + } + + /** + * Expose underlying {@link SocketUDT} for debugging and monitoring. + *

+ * @return underlying {@link SocketUDT} or null, if parameter is not + * {@link UdtChannel} + */ + public static SocketUDT socketUDT(final Channel channel) { + final ChannelUDT channelUDT = channelUDT(channel); + if (channelUDT == null) { + return null; + } else { + return channelUDT.socketUDT(); + } + } + + private final KindUDT kind; + private final TypeUDT type; + + /** + * {@link ChannelFactory} for given {@link TypeUDT} and {@link KindUDT} + */ + private NioUdtProvider(final TypeUDT type, final KindUDT kind) { + this.type = type; + this.kind = kind; + } + + /** + * UDT Channel Kind. See {@link KindUDT} + */ + public KindUDT kind() { + return kind; + } + + /** + * Produce new {@link UdtChannel} based on factory {@link #kind()} and + * {@link #type()} + */ + @Override + public UdtChannel newChannel() { + switch (kind) { + case ACCEPTOR: + switch (type) { + case DATAGRAM: + return new NioUdtMessageAcceptorChannel(); + case STREAM: + return new NioUdtByteAcceptorChannel(); + default: + throw new IllegalStateException("wrong type=" + type); + } + case CONNECTOR: + switch (type) { + case DATAGRAM: + return new NioUdtMessageConnectorChannel(); + case STREAM: + return new NioUdtByteConnectorChannel(); + default: + throw new IllegalStateException("wrong type=" + type); + } + case RENDEZVOUS: + switch (type) { + case DATAGRAM: + return new NioUdtMessageRendezvousChannel(); + case STREAM: + return new NioUdtByteRendezvousChannel(); + default: + throw new IllegalStateException("wrong type=" + type); + } + default: + throw new IllegalStateException("wrong kind=" + kind); + } + } + + /** + * UDT Socket Type. See {@link TypeUDT} + */ + public TypeUDT type() { + return type; + } + +} diff --git a/transport-udt/src/main/java/io/netty/transport/udt/nio/package-info.java b/transport-udt/src/main/java/io/netty/transport/udt/nio/package-info.java new file mode 100644 index 000000000000..fe7bc0f22c83 --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/nio/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ +/** + * UDT Transport for NIO Channels. + *

+ * @see /netty/example/src/main/java/io/netty/example/udt + */ +package io.netty.transport.udt.nio; + diff --git a/transport-udt/src/main/java/io/netty/transport/udt/oio/package-info.java b/transport-udt/src/main/java/io/netty/transport/udt/oio/package-info.java new file mode 100644 index 000000000000..8d7863c1813b --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/oio/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ +/** + * UDT Transport for OIO Channels. + *

+ * @see /netty/example/src/main/java/io/netty/example/udt + */ +package io.netty.transport.udt.oio; + diff --git a/transport-udt/src/main/java/io/netty/transport/udt/package-info.java b/transport-udt/src/main/java/io/netty/transport/udt/package-info.java new file mode 100644 index 000000000000..933877ca2d7e --- /dev/null +++ b/transport-udt/src/main/java/io/netty/transport/udt/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ +/** + * UDT Transport. + *

+ * @see /netty/example/src/main/java/io/netty/example/udt + */ +package io.netty.transport.udt; + diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/BenchXfer.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/BenchXfer.java new file mode 100644 index 000000000000..a015f350f3ab --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/BenchXfer.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.bench; + +import io.netty.transport.udt.util.CaliperBench; +import io.netty.transport.udt.util.CaliperRunner; +import io.netty.transport.udt.util.TrafficControl; + +import java.util.List; + +/** + * perform two way native udt socket send/recv + */ +public abstract class BenchXfer extends CaliperBench { + + /** introduce network latency */ + protected static List latencyList() { + if (TrafficControl.isAvailable()) { + return CaliperRunner.valueList("0,10,30"); + } else { + return CaliperRunner.valueList("0"); + } + } + + /** verify different message sizes */ + protected static List messageList() { + return CaliperRunner + .valueList("500,1500,3000,5000,10000,20000,50000,100000"); + } + + /** benchmark run time per each configuration */ + protected static List durationList() { + return CaliperRunner.valueList("30000"); + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/package-info.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/package-info.java new file mode 100644 index 000000000000..fc2c1dcd6aa5 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * UDT Benchmarks + */ +package io.netty.transport.udt.bench; + diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/TcpNative.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/TcpNative.java new file mode 100644 index 000000000000..0885eedab33e --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/TcpNative.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.bench.xfer; + +import io.netty.transport.udt.bench.BenchXfer; +import io.netty.transport.udt.util.CaliperRunner; +import io.netty.transport.udt.util.TrafficControl; + +import java.util.List; + +import com.google.caliper.Param; + +/** + * perform two way native TCP socket send/recv + */ +public class TcpNative extends BenchXfer { + + @Param + private volatile int latency; + + protected static List latencyValues() { + return BenchXfer.latencyList(); + } + + @Param + private volatile int message; + + protected static List messageValues() { + return BenchXfer.messageList(); + } + + @Param + private volatile int duration; + + protected static List durationValues() { + return BenchXfer.durationList(); + } + + public void timeRun(final int reps) throws Exception { + log.info("init"); + + TrafficControl.delay(latency); + + TrafficControl.delay(0); + + log.info("done"); + } + + public static void main(final String[] args) throws Exception { + CaliperRunner.execute(TcpNative.class); + } +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNative.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNative.java new file mode 100644 index 000000000000..b1a0466ee7c0 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNative.java @@ -0,0 +1,270 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.bench.xfer; + +import static io.netty.transport.udt.util.UnitHelp.*; +import io.netty.transport.udt.bench.BenchXfer; +import io.netty.transport.udt.util.CaliperRunner; +import io.netty.transport.udt.util.TrafficControl; + +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.barchart.udt.SocketUDT; +import com.barchart.udt.StatusUDT; +import com.barchart.udt.TypeUDT; +import com.google.caliper.Param; + +/** + * perform two way native UDT socket send/recv + */ +public class UdtNative extends BenchXfer { + + @Param + private volatile int latency; + + protected static List latencyValues() { + return BenchXfer.latencyList(); + } + + @Param + private volatile int message; + + protected static List messageValues() { + return BenchXfer.messageList(); + } + + @Param + private volatile int duration; + + protected static List durationValues() { + return BenchXfer.durationList(); + } + + private volatile SocketUDT peer1; + private volatile SocketUDT peer2; + + @Override + protected void setUp() throws Exception { + log.info("init"); + + TrafficControl.delay(latency); + + final InetSocketAddress addr1 = localSocketAddress(); + final InetSocketAddress addr2 = localSocketAddress(); + + peer1 = new SocketUDT(TypeUDT.DATAGRAM); + peer2 = new SocketUDT(TypeUDT.DATAGRAM); + + peer1.setBlocking(false); + peer2.setBlocking(false); + + peer1.setRendezvous(true); + peer2.setRendezvous(true); + + peer1.bind(addr1); + peer2.bind(addr2); + + socketAwait(peer1, StatusUDT.OPENED); + socketAwait(peer2, StatusUDT.OPENED); + + peer1.connect(addr2); + peer2.connect(addr1); + + socketAwait(peer1, StatusUDT.CONNECTED); + socketAwait(peer2, StatusUDT.CONNECTED); + + peer1.setBlocking(true); + peer2.setBlocking(true); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + peer1.setBlocking(false); + peer2.setBlocking(false); + + peer1.close(); + peer2.close(); + + socketAwait(peer1, StatusUDT.CLOSED, StatusUDT.BROKEN); + socketAwait(peer2, StatusUDT.CLOSED, StatusUDT.BROKEN); + + TrafficControl.delay(0); + + log.info("done"); + } + + /** benchmark invocation */ + public void timeMain(final int reps) throws Exception { + + final int threadCount = 4; + + final CountDownLatch completion = new CountDownLatch(threadCount); + + final AtomicBoolean isOn = new AtomicBoolean(true); + + final Runnable sendPeer1 = new Runnable() { + + @Override + public void run() { + try { + while (isOn.get()) { + runCore(); + } + } catch (final Exception e) { + log.error("", e); + } finally { + completion.countDown(); + } + } + + final ByteBuffer buffer = ByteBuffer.allocateDirect(message); + + long sequence; + + void runCore() throws Exception { + buffer.rewind(); + buffer.putLong(0, sequence++); + final int count = peer1.send(buffer); + if (count != message) { + throw new Exception("count"); + } + measure().rate().mark(count); + } + }; + + final Runnable sendPeer2 = new Runnable() { + + @Override + public void run() { + try { + while (isOn.get()) { + runCore(); + } + } catch (final Exception e) { + log.error("", e); + } finally { + completion.countDown(); + } + } + + final ByteBuffer buffer = ByteBuffer.allocateDirect(message); + + long sequence; + + void runCore() throws Exception { + buffer.rewind(); + buffer.putLong(0, sequence++); + final int count = peer2.send(buffer); + if (count != message) { + throw new Exception("count"); + } + } + }; + + final Runnable recvPeer1 = new Runnable() { + + @Override + public void run() { + try { + while (isOn.get()) { + runCore(); + } + } catch (final Exception e) { + log.error("", e); + } finally { + completion.countDown(); + } + } + + final ByteBuffer buffer = ByteBuffer.allocateDirect(message); + + long sequence; + + void runCore() throws Exception { + buffer.rewind(); + final int count = peer1.receive(buffer); + if (count != message) { + throw new Exception("count"); + } + if (this.sequence++ != buffer.getLong(0)) { + throw new Exception("sequence"); + } + } + }; + + final Runnable recvPeer2 = new Runnable() { + + @Override + public void run() { + try { + while (isOn.get()) { + runCore(); + } + } catch (final Exception e) { + log.error("", e); + } finally { + completion.countDown(); + } + } + + final ByteBuffer buffer = ByteBuffer.allocateDirect(message); + + long sequence; + + void runCore() throws Exception { + buffer.rewind(); + final int count = peer2.receive(buffer); + if (count != message) { + throw new Exception("count"); + } + if (this.sequence++ != buffer.getLong(0)) { + throw new Exception("sequence"); + } + } + }; + + final ExecutorService executor = Executors + .newFixedThreadPool(threadCount); + + executor.submit(recvPeer1); + executor.submit(recvPeer2); + executor.submit(sendPeer1); + executor.submit(sendPeer2); + + markWait(duration); + + isOn.set(false); + + completion.await(); + + executor.shutdownNow(); + } + + public static void main(final String[] args) throws Exception { + CaliperRunner.execute(UdtNative.class); + } +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNetty.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNetty.java new file mode 100644 index 000000000000..8323ce2daae3 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/UdtNetty.java @@ -0,0 +1,137 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.bench.xfer; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.logging.InternalLoggerFactory; +import io.netty.logging.Slf4JLoggerFactory; +import io.netty.transport.udt.util.BootHelp; +import io.netty.transport.udt.util.CustomReporter; +import io.netty.transport.udt.util.EchoMessageHandler; +import io.netty.transport.udt.util.TrafficControl; +import io.netty.transport.udt.util.UnitHelp; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Counter; +import com.yammer.metrics.core.Meter; + +/** + * perform two way netty send/recv + */ +public final class UdtNetty { + + private UdtNetty() { + } + + static final Logger log = LoggerFactory.getLogger(UdtNetty.class); + + /** + * use slf4j provider for io.netty.logging.InternalLogger + */ + static { + final InternalLoggerFactory defaultFactory = new Slf4JLoggerFactory(); + InternalLoggerFactory.setDefaultFactory(defaultFactory); + log.info("InternalLoggerFactory={}", InternalLoggerFactory + .getDefaultFactory().getClass().getName()); + } + + /** benchmark duration */ + static final int time = 10 * 60 * 1000; + + /** transfer chunk size */ + static final int size = 64 * 1024; + + static final Counter benchTime = Metrics.newCounter(UdtNetty.class, + "bench time"); + + static final Counter benchSize = Metrics.newCounter(UdtNetty.class, + "bench size"); + + static { + benchTime.inc(time); + benchSize.inc(size); + } + + static final Meter rate = Metrics.newMeter(UdtNetty.class, "rate", + "bytes", TimeUnit.SECONDS); + + static { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + TrafficControl.delay(0); + } catch (final Exception e) { + log.error("", e); + } + } + }); + } + + public static void main(final String[] args) throws Exception { + + log.info("init"); + TrafficControl.delay(0); + + final AtomicBoolean isOn = new AtomicBoolean(true); + + final InetSocketAddress addr1 = UnitHelp.localSocketAddress(); + final InetSocketAddress addr2 = UnitHelp.localSocketAddress(); + + final ChannelHandler handler1 = new EchoMessageHandler(rate, size); + final ChannelHandler handler2 = new EchoMessageHandler(null, size); + + final Bootstrap peerBoot1 = BootHelp.messagePeerBoot(addr1, addr2, + handler1); + final Bootstrap peerBoot2 = BootHelp.messagePeerBoot(addr2, addr1, + handler2); + + final ChannelFuture peerFuture1 = peerBoot1.connect(); + final ChannelFuture peerFuture2 = peerBoot2.connect(); + + CustomReporter.enable(3, TimeUnit.SECONDS); + + Thread.sleep(time); + + isOn.set(false); + + Thread.sleep(1 * 1000); + + peerFuture1.channel().close().sync(); + peerFuture2.channel().close().sync(); + + Thread.sleep(1 * 1000); + + peerBoot1.shutdown(); + peerBoot2.shutdown(); + + Metrics.defaultRegistry().shutdown(); + + TrafficControl.delay(0); + log.info("done"); + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/package-info.java b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/package-info.java new file mode 100644 index 000000000000..3ca762c456e2 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/bench/xfer/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * UDT Transfer Speed Benchmarks + */ +package io.netty.transport.udt.bench.xfer; + diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestAny.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestAny.java new file mode 100644 index 000000000000..11e4a27a76e7 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestAny.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import io.netty.logging.InternalLoggerFactory; +import io.netty.logging.Slf4JLoggerFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * shared test base + */ +public abstract class TestAny { + + protected static final Logger log = LoggerFactory.getLogger(TestAny.class); + + /** + * use slf4j provider for io.netty.logging.InternalLogger + */ + static { + final InternalLoggerFactory defaultFactory = new Slf4JLoggerFactory(); + InternalLoggerFactory.setDefaultFactory(defaultFactory); + log.info("InternalLoggerFactory={}", InternalLoggerFactory + .getDefaultFactory().getClass().getName()); + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteAcceptorChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteAcceptorChannel.java new file mode 100644 index 000000000000..69be6f5b8f55 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteAcceptorChannel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.buffer.BufType; + +import org.junit.Test; + +public class TestNioUdtByteAcceptorChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.BYTE, new NioUdtByteAcceptorChannel().metadata() + .bufferType()); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteConnectorChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteConnectorChannel.java new file mode 100644 index 000000000000..afe1273fed80 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteConnectorChannel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.buffer.BufType; + +import org.junit.Test; + +public class TestNioUdtByteConnectorChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.BYTE, new NioUdtByteConnectorChannel().metadata() + .bufferType()); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteRendezvousChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteRendezvousChannel.java new file mode 100644 index 000000000000..2f3c35596e48 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtByteRendezvousChannel.java @@ -0,0 +1,103 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.BufType; +import io.netty.channel.ChannelFuture; +import io.netty.transport.udt.util.BootHelp; +import io.netty.transport.udt.util.EchoByteHandler; +import io.netty.transport.udt.util.UnitHelp; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Meter; + +public class TestNioUdtByteRendezvousChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.BYTE, new NioUdtByteRendezvousChannel().metadata() + .bufferType()); + + } + + /** + * verify basic echo byte rendezvous + */ + @Test(timeout = 10 * 1000) + public void basicEcho() throws Exception { + + final int messageSize = 64 * 1024; + final int transferLimit = messageSize * 16; + + final Meter rate1 = Metrics.newMeter( + TestNioUdtMessageRendezvousChannel.class, "send rate", "bytes", + TimeUnit.SECONDS); + + final Meter rate2 = Metrics.newMeter( + TestNioUdtMessageRendezvousChannel.class, "send rate", "bytes", + TimeUnit.SECONDS); + + final InetSocketAddress addr1 = UnitHelp.localSocketAddress(); + final InetSocketAddress addr2 = UnitHelp.localSocketAddress(); + + final EchoByteHandler handler1 = new EchoByteHandler(rate1, messageSize); + final EchoByteHandler handler2 = new EchoByteHandler(rate2, messageSize); + + final Bootstrap boot1 = BootHelp.bytePeerBoot(addr1, addr2, handler1); + final Bootstrap boot2 = BootHelp.bytePeerBoot(addr2, addr1, handler2); + + final ChannelFuture connectFuture1 = boot1.connect(); + final ChannelFuture connectFuture2 = boot2.connect(); + + while (handler1.meter().count() < transferLimit + && handler2.meter().count() < transferLimit) { + + log.info("progress : {} {}", handler1.meter().count(), handler2 + .meter().count()); + + Thread.sleep(1000); + + } + + connectFuture1.channel().close().sync(); + connectFuture2.channel().close().sync(); + + log.info("handler1 : {}", handler1.meter().count()); + log.info("handler2 : {}", handler2.meter().count()); + + assertTrue(handler1.meter().count() >= transferLimit); + assertTrue(handler2.meter().count() >= transferLimit); + + assertEquals(handler1.meter().count(), handler2.meter().count()); + + boot1.shutdown(); + boot2.shutdown(); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageAcceptorChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageAcceptorChannel.java new file mode 100644 index 000000000000..0be4eb1e35dd --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageAcceptorChannel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.buffer.BufType; + +import org.junit.Test; + +public class TestNioUdtMessageAcceptorChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.MESSAGE, new NioUdtMessageAcceptorChannel() + .metadata().bufferType()); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageConnectorChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageConnectorChannel.java new file mode 100644 index 000000000000..c48bb4e2a0fb --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageConnectorChannel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.buffer.BufType; + +import org.junit.Test; + +public class TestNioUdtMessageConnectorChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.MESSAGE, new NioUdtMessageConnectorChannel() + .metadata().bufferType()); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageRendezvousChannel.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageRendezvousChannel.java new file mode 100644 index 000000000000..6ce803481a67 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtMessageRendezvousChannel.java @@ -0,0 +1,107 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.BufType; +import io.netty.channel.ChannelFuture; +import io.netty.transport.udt.util.BootHelp; +import io.netty.transport.udt.util.EchoMessageHandler; +import io.netty.transport.udt.util.UnitHelp; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Meter; + +public class TestNioUdtMessageRendezvousChannel extends TestAny { + + /** + * verify channel meta data + */ + @Test + public void metadata() throws Exception { + + assertEquals(BufType.MESSAGE, new NioUdtMessageRendezvousChannel() + .metadata().bufferType()); + + } + + /** + * verify basic echo message rendezvous + */ + @Test(timeout = 10 * 1000) + public void basicEcho() throws Exception { + + final int messageSize = 64 * 1024; + final int transferLimit = messageSize * 16; + + final Meter rate1 = Metrics.newMeter( + TestNioUdtMessageRendezvousChannel.class, "send rate", "bytes", + TimeUnit.SECONDS); + + final Meter rate2 = Metrics.newMeter( + TestNioUdtMessageRendezvousChannel.class, "send rate", "bytes", + TimeUnit.SECONDS); + + final InetSocketAddress addr1 = UnitHelp.localSocketAddress(); + final InetSocketAddress addr2 = UnitHelp.localSocketAddress(); + + final EchoMessageHandler handler1 = new EchoMessageHandler(rate1, + messageSize); + final EchoMessageHandler handler2 = new EchoMessageHandler(rate2, + messageSize); + + final Bootstrap boot1 = BootHelp + .messagePeerBoot(addr1, addr2, handler1); + final Bootstrap boot2 = BootHelp + .messagePeerBoot(addr2, addr1, handler2); + + final ChannelFuture connectFuture1 = boot1.connect(); + final ChannelFuture connectFuture2 = boot2.connect(); + + while (handler1.meter().count() < transferLimit + && handler2.meter().count() < transferLimit) { + + log.info("progress : {} {}", handler1.meter().count(), handler2 + .meter().count()); + + Thread.sleep(1000); + + } + + connectFuture1.channel().close().sync(); + connectFuture2.channel().close().sync(); + + log.info("handler1 : {}", handler1.meter().count()); + log.info("handler2 : {}", handler2.meter().count()); + + assertTrue(handler1.meter().count() >= transferLimit); + assertTrue(handler2.meter().count() >= transferLimit); + + assertEquals(handler1.meter().count(), handler2.meter().count()); + + boot1.shutdown(); + boot2.shutdown(); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtProvider.java b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtProvider.java new file mode 100644 index 000000000000..a0f2661eb9a9 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/nio/TestNioUdtProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.nio; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class TestNioUdtProvider extends TestAny { + + /** + * verify factory + */ + @Test + public void provideFactory() { + + // bytes + assertNotNull(NioUdtProvider.BYTE_ACCEPTOR.newChannel()); + assertNotNull(NioUdtProvider.BYTE_CONNECTOR.newChannel()); + assertNotNull(NioUdtProvider.BYTE_RENDEZVOUS.newChannel()); + + // message + assertNotNull(NioUdtProvider.MESSAGE_ACCEPTOR.newChannel()); + assertNotNull(NioUdtProvider.MESSAGE_CONNECTOR.newChannel()); + assertNotNull(NioUdtProvider.MESSAGE_RENDEZVOUS.newChannel()); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/BootHelp.java b/transport-udt/src/test/java/io/netty/transport/udt/util/BootHelp.java new file mode 100644 index 000000000000..ac8d1fe5491a --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/BootHelp.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelHandler; +import io.netty.channel.socket.nio.NioEventLoopGroup; +import io.netty.transport.udt.nio.NioUdtProvider; + +import java.net.InetSocketAddress; +import java.util.concurrent.ThreadFactory; + +/** + * Bootstrap utilities. + */ +public class BootHelp { + + /** + * bootstrap for byte rendezvous peer + */ + public static Bootstrap bytePeerBoot(final InetSocketAddress self, + final InetSocketAddress peer, final ChannelHandler handler) { + + final Bootstrap boot = new Bootstrap(); + + final ThreadFactory connectFactory = new UtilThreadFactory("peer"); + + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.BYTE_PROVIDER); + + boot.group(connectGroup).channelFactory(NioUdtProvider.BYTE_RENDEZVOUS) + .localAddress(self).remoteAddress(peer).handler(handler); + + return boot; + + } + + /** + * bootstrap for message rendezvous peer + */ + public static Bootstrap messagePeerBoot(final InetSocketAddress self, + final InetSocketAddress peer, final ChannelHandler handler) { + + final Bootstrap boot = new Bootstrap(); + + final ThreadFactory connectFactory = new UtilThreadFactory("peer"); + + final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, + connectFactory, NioUdtProvider.MESSAGE_PROVIDER); + + boot.group(connectGroup) + .channelFactory(NioUdtProvider.MESSAGE_RENDEZVOUS) + .localAddress(self).remoteAddress(peer).handler(handler); + + return boot; + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperBench.java b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperBench.java new file mode 100644 index 000000000000..01f52cf4e105 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperBench.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import io.netty.logging.InternalLoggerFactory; +import io.netty.logging.Slf4JLoggerFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.caliper.SimpleBenchmark; + +/** + * Base class for caliper/metrics benchmarks. + */ +public abstract class CaliperBench extends SimpleBenchmark { + + /** + * Ensure no network latency after JVM shutdown + */ + static { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + TrafficControl.delay(0); + } catch (final Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Use slf4j logging. + */ + static { + final InternalLoggerFactory defaultFactory = new Slf4JLoggerFactory(); + InternalLoggerFactory.setDefaultFactory(defaultFactory); + } + + protected final Logger log = LoggerFactory.getLogger(getClass()); + + private volatile CaliperMeasure measure; + + /** + * Caliper metrics wrapper. + */ + protected CaliperMeasure measure() { + return measure; + } + + /** + * Start measurement. + */ + @Override + protected void setUp() throws Exception { + measure = new CaliperMeasure(); + } + + /** + * Finish measurement. + */ + @Override + protected void tearDown() throws Exception { + measure.shutdown(); + } + + /** + * Measure time step and minimum run time. + */ + protected long markStep() { + return 3 * 1000; + } + + /** + * Measure progress while in sleep. + */ + protected void markWait(final long time) throws Exception { + + final long timeStart = System.currentTimeMillis(); + + while (true) { + Thread.sleep(markStep()); + measure().mark(); + final long timeFinish = System.currentTimeMillis(); + if (timeFinish - timeStart >= time) { + System.out.print("+\n"); + return; + } else { + System.out.print("-"); + continue; + } + } + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperMeasure.java b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperMeasure.java new file mode 100644 index 000000000000..2d43c48d8a3a --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperMeasure.java @@ -0,0 +1,224 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.caliper.Measurement; +import com.google.caliper.MeasurementSet; +import com.google.caliper.Run; +import com.google.caliper.Scenario; +import com.google.caliper.ScenarioResult; +import com.yammer.metrics.core.Gauge; +import com.yammer.metrics.core.Meter; +import com.yammer.metrics.core.MetricsRegistry; +import com.yammer.metrics.core.Timer; + +/** + * Caliper measure with Metrics provider. + *

+ * measure up to 3 values: {@link #rate()}, {@link #time()}, {@link #size()} + */ +public class CaliperMeasure { + + private final static Logger log = LoggerFactory + .getLogger(CaliperMeasure.class); + + /** + * Gauge any double value + */ + public static class SizeGuage extends Gauge { + + private volatile Double size = 0.0; + + @Override + public Double value() { + return size; + } + + public void value(final double number) { + this.size = number; + } + } + + /** + * Default rate measurement units. + */ + private static final Map RATE_UNIT = new HashMap(); + static { + RATE_UNIT.put("Rate B/s", 1); + RATE_UNIT.put("Rate KB/s", 1024); + RATE_UNIT.put("Rate MB/s", 1024 * 1024); + RATE_UNIT.put("Rate GB/s", 1024 * 1024 * 1024); + } + + /** + * Default time measurement units. + */ + private static final Map TIME_UNIT = new HashMap(); + static { + TIME_UNIT.put("Time ns", 1); + TIME_UNIT.put("Time us", 1000); + TIME_UNIT.put("Time ms", 1000 * 1000); + TIME_UNIT.put("Time s ", 1000 * 1000 * 1000); + } + + /** + * Default size measurement units. + */ + private static final Map SIZE_UNIT = new HashMap(); + static { + SIZE_UNIT.put("Size B", 1); + SIZE_UNIT.put("Size KB", 1024); + SIZE_UNIT.put("Size MB", 1024 * 1024); + SIZE_UNIT.put("Size GB", 1024 * 1024 * 1024); + } + + private final Map rateMap = new HashMap(); + private final Map timeMap = new HashMap(); + private final Map sizeMap = new HashMap(); + + private final MetricsRegistry metrics = new MetricsRegistry(); + + private final Meter rate = metrics.newMeter(getClass(), "rate", "bytes", + TimeUnit.SECONDS); + + private final Timer time = metrics.newTimer(getClass(), "time", + TimeUnit.NANOSECONDS, TimeUnit.SECONDS); + + private final SizeGuage size = new SizeGuage(); + { + metrics.newGauge(getClass(), "", size); + } + + /** + * Rate meter. + */ + public Meter rate() { + return rate; + } + + /** + * Time meter. + */ + public Timer time() { + return time; + } + + /** + * Size meter. + */ + public SizeGuage size() { + return size; + } + + /** + * Workaround: zero breaks gwt web app. + */ + private double filter(final double value) { + if (value <= 0.0) { + return 1.0; + } else { + return value; + } + } + + /** + * Perform measurement; convert from metrics into caliper. + */ + public void mark() { + final double rateValue = filter(rate.oneMinuteRate()); + final double timeValue = filter(time.mean()); + final double sizeValue = filter(size.value()); + if (rateValue == 1.0 && timeValue == 1.0 && sizeValue == 1.0) { + /** ignore complete blank entries */ + return; + } + { + final Measurement mark = new Measurement(RATE_UNIT, rateValue, + rateValue); + rateMap.put(System.nanoTime(), mark); + } + { + final Measurement mark = new Measurement(TIME_UNIT, timeValue, + timeValue); + timeMap.put(System.nanoTime(), mark); + } + { + final Measurement mark = new Measurement(SIZE_UNIT, sizeValue, + sizeValue); + sizeMap.put(System.nanoTime(), mark); + } + } + + private final Map variables = new HashMap(); + + /** + * Caliper scenario variables. + */ + public Map variables() { + return variables; + } + + private MeasurementSet measurementSet(final Map map) { + final Measurement[] array = map.values().toArray(new Measurement[0]); + final MeasurementSet set = new MeasurementSet(array); + return set; + } + + /** + * Attach this measure to parent caliper run. + */ + public void appendTo(final Run run) { + + final Scenario scenario = new Scenario(variables()); + + /** display rate as caliper durations */ + final MeasurementSet timeSet = measurementSet(rateMap); + final String timeLog = null; + + /** display time as caliper instances */ + final MeasurementSet instSet = measurementSet(timeMap); + final String instLog = null; + + /** display size as caliper memory */ + final MeasurementSet heapSet = measurementSet(sizeMap); + final String heapLog = null; + + final ScenarioResult scenarioResult = new ScenarioResult(timeSet, + timeLog, instSet, instLog, heapSet, heapLog); + + final Map measurements = run + .getMeasurements(); + + measurements.put(scenario, scenarioResult); + } + + /** + * Terminate metrics resources. + */ + public void shutdown() { + rate.stop(); + time.stop(); + metrics.shutdown(); + } +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperRunner.java b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperRunner.java new file mode 100644 index 000000000000..e74e5380b8fc --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/CaliperRunner.java @@ -0,0 +1,245 @@ +/* + * Copyright 2012 The Netty Project + + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.caliper.ConfiguredBenchmark; +import com.google.caliper.Environment; +import com.google.caliper.EnvironmentGetter; +import com.google.caliper.Json; +import com.google.caliper.Result; +import com.google.caliper.Run; +import com.google.caliper.Runner; +import com.google.caliper.Scenario; +import com.google.caliper.ScenarioResult; +import com.google.caliper.SimpleBenchmark; +import com.yammer.metrics.core.TimerContext; + +/** + * Custom caliper runner for {@link CaliperBench}. + */ +public final class CaliperRunner { + + private final static Logger log = LoggerFactory + .getLogger(CaliperRunner.class); + + private CaliperRunner() { + } + + /** + * Parse bench parameters. + */ + public static List valueList(final String valueText) { + return Arrays.asList(valueText.split(",")); + } + + /** + * Execute full cycle: warm up, execute and publish benchmark. + */ + public static void execute(final Class klaz) + throws Exception { + Run run; + run = execute("WARMUP", klaz); + run = execute("REPORT", klaz); + publish(newResult(run)); + } + + /** + * Execute benchmark for all parameter combinations. + */ + public static Run execute(final String name, + final Class klaz) throws Exception { + + final CaliperBench booter = klaz.newInstance(); + + final List> varsSet = product(booter); + + final Run run = newRun(klaz.getName()); + + int index = 0; + for (final Map vars : varsSet) { + final int done = 100 * index++ / varsSet.size(); + + log.info("{} {}% {}", name, done, vars); + + /** call setUp() */ + final ConfiguredBenchmark runner = booter.createBenchmark(vars); + + final CaliperBench bench = (CaliperBench) runner.getBenchmark(); + final CaliperMeasure measure = bench.measure(); + measure.variables().putAll(vars); + + /** call timeXXX() */ + runner.run(0); + + /** call tearDown() */ + runner.close(); + + measure.appendTo(run); + } + + return run; + } + + /** + * Convert caliper result into JSON string. + */ + public static String json(final Result result) { + return Json.getGsonInstance().toJson(result); + } + + /** + * Map signature based on map values. + */ + public static String signature(final Map map) { + final StringBuilder text = new StringBuilder(); + for (final String item : map.values()) { + text.append(String.format("%20s", item)); + } + return text.toString(); + } + + /** + * Generate all parameter combinations for {@link SimpleBenchmark}. + */ + public static List> product(final SimpleBenchmark bench) { + final Set> collect = new HashSet>(); + final Map> pending = new TreeMap>(); + for (final String name : new TreeSet(bench.parameterNames())) { + pending.put(name, bench.parameterValues(name)); + } + final List> list = new ArrayList>( + product(collect, pending)); + final Comparator> comp = new Comparator>() { + @Override + public int compare(final Map o1, + final Map o2) { + return signature(o1).compareTo(signature(o2)); + } + }; + Collections.sort(list, comp); + return list; + } + + /** + * Calculate ordered Cartesian product of sets. + */ + public static Set> product( + final Set> collect, + final Map> pending) { + + if (pending.isEmpty()) { + return collect; + } + + final Set> extract = new HashSet>(); + final String key = pending.keySet().iterator().next(); + for (final String value : pending.remove(key)) { + final Map map = new TreeMap(); + map.put(key, value); + extract.add(map); + } + + if (collect.isEmpty()) { + collect.addAll(extract); + return product(collect, pending); + } else { + final Set> inject = new HashSet>(); + for (final Map mapExtr : extract) { + for (final Map mapColl : collect) { + final Map mapProd = new TreeMap(); + mapProd.putAll(mapExtr); + mapProd.putAll(mapColl); + inject.add(mapProd); + } + } + return product(inject, pending); + } + } + + /** + * Publish result on http://microbenchmarks.appspot.com + */ + public static void publish(final Result result) throws Exception { + final Runner runner = new Runner(); + final Method method = runner.getClass().getDeclaredMethod( + "postResults", Result.class); + method.setAccessible(true); + method.invoke(runner, result); + } + + /** + * Provide new named run instance. + */ + public static Run newRun(final String benchmarkName) { + final Map measurements = new HashMap(); + final Date executedTimestamp = new Date(); + final Run run = new Run(measurements, benchmarkName, executedTimestamp); + return run; + } + + /** + * Make new result from run. + */ + public static Result newResult(final Run run) { + final Environment env = new EnvironmentGetter() + .getEnvironmentSnapshot(); + final Result result = new Result(run, env); + return result; + } + + /** + * Verify measure publication manually. + */ + public static void main(final String[] args) throws Exception { + final Run run = newRun("test-main"); + for (int param = 0; param < 5; param++) { + final CaliperMeasure measure = new CaliperMeasure(); + measure.variables().put("param", "" + param); + for (int step = 0; step < 5; step++) { + measure.rate().mark(50 + step); + final TimerContext time = measure.time().time(); + Thread.sleep(15); + time.stop(); + measure.size().value(50 + step); + measure.mark(); + } + measure.appendTo(run); + } + final Result result = newResult(run); + publish(result); + System.out.println(json(result)); + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/CustomReporter.java b/transport-udt/src/test/java/io/netty/transport/udt/util/CustomReporter.java new file mode 100644 index 000000000000..c8b7130b82a7 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/CustomReporter.java @@ -0,0 +1,250 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import java.io.PrintStream; +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.SortedMap; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; + +import com.yammer.metrics.Metrics; +import com.yammer.metrics.core.Clock; +import com.yammer.metrics.core.Counter; +import com.yammer.metrics.core.Gauge; +import com.yammer.metrics.core.Histogram; +import com.yammer.metrics.core.Metered; +import com.yammer.metrics.core.Metric; +import com.yammer.metrics.core.MetricName; +import com.yammer.metrics.core.MetricPredicate; +import com.yammer.metrics.core.MetricProcessor; +import com.yammer.metrics.core.MetricsRegistry; +import com.yammer.metrics.core.Timer; +import com.yammer.metrics.reporting.AbstractPollingReporter; +import com.yammer.metrics.stats.Snapshot; + +/** + * A simple reporters which prints out application metrics to a + * {@link PrintStream} periodically. + */ +public class CustomReporter extends AbstractPollingReporter implements + MetricProcessor { + private static final int CONSOLE_WIDTH = 80; + + /** + * Enables the console reporter for the default metrics registry, and causes + * it to print to STDOUT with the specified period. + */ + public static void enable(final long period, final TimeUnit unit) { + enable(Metrics.defaultRegistry(), period, unit); + } + + /** + * Enables the console reporter for the given metrics registry, and causes + * it to print to STDOUT with the specified period and unrestricted output. + */ + public static void enable(final MetricsRegistry metricsRegistry, + final long period, final TimeUnit unit) { + final CustomReporter reporter = new CustomReporter( + metricsRegistry, System.out, MetricPredicate.ALL); + reporter.start(period, unit); + } + + private final PrintStream out; + private final MetricPredicate predicate; + private final Clock clock; + private final TimeZone timeZone; + private final Locale locale; + + /** + * Creates a new {@link CustomReporter} for the default metrics + * registry, with unrestricted output. + */ + public CustomReporter(final PrintStream out) { + this(Metrics.defaultRegistry(), out, MetricPredicate.ALL); + } + + /** + * Creates a new {@link CustomReporter} for a given metrics registry. + */ + public CustomReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate) { + this(metricsRegistry, out, predicate, Clock.defaultClock(), TimeZone + .getDefault()); + } + + /** + * Creates a new {@link CustomReporter} for a given metrics registry. + */ + public CustomReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate, + final Clock clock, final TimeZone timeZone) { + this(metricsRegistry, out, predicate, clock, timeZone, Locale + .getDefault()); + } + + /** + * Creates a new {@link CustomReporter} for a given metrics registry. + */ + public CustomReporter(final MetricsRegistry metricsRegistry, + final PrintStream out, final MetricPredicate predicate, + final Clock clock, final TimeZone timeZone, final Locale locale) { + super(metricsRegistry, "console-reporter"); + this.out = out; + this.predicate = predicate; + this.clock = clock; + this.timeZone = timeZone; + this.locale = locale; + } + + @Override + public void run() { + try { + final DateFormat format = DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.MEDIUM, locale); + format.setTimeZone(timeZone); + final String dateTime = format.format(new Date(clock.time())); + out.print(dateTime); + out.print(' '); + for (int i = 0; i < (CONSOLE_WIDTH - dateTime.length() - 1); i++) { + out.print('='); + } + out.println(); + for (final Entry> entry : getMetricsRegistry() + .groupedMetrics(predicate).entrySet()) { + out.print(entry.getKey()); + out.println(':'); + for (final Entry subEntry : entry + .getValue().entrySet()) { + out.print(" "); + out.print(subEntry.getKey().getName()); + out.println(':'); + subEntry.getValue().processWith(this, subEntry.getKey(), + out); + out.println(); + } + out.println(); + } + out.println(); + out.flush(); + } catch (final Exception e) { + e.printStackTrace(out); + } + } + + @Override + public void processGauge(final MetricName name, final Gauge gauge, + final PrintStream stream) { + stream.printf(locale, " value = %s\n", gauge.value()); + } + + @Override + public void processCounter(final MetricName name, final Counter counter, + final PrintStream stream) { + stream.printf(locale, " count = %,d\n", counter.count()); + } + + @Override + public void processMeter(final MetricName name, final Metered meter, + final PrintStream stream) { + final String unit = abbrev(meter.rateUnit()); + stream.printf(locale, " count = %,d\n", meter.count()); + stream.printf(locale, " mean rate = %,2.2f %s/%s\n", + meter.meanRate(), meter.eventType(), unit); + stream.printf(locale, " 1-minute rate = %,2.2f %s/%s\n", + meter.oneMinuteRate(), meter.eventType(), unit); + stream.printf(locale, " 5-minute rate = %,2.2f %s/%s\n", + meter.fiveMinuteRate(), meter.eventType(), unit); + stream.printf(locale, " 15-minute rate = %,2.2f %s/%s\n", + meter.fifteenMinuteRate(), meter.eventType(), unit); + } + + @Override + public void processHistogram(final MetricName name, + final Histogram histogram, final PrintStream stream) { + final Snapshot snapshot = histogram.getSnapshot(); + stream.printf(locale, " min = %,2.2f\n", histogram.min()); + stream.printf(locale, " max = %,2.2f\n", histogram.max()); + stream.printf(locale, " mean = %,2.2f\n", histogram.mean()); + stream.printf(locale, " stddev = %,2.2f\n", + histogram.stdDev()); + stream.printf(locale, " median = %,2.2f\n", + snapshot.getMedian()); + stream.printf(locale, " 75%% <= %,2.2f\n", + snapshot.get75thPercentile()); + stream.printf(locale, " 95%% <= %,2.2f\n", + snapshot.get95thPercentile()); + stream.printf(locale, " 98%% <= %,2.2f\n", + snapshot.get98thPercentile()); + stream.printf(locale, " 99%% <= %,2.2f\n", + snapshot.get99thPercentile()); + stream.printf(locale, " 99.9%% <= %,2.2f\n", + snapshot.get999thPercentile()); + } + + @Override + public void processTimer(final MetricName name, final Timer timer, + final PrintStream stream) { + processMeter(name, timer, stream); + final String durationUnit = abbrev(timer.durationUnit()); + final Snapshot snapshot = timer.getSnapshot(); + stream.printf(locale, " min = %,2.2f %s\n", timer.min(), + durationUnit); + stream.printf(locale, " max = %,2.2f %s\n", timer.max(), + durationUnit); + stream.printf(locale, " mean = %,2.2f %s\n", timer.mean(), + durationUnit); + stream.printf(locale, " stddev = %,2.2f %s\n", + timer.stdDev(), durationUnit); + stream.printf(locale, " median = %,2.2f %s\n", + snapshot.getMedian(), durationUnit); + stream.printf(locale, " 75%% <= %,2.2f %s\n", + snapshot.get75thPercentile(), durationUnit); + stream.printf(locale, " 95%% <= %,2.2f %s\n", + snapshot.get95thPercentile(), durationUnit); + stream.printf(locale, " 98%% <= %,2.2f %s\n", + snapshot.get98thPercentile(), durationUnit); + stream.printf(locale, " 99%% <= %,2.2f %s\n", + snapshot.get99thPercentile(), durationUnit); + stream.printf(locale, " 99.9%% <= %,2.2f %s\n", + snapshot.get999thPercentile(), durationUnit); + } + + private String abbrev(final TimeUnit unit) { + switch (unit) { + case NANOSECONDS: + return "ns"; + case MICROSECONDS: + return "us"; + case MILLISECONDS: + return "ms"; + case SECONDS: + return "s"; + case MINUTES: + return "m"; + case HOURS: + return "h"; + case DAYS: + return "d"; + default: + throw new IllegalArgumentException("Unrecognized TimeUnit: " + unit); + } + } +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/EchoByteHandler.java b/transport-udt/src/test/java/io/netty/transport/udt/util/EchoByteHandler.java new file mode 100644 index 000000000000..4a389d565910 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/EchoByteHandler.java @@ -0,0 +1,110 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundByteHandlerAdapter; +import io.netty.channel.ChannelOption; +import io.netty.transport.udt.nio.NioUdtProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.core.Meter; + +/** + * Handler implementation for the echo client. It initiates the ping-pong + * traffic between the echo client and server by sending the first message to + * the server on activation. + */ +public class EchoByteHandler extends ChannelInboundByteHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(EchoByteHandler.class.getName()); + + private final ByteBuf message; + + private final Meter meter; + + public Meter meter() { + return meter; + } + + public EchoByteHandler(final Meter meter, final int messageSize) { + + this.meter = meter; + + message = Unpooled.buffer(messageSize); + + for (int i = 0; i < message.capacity(); i++) { + message.writeByte((byte) i); + } + + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + + ctx.write(message); + + ctx.flush(); + + } + + @Override + public void inboundBufferUpdated(final ChannelHandlerContext ctx, + final ByteBuf in) { + + if (meter != null) { + meter.mark(in.readableBytes()); + } + + final ByteBuf out = ctx.nextOutboundByteBuffer(); + + out.discardReadBytes(); // FIXME + + out.writeBytes(in); + + ctx.flush(); + + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable e) { + + log.error("exception : {}", e.getMessage()); + + ctx.close(); + + } + + @Override + public ByteBuf newInboundBuffer(final ChannelHandlerContext ctx) + throws Exception { + + return ctx.alloc().directBuffer( + ctx.channel().config().getOption(ChannelOption.SO_RCVBUF)); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/EchoMessageHandler.java b/transport-udt/src/test/java/io/netty/transport/udt/util/EchoMessageHandler.java new file mode 100644 index 000000000000..5bffc800e883 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/EchoMessageHandler.java @@ -0,0 +1,108 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.MessageBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundMessageHandlerAdapter; +import io.netty.transport.udt.UdtMessage; +import io.netty.transport.udt.nio.NioUdtProvider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.yammer.metrics.core.Meter; + +/** + * Handler implementation for the echo peer. It initiates the ping-pong traffic + * between the echo peers by sending the first message to the other peer on + * activation. + */ +public class EchoMessageHandler extends + ChannelInboundMessageHandlerAdapter { + + private static final Logger log = LoggerFactory + .getLogger(EchoMessageHandler.class.getName()); + + private final Meter meter; + private final UdtMessage message; + + public Meter meter() { + return meter; + } + + public EchoMessageHandler(final Meter meter, final int messageSize) { + + super(UdtMessage.class); + + this.meter = meter; + + final ByteBuf byteBuf = Unpooled.buffer(messageSize); + + for (int i = 0; i < byteBuf.capacity(); i++) { + byteBuf.writeByte((byte) i); + } + + this.message = new UdtMessage(byteBuf); + + } + + @Override + public void channelActive(final ChannelHandlerContext ctx) throws Exception { + + log.info("ECHO active {}", NioUdtProvider.socketUDT(ctx.channel()) + .toStringOptions()); + + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + + out.add(message); + + ctx.flush(); + + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, + final Throwable e) { + + log.error("exception : {}", e.getMessage()); + + ctx.close(); + + } + + @Override + protected void messageReceived(final ChannelHandlerContext ctx, + final UdtMessage message) throws Exception { + + final ByteBuf byteBuf = message.data(); + + if (meter != null) { + meter.mark(byteBuf.readableBytes()); + } + + final MessageBuf out = ctx.nextOutboundMessageBuffer(); + + out.add(message); + + ctx.flush(); + + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/TrafficControl.java b/transport-udt/src/test/java/io/netty/transport/udt/util/TrafficControl.java new file mode 100644 index 000000000000..5f73c8b8a470 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/TrafficControl.java @@ -0,0 +1,80 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Introduce traffic control, such as transfer latency. + *

+ * requires sudo setup for /sbin/tc under current account + *

+ * see http://www.davidverhasselt.com/2008/01/27/passwordless-sudo/ + */ +public final class TrafficControl { + + private static final Logger log = LoggerFactory + .getLogger(TrafficControl.class.getName()); + + private TrafficControl() { + } + + private static final String TC_DELAY = "sudo tc qdisc add dev %s root netem delay %sms limit %s"; + private static final String TC_RESET = "sudo tc qdisc del dev %s root"; + + /** + * verify if traffic control is available + */ + public static boolean isAvailable() { + try { + final int millis = 100; + final int margin = 20; + delay(0); + final long time1 = UnitHelp.ping("localhost"); + delay(millis); + final long time2 = UnitHelp.ping("localhost"); + delay(0); + final long time3 = UnitHelp.ping("localhost"); + return time2 >= time1 + millis - margin + && time2 >= time3 + millis - margin; + } catch (final Throwable e) { + log.debug("", e); + return false; + } + } + + /** + * Introduce round-trip delay on local host + * @param time - delay in milliseconds; use zero to remove delay. + */ + public static void delay(final int time) throws Exception { + if (time < 0) { + throw new IllegalArgumentException("negative latency"); + } + final int delay = time / 2; + if (delay == 0) { + UnitHelp.process(String.format(TC_RESET, "lo")); + } else { + /** extend packet buffer queue to avoid packet loss due to latency */ + final int limit = 1024 * 1024; + UnitHelp.process(String.format(TC_RESET, "lo")); + UnitHelp.process(String.format(TC_DELAY, "lo", delay, limit)); + } + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/UnitHelp.java b/transport-udt/src/test/java/io/netty/transport/udt/util/UnitHelp.java new file mode 100644 index 000000000000..b37345798679 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/UnitHelp.java @@ -0,0 +1,262 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import java.io.File; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.nio.IntBuffer; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.barchart.udt.SocketUDT; +import com.barchart.udt.StatusUDT; + +/** + * Unit test helper. + */ +public final class UnitHelp { + + private static final Logger log = LoggerFactory.getLogger(UnitHelp.class); + + /** + * Zero out buffer. + */ + public static void clear(final IntBuffer buffer) { + for (int index = 0; index < buffer.capacity(); index++) { + buffer.put(index, 0); + } + } + + /** + * Measure ping time to a host. + */ + public static long ping(final String host) throws Exception { + final String name = System.getProperty("os.name").toLowerCase(); + + final String command; + if (name.contains("linux")) { + command = "ping -c 1 " + host; + } else if (name.contains("mac os x")) { + command = "ping -c 1 " + host; + } else if (name.contains("windows")) { + command = "ping -n 1 " + host; + } else { + throw new Exception("unknown platform"); + } + + final long timeStart = System.currentTimeMillis(); + + process(command); + + final long timeFinish = System.currentTimeMillis(); + + final long timeDiff = timeFinish - timeStart; + + return timeDiff; + } + + /** + * Invoke external process and wait for completion. + */ + public static void process(final String command) throws Exception { + final ProcessBuilder builder = new ProcessBuilder(command.split("\\s+")); + final Process process = builder.start(); + process.waitFor(); + } + + /** + * @return newly allocated address or null for failure + */ + public static synchronized InetSocketAddress findLocalAddress( + final String host) { + ServerSocket socket = null; + try { + final InetAddress address = InetAddress.getByName(host); + socket = new ServerSocket(0, 3, address); + return (InetSocketAddress) socket.getLocalSocketAddress(); + } catch (final Exception e) { + log.error("Failed to find addess."); + return null; + } finally { + if (socket != null) { + try { + socket.close(); + } catch (final Exception e) { + log.error("Failed to close socket."); + } + } + } + } + + /** + * Find named address on local host. + */ + public static InetSocketAddress hostedSocketAddress(final String host) + throws Exception { + for (int k = 0; k < 10; k++) { + final InetSocketAddress address = findLocalAddress(host); + if (address == null) { + Thread.sleep(500); + continue; + } + return address; + } + throw new Exception("Failed to allocate address."); + } + + /** + * Allocate available local address / port or throw exception. + */ + public static InetSocketAddress localSocketAddress() throws Exception { + return hostedSocketAddress("localhost"); + } + + /** + * Display contents of a buffer. + */ + public static void logBuffer(final String title, final IntBuffer buffer) { + for (int index = 0; index < buffer.capacity(); index++) { + final int value = buffer.get(index); + if (value == 0) { + continue; + } + log.info(String.format("%s [id: 0x%08x]", title, value)); + } + } + + /** + * Display java.class.path + */ + public static void logClassPath() { + final String classPath = System.getProperty("java.class.path"); + final String[] entries = classPath.split(File.pathSeparator); + final StringBuilder text = new StringBuilder(1024); + for (final String item : entries) { + text.append("\n\t"); + text.append(item); + } + log.info("\n\t[java.class.path]{}", text); + } + + /** + * Display java.library.path + */ + public static void logLibraryPath() { + final String classPath = System.getProperty("java.library.path"); + final String[] entries = classPath.split(File.pathSeparator); + final StringBuilder text = new StringBuilder(1024); + for (final String item : entries) { + text.append("\n\t"); + text.append(item); + } + log.info("\n\t[java.library.path]{}", text); + } + + /** + * Display current OS/ARCH. + */ + public static void logOsArch() { + final StringBuilder text = new StringBuilder(1024); + text.append("\n\t"); + text.append(System.getProperty("os.name")); + text.append("\n\t"); + text.append(System.getProperty("os.arch")); + log.info("\n\t[os/arch]{}", text); + } + + /** + * Display contents of a set. + */ + public static void logSet(final Set set) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + final TreeSet treeSet = new TreeSet(set); + for (final Object item : treeSet) { + log.info("-> {}", item); + } + } + + public static String property(final String name) { + final String value = System.getProperty(name); + if (value == null) { + log.error("property '{}' not defined; terminating", name); + System.exit(1); + } + return value; + } + + public static int[] randomIntArray(final int length, final int range) { + final int[] array = new int[length]; + final Random generator = new Random(0); + for (int i = 0; i < array.length; i++) { + array[i] = generator.nextInt(range); + } + return array; + } + + public static String randomString() { + return "" + System.currentTimeMillis(); + } + + public static String randomSuffix(final String name) { + return name + "-" + System.currentTimeMillis(); + } + + /** + * Block till socket reaches given state. + */ + public static void socketAwait(final SocketUDT socket, + final StatusUDT... statusArray) throws Exception { + while (true) { + for (final StatusUDT status : statusArray) { + if (socket.status() == status) { + return; + } else { + Thread.sleep(50); + } + } + } + } + + public static Set socketIndexSet(final IntBuffer buffer) { + final Set set = new HashSet(); + while (buffer.hasRemaining()) { + set.add(buffer.get()); + } + return set; + } + + public static boolean socketPresent(final SocketUDT socket, + final IntBuffer buffer) { + for (int index = 0; index < buffer.capacity(); index++) { + if (buffer.get(index) == socket.id()) { + return true; + } + } + return false; + } + + private UnitHelp() { + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/UtilThreadFactory.java b/transport-udt/src/test/java/io/netty/transport/udt/util/UtilThreadFactory.java new file mode 100644 index 000000000000..87f05fb7d50d --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/UtilThreadFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.transport.udt.util; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Thread factory for tests. + */ +public class UtilThreadFactory implements ThreadFactory { + + private static final AtomicInteger counter = new AtomicInteger(); + + private final String name; + + public UtilThreadFactory(final String name) { + this.name = name; + } + + @Override + public Thread newThread(final Runnable runnable) { + return new Thread(runnable, name + "-" + counter.getAndIncrement()); + } + +} diff --git a/transport-udt/src/test/java/io/netty/transport/udt/util/package-info.java b/transport-udt/src/test/java/io/netty/transport/udt/util/package-info.java new file mode 100644 index 000000000000..d837ae7b9854 --- /dev/null +++ b/transport-udt/src/test/java/io/netty/transport/udt/util/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you 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. + */ + +/** + * UDT Benchmarks and Tests Utilities + */ +package io.netty.transport.udt.util; + diff --git a/transport-udt/src/test/resources/logback-test.xml b/transport-udt/src/test/resources/logback-test.xml new file mode 100644 index 000000000000..818714d9772e --- /dev/null +++ b/transport-udt/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %date{ss.SSS} [%5.5thread] %-5level %16.16class{16} %-16.16method{16} %3.3line - %message%n + + + + + + + + + +