All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.opentsdb.tsd.PipelineFactory Maven / Gradle / Ivy

Go to download

OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top of HBase. OpenTSDB was written to address a common need: store, index and serve metrics collected from computer systems (network gear, operating systems, applications) at a large scale, and make this data easily accessible and graphable.

There is a newer version: 2.4.1
Show newest version
// This file is part of OpenTSDB.
// Copyright (C) 2010-2012  The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version.  This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
// General Public License for more details.  You should have received a copy
// of the GNU Lesser General Public License along with this program.  If not,
// see .
package net.opentsdb.tsd;

import static org.jboss.netty.channel.Channels.pipeline;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpContentDecompressor;
import org.jboss.netty.handler.codec.http.HttpContentCompressor;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.Timer;

import net.opentsdb.core.TSDB;

/**
 * Creates a newly configured {@link ChannelPipeline} for a new channel.
 * This class is supposed to be a singleton.
 * NOTE: On creation (as of 2.3) the property given in the config for 
 * "tsd.core.connections.limit" will be used to limit the number of concurrent
 * connections supported by the pipeline. The default is zero.
 */
public final class PipelineFactory implements ChannelPipelineFactory {

  // Those are entirely stateless and thus a single instance is needed.
  private static final StringEncoder ENCODER = new StringEncoder();
  private static final WordSplitter DECODER = new WordSplitter();

  // Those are sharable but maintain some state, so a single instance per
  // PipelineFactory is needed.
  private final ConnectionManager connmgr;
  private final DetectHttpOrRpc HTTP_OR_RPC = new DetectHttpOrRpc();
  private final Timer timer;
  private final ChannelHandler timeoutHandler;

  /** Stateless handler for RPCs. */
  private final RpcHandler rpchandler;
  
  /** The TSDB to which we belong */ 
  private final TSDB tsdb;
  
  /** The server side socket timeout. **/
  private final int socketTimeout;
  
  /**
   * Constructor that initializes the RPC router and loads HTTP formatter 
   * plugins. This constructor creates its own {@link RpcManager}.
   * @param tsdb The TSDB to use.
   * @throws RuntimeException if there is an issue loading plugins
   * @throws Exception if the HttpQuery handler is unable to load 
   * serializers
   */
  public PipelineFactory(final TSDB tsdb) {
    this(tsdb, RpcManager.instance(tsdb), 
        tsdb.getConfig().getInt("tsd.core.connections.limit"));
  }

  /**
   * Constructor that initializes the RPC router and loads HTTP formatter 
   * plugins using an already-configured {@link RpcManager}.
   * @param tsdb The TSDB to use.
   * @param manager instance of a ready-to-use {@link RpcManager}.
   * @throws RuntimeException if there is an issue loading plugins
   * @throws Exception if the HttpQuery handler is unable to load serializers
   */
  public PipelineFactory(final TSDB tsdb, final RpcManager manager) {
    this(tsdb, RpcManager.instance(tsdb), 
        tsdb.getConfig().getInt("tsd.core.connections.limit"));
  }
  
  /**
   * Constructor that initializes the RPC router and loads HTTP formatter 
   * plugins using an already-configured {@link RpcManager}.
   * @param tsdb The TSDB to use.
   * @param manager instance of a ready-to-use {@link RpcManager}.
   * @param connections_limit The maximum number of concurrent connections 
   * supported by the TSD.
   * @throws RuntimeException if there is an issue loading plugins
   * @throws Exception if the HttpQuery handler is unable to load serializers
   * @since 2.3
   */
  public PipelineFactory(final TSDB tsdb, final RpcManager manager, 
      final int connections_limit) {
    this.tsdb = tsdb;
    socketTimeout = tsdb.getConfig().getInt("tsd.core.socket.timeout");
    timer = tsdb.getTimer();
    timeoutHandler = new IdleStateHandler(timer, 0, 0, socketTimeout);
    rpchandler = new RpcHandler(tsdb, manager);
    connmgr = new ConnectionManager(connections_limit);
    try {
      HttpQuery.initializeSerializerMaps(tsdb);
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      throw new RuntimeException("Failed to initialize formatter plugins", e);
    }
  }

  @Override
  public ChannelPipeline getPipeline() throws Exception {
   final ChannelPipeline pipeline = pipeline();

    pipeline.addLast("connmgr", connmgr);
    pipeline.addLast("detect", HTTP_OR_RPC);
    return pipeline;
  }

  /**
   * Dynamically changes the {@link ChannelPipeline} based on the request.
   * If a request uses HTTP, then this changes the pipeline to process HTTP.
   * Otherwise, the pipeline is changed to processes an RPC.
   */
  final class DetectHttpOrRpc extends FrameDecoder {

    @Override
    protected Object decode(final ChannelHandlerContext ctx,
                            final Channel chan,
                            final ChannelBuffer buffer) throws Exception {
      if (buffer.readableBytes() < 1) {  // Yes sometimes we can be called
        return null;                     // with an empty buffer...
      }

      final int firstbyte = buffer.getUnsignedByte(buffer.readerIndex());
      final ChannelPipeline pipeline = ctx.getPipeline();
      // None of the commands in the RPC protocol start with a capital ASCII
      // letter for the time being, and all HTTP commands do (GET, POST, etc.)
      // so use this as a cheap way to differentiate the two.
      if ('A' <= firstbyte && firstbyte <= 'Z') {
        pipeline.addLast("decoder", new HttpRequestDecoder());
        if (tsdb.getConfig().enable_chunked_requests()) {
          pipeline.addLast("aggregator", new HttpChunkAggregator(
              tsdb.getConfig().max_chunked_requests()));
        }
        // allow client to encode the payload (ie : with gziped json)
        pipeline.addLast("inflater", new HttpContentDecompressor());
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("deflater", new HttpContentCompressor());
      } else {
        pipeline.addLast("framer", new LineBasedFrameDecoder(1024));
        pipeline.addLast("encoder", ENCODER);
        pipeline.addLast("decoder", DECODER);
      }

      pipeline.addLast("timeout", timeoutHandler);
      pipeline.remove(this);
      pipeline.addLast("handler", rpchandler);

      // Forward the buffer to the next handler.
      return buffer.readBytes(buffer.readableBytes());
    }

  }
  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy