package io.scalecube.socketio;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
import java.util.concurrent.ThreadFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.internal.SystemPropertyUtil;
/**
* @author Anton Kharenko
*/
final class DefaultServerBootstrapFactory implements ServerBootstrapFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultServerBootstrapFactory.class);
private static final int BOSS_THREAD_NUM = 2;
private static final int IO_THREAD_NUM = 0; // Netty default
private static boolean envSupportEpoll;
static {
String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
if (!name.contains("linux")) {
envSupportEpoll = false;
LOGGER.warn("Env doesn't support epoll transport");
} else {
try {
Class.forName("io.netty.channel.epoll.Native");
envSupportEpoll = true;
LOGGER.info("Use epoll transport");
} catch (Throwable t) {
LOGGER.warn("Tried to use epoll transport, but it's not supported by host OS (or no corresponding libs included) "
+ "using NIO instead, cause: ", t);
envSupportEpoll = false;
}
}
}
private final boolean epollEnabled;
public DefaultServerBootstrapFactory(ServerConfiguration config) {
this.epollEnabled = config.isEpollEnabled();
}
@Override
public ServerBootstrap createServerBootstrap() {
EventLoopGroup bossGroup = createEventLoopGroup(BOSS_THREAD_NUM, "socketio-boss");
EventLoopGroup workerGroup = createEventLoopGroup(IO_THREAD_NUM, "socketio-io");
return new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(serverChannelClass())
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
}
/**
* @return {@link EpollEventLoopGroup} or {@link NioEventLoopGroup} object dep on {@link #isEpollSupported()} call.
*/
private EventLoopGroup createEventLoopGroup(int threadNum, String poolName) {
ThreadFactory threadFactory = new DefaultThreadFactory(poolName, true);
return isEpollSupported()
? new EpollEventLoopGroup(threadNum, threadFactory)
: new NioEventLoopGroup(threadNum, threadFactory);
}
private Class<? extends ServerSocketChannel> serverChannelClass() {
return isEpollSupported() ? EpollServerSocketChannel.class : NioServerSocketChannel.class;
}
private boolean isEpollSupported() {
return epollEnabled && envSupportEpoll;
}
}