package com.outbrain.gruffalo.netty; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.outbrain.swinfra.metrics.api.MetricFactory; import io.netty.channel.ChannelHandler; import io.netty.channel.EventLoopGroup; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * Time: 8/4/13 2:20 PM * * @author Eran Harel */ class GraphiteClientPool implements GraphiteClient { private static final Logger logger = LoggerFactory.getLogger(GraphiteClientPool.class); private final GraphiteClient[] pool; private final AtomicInteger nextIndex = new AtomicInteger(); public GraphiteClientPool(final EventLoopGroup eventLoopGroup, final StringDecoder decoder, final StringEncoder encoder, final Throttler throttler, final int inFlightBatchesHighThreshold, final MetricFactory metricFactory, final String graphiteRelayHosts) { Preconditions.checkNotNull(graphiteRelayHosts); Preconditions.checkNotNull(decoder, "decoder must not be null"); Preconditions.checkNotNull(encoder, "encoder must not be null"); Preconditions.checkNotNull(eventLoopGroup, "eventLoopGroup must not be null"); logger.info("Creating a client pool for [{}]", graphiteRelayHosts); final String[] hosts = graphiteRelayHosts.trim().split(","); pool = new GraphiteClient[hosts.length]; initClients(hosts, eventLoopGroup, decoder, encoder, throttler, inFlightBatchesHighThreshold, metricFactory); } private void initClients(final String[] hosts, final EventLoopGroup eventLoopGroup, final StringDecoder decoder, final StringEncoder encoder, final Throttler throttler, final int inFlightBatchesHighThreshold, final MetricFactory metricFactory) { for (int i = 0; i < hosts.length; i++) { final String[] hostAndPort = hosts[i].split(":"); final String host = hostAndPort[0]; final int port = Integer.parseInt(hostAndPort[1]); final NettyGraphiteClient client = new NettyGraphiteClient(throttler, inFlightBatchesHighThreshold, metricFactory, hosts[i]); pool[i] = client; final ChannelHandler graphiteChannelHandler = new GraphiteChannelInboundHandler(client, hosts[i], throttler); final GraphiteClientChannelInitializer channelInitializer = new GraphiteClientChannelInitializer(host, port, eventLoopGroup, decoder, encoder, graphiteChannelHandler); client.setChannelInitializer(channelInitializer); } } @Override public void connect() { for (final GraphiteClient client : pool) { client.connect(); } } @Override public boolean publishMetrics(final String metrics) { final int currIndex = nextIndex.getAndIncrement(); for(int i = 0; i < pool.length; i++) { final int currClientIndex = (i + currIndex) % pool.length; if (pool[currClientIndex].publishMetrics(metrics)) { return true; } } return false; } @Override public void onPushBack() { // meh // in the future we may implement some weighted round robin using this input // currently this is only used by the children to add metrics } }