// threads attempt to create the same client at the same time, and they
// could both test the map at the same time and create 2 instances.
final String hostport = host + ':' + port;
RegionClient client;
SocketChannel chan = null;
synchronized (ip2client) {
client = ip2client.get(hostport);
if (client != null && client.isAlive()) {
return client;
}
// We don't use Netty's ClientBootstrap class because it makes it
// unnecessarily complicated to have control over which ChannelPipeline
// exactly will be given to the channel. It's over-designed.
final RegionClientPipeline pipeline = new RegionClientPipeline();
client = pipeline.init();
chan = channel_factory.newChannel(pipeline);
ip2client.put(hostport, client); // This is guaranteed to return null.
}
client2regions.put(client, new ArrayList<RegionInfo>());
num_connections_created.increment();
// Configure and connect the channel without locking ip2client.
final SocketChannelConfig config = chan.getConfig();
config.setConnectTimeoutMillis(5000);
config.setTcpNoDelay(true);
// Unfortunately there is no way to override the keep-alive timeout in
// Java since the JRE doesn't expose any way to call setsockopt() with
// TCP_KEEPIDLE. And of course the default timeout is >2h. Sigh.
config.setKeepAlive(true);
chan.connect(new InetSocketAddress(host, port)); // Won't block.
return client;
}