Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima

* Prevented XML External Entity (XXE) style attacks via `GraphMLReader` by disabling DTD and external entities by default.
* Fixed a `NullPointerException` that could occur during a failed `Connection` initialization due to uninstantiated `AtomicInteger`.
* Added a check for when Epoll is available in the Java client and if so use it instead of Nio.

[[release-3-4-12]]
=== TinkerPop 3.4.12 (Release Date: July 19, 2021)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
Expand Down Expand Up @@ -1103,11 +1106,14 @@ public Cluster create() {
}

static class Factory {
private final NioEventLoopGroup group;
private final EventLoopGroup group;

public Factory(final int nioPoolSize) {
final BasicThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern("gremlin-driver-loop-%d").build();
group = new NioEventLoopGroup(nioPoolSize, threadFactory);
// Checks and uses Epoll if it is available. ref: http://netty.io/wiki/native-transports.html
System.out.println(Epoll.isAvailable() ? "epoll is available, using epoll" : "epoll is unavailable, using NIO.");
logger.warn(Epoll.isAvailable() ? "epoll is available, using epoll" : "epoll is unavailable, using NIO.");
group = Epoll.isAvailable() ? new EpollEventLoopGroup(nioPoolSize, threadFactory) : new NioEventLoopGroup(nioPoolSize, threadFactory);
}

Bootstrap createBootstrap() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -38,10 +42,14 @@
public abstract class AbstractClient implements SimpleClient {
protected final CallbackResponseHandler callbackResponseHandler = new CallbackResponseHandler();
protected final EventLoopGroup group;
protected static final Logger logger = LoggerFactory.getLogger(AbstractClient.class);

public AbstractClient(final String threadPattern) {
final BasicThreadFactory threadFactory = new BasicThreadFactory.Builder().namingPattern(threadPattern).build();
group = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), threadFactory);
// Checks and uses Epoll if it is available. ref: http://netty.io/wiki/native-transports.html
logger.warn(Epoll.isAvailable() ? "epoll is available, using epoll" : "epoll is unavailable, using NIO.");
group = Epoll.isAvailable() ? new EpollEventLoopGroup(Runtime.getRuntime().availableProcessors(), threadFactory)
: new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), threadFactory);
}

public abstract void writeAndFlush(final RequestMessage requestMessage) throws Exception;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelOption;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.handler.codec.http.EmptyHttpHeaders;
import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
import org.apache.tinkerpop.gremlin.driver.handler.WebSocketClientHandler;
Expand Down Expand Up @@ -66,7 +68,9 @@ public WebSocketClient(final URI uri) {
final WebSocketClientHandler wsHandler = new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, true, EmptyHttpHeaders.INSTANCE, 65536), 10000);
final MessageSerializer serializer = new GryoMessageSerializerV3d0();
b.channel(NioSocketChannel.class)
// Checks and uses Epoll if it is available. ref: http://netty.io/wiki/native-transports.html
logger.info(Epoll.isAvailable() ? "epoll is available, using epoll" : "epoll is unavailable, using NIO.");
b.channel(Epoll.isAvailable() ? EpollSocketChannel.class : NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(final SocketChannel ch) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
Expand All @@ -37,11 +40,12 @@ public class SimpleSocketServer {
private EventLoopGroup workerGroup;

public Channel start(final ChannelInitializer<SocketChannel> channelInitializer) throws InterruptedException {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
// Checks and uses Epoll if it is available. ref: http://netty.io/wiki/native-transports.html
bossGroup = Epoll.isAvailable() ? new EpollEventLoopGroup(1) : new NioEventLoopGroup(1);
workerGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();
final ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(channelInitializer);
return b.bind(PORT).sync().channel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
*/
package org.apache.tinkerpop.gremlin.driver;

import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
Expand All @@ -41,6 +46,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class WebSocketClientBehaviorIntegrateTest {
@Rule
Expand Down Expand Up @@ -271,4 +277,22 @@ public void shouldNotCreateReplacementConnectionWhenClientClosesConnection() thr
.filter(str -> str.contains("Considering new connection on"))
.count());
}
}

// A mock client is made here, so we can test the protected field group
private static class MockClient extends WebSocketClient {
EventLoopGroup getEventLoopGroup() {
return group;
}
}

@Test
public void shouldUseEpollIfAvailable() throws Exception {
final MockClient client = new MockClient();
if (Epoll.isAvailable()) {
assertTrue(client.getEventLoopGroup() instanceof EpollEventLoopGroup);
} else {
assertTrue(client.getEventLoopGroup() instanceof NioEventLoopGroup);
}
}

}