Add support for using epoll Netty transport
[ovsdb.git] / library / impl / src / main / java / org / opendaylight / ovsdb / lib / impl / NettyBootstrapFactory.java
1 /*
2  * Copyright © 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.ovsdb.lib.impl;
9
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import io.netty.bootstrap.Bootstrap;
12 import io.netty.bootstrap.ServerBootstrap;
13 import io.netty.channel.AdaptiveRecvByteBufAllocator;
14 import io.netty.channel.ChannelOption;
15 import io.netty.channel.EventLoopGroup;
16 import io.netty.channel.epoll.Epoll;
17 import io.netty.channel.epoll.EpollEventLoopGroup;
18 import io.netty.channel.epoll.EpollServerSocketChannel;
19 import io.netty.channel.epoll.EpollSocketChannel;
20 import io.netty.channel.nio.NioEventLoopGroup;
21 import io.netty.channel.socket.nio.NioServerSocketChannel;
22 import io.netty.channel.socket.nio.NioSocketChannel;
23 import java.util.concurrent.ThreadFactory;
24 import javax.annotation.PreDestroy;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * A globally-instantiated context for use with OvsdbConnectionService.
32  */
33 @Singleton
34 public class NettyBootstrapFactory implements AutoCloseable {
35     private abstract static class Provider {
36         /**
37          * Return user friendly name, suitable for system operators.
38          *
39          * @return An admin-friendly name.
40          */
41         abstract String name();
42
43         abstract EventLoopGroup createGroup(ThreadFactory threadFactory);
44
45         abstract Bootstrap createBootstrap();
46
47         abstract ServerBootstrap createServerBootstrap();
48     }
49
50     private static final class EpollProvider extends Provider {
51         @Override
52         String name() {
53             return "epoll(7)";
54         }
55
56         @Override
57         EventLoopGroup createGroup(final ThreadFactory threadFactory) {
58             return new EpollEventLoopGroup(0, threadFactory);
59         }
60
61         @Override
62         Bootstrap createBootstrap() {
63             return new Bootstrap()
64                     .channel(EpollSocketChannel.class);
65         }
66
67         @Override
68         ServerBootstrap createServerBootstrap() {
69             return new ServerBootstrap()
70                     .channel(EpollServerSocketChannel.class);
71         }
72     }
73
74     private static final class NioProvider extends Provider {
75         @Override
76         String name() {
77             return "java.nio";
78         }
79
80         @Override
81         EventLoopGroup createGroup(final ThreadFactory threadFactory) {
82             return new NioEventLoopGroup(0, threadFactory);
83         }
84
85         @Override
86         Bootstrap createBootstrap() {
87             return new Bootstrap()
88                     .channel(NioSocketChannel.class);
89         }
90
91         @Override
92         ServerBootstrap createServerBootstrap() {
93             return new ServerBootstrap()
94                     .channel(NioServerSocketChannel.class);
95         }
96     }
97
98     private static final Logger LOG = LoggerFactory.getLogger(NettyBootstrapFactory.class);
99
100     // Minimum footprint runtime-constant
101     private static final Provider PROVIDER = Epoll.isAvailable() ? new EpollProvider() : new NioProvider();
102
103     private final EventLoopGroup bossGroup;
104     private final EventLoopGroup workerGroup;
105
106     @Inject
107     public NettyBootstrapFactory() {
108         bossGroup = PROVIDER.createGroup(new ThreadFactoryBuilder().setNameFormat("OVSDB listener-%d").build());
109         workerGroup = PROVIDER.createGroup(new ThreadFactoryBuilder().setNameFormat("OVSDB connection-%d").build());
110         LOG.info("OVSDB global Netty context started with {}", PROVIDER.name());
111     }
112
113     Bootstrap newClient() {
114         return PROVIDER.createBootstrap()
115                 .group(workerGroup)
116                 .option(ChannelOption.TCP_NODELAY, true)
117                 .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(65535, 65535, 65535));
118     }
119
120     ServerBootstrap newServer() {
121         return PROVIDER.createServerBootstrap()
122                 .group(bossGroup, workerGroup)
123                 .option(ChannelOption.TCP_NODELAY, true)
124                 .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(65535, 65535, 65535))
125                 .option(ChannelOption.SO_BACKLOG, 100);
126     }
127
128     @PreDestroy
129     @Override
130     public void close() {
131         LOG.info("OVSDB global Netty context terminating");
132         bossGroup.shutdownGracefully().addListener(ignore -> {
133             LOG.info("OVSDB global server group terminated");
134         });
135         workerGroup.shutdownGracefully().addListener(ignore -> {
136             LOG.info("OVSDB global channel group terminated");
137         });
138     }
139 }