org.lilyproject.testclientfw.BaseTestTool.java Source code

Java tutorial

Introduction

Here is the source code for org.lilyproject.testclientfw.BaseTestTool.java

Source

/*
 * Copyright 2012 NGDATA nv
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.lilyproject.testclientfw;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.joda.time.DateTime;
import org.lilyproject.cli.BaseZkCliTool;
import org.lilyproject.cli.OptionUtil;
import org.lilyproject.clientmetrics.HBaseMetrics;
import org.lilyproject.clientmetrics.HBaseMetricsPlugin;
import org.lilyproject.clientmetrics.LilyMetrics;
import org.lilyproject.clientmetrics.ListMetricsPlugin;
import org.lilyproject.clientmetrics.Metrics;
import org.lilyproject.util.concurrent.WaitPolicy;
import org.lilyproject.util.io.Closer;
import org.lilyproject.util.zookeeper.StateWatchingZooKeeper;
import org.lilyproject.util.zookeeper.ZooKeeperItf;

public abstract class BaseTestTool extends BaseZkCliTool {
    private Option workersOption;

    private Option verboseOption;

    private Option hbaseMetricsOption;

    private Option lilyMetricsOption;

    protected int workers;

    protected boolean verbose;

    protected boolean useHbaseMetrics;

    protected boolean useLilyMetrics;

    protected HBaseMetrics hbaseMetrics;

    private LilyMetrics lilyMetrics;

    protected PrintStream metricsStream;

    protected ThreadPoolExecutor executor;

    protected Metrics metrics;

    private ZooKeeperItf zk;

    private Configuration hbaseConf;

    protected int getDefaultWorkers() {
        return 2;
    }

    @Override
    @SuppressWarnings("static-access")
    public List<Option> getOptions() {
        List<Option> options = super.getOptions();

        workersOption = OptionBuilder.withArgName("count").hasArg().withDescription("Number of workers (threads)")
                .withLongOpt("workers").create("w");
        options.add(workersOption);

        verboseOption = OptionBuilder.withDescription("Be verbose").withLongOpt("verbose").create("vb");
        options.add(verboseOption);

        hbaseMetricsOption = OptionBuilder
                .withDescription("Enable HBase metrics options (requires JMX on default port 10102)")
                .withLongOpt("hbase-metrics").create("hm");
        options.add(hbaseMetricsOption);

        lilyMetricsOption = OptionBuilder
                .withDescription("Enable Lily metrics options (requires JMX on default port 10202)")
                .withLongOpt("lily-metrics").create("lm");
        options.add(lilyMetricsOption);

        return options;
    }

    @Override
    protected int processOptions(CommandLine cmd) throws Exception {
        int result = super.processOptions(cmd);
        if (result != 0) {
            return result;
        }

        workers = OptionUtil.getIntOption(cmd, workersOption, getDefaultWorkers());

        if (cmd.hasOption(verboseOption.getOpt())) {
            verbose = true;
        }

        if (cmd.hasOption(hbaseMetricsOption.getOpt())) {
            useHbaseMetrics = true;
        }

        if (cmd.hasOption(lilyMetricsOption.getOpt())) {
            useLilyMetrics = true;
        }

        return 0;
    }

    @Override
    protected void cleanup() {
        Closer.close(zk);

        // Close any HBase connections used for the metrics
        HConnectionManager.deleteAllConnections(true);
        super.cleanup();
    }

    public void setupMetrics() throws Exception {
        String metricsFileName = getClass().getSimpleName() + "-metrics";

        System.out.println();
        System.out.println("Setting up metrics to file " + metricsFileName);

        File metricsFile = Util.getOutputFileRollOldOne(metricsFileName);

        HBaseAdmin hbaseAdmin = new HBaseAdmin(getHBaseConf());

        hbaseMetrics = new HBaseMetrics(hbaseAdmin);
        lilyMetrics = new LilyMetrics(getZooKeeper());

        ListMetricsPlugin plugins = new ListMetricsPlugin();
        HBaseMetricsPlugin metricsPlugin = new HBaseMetricsPlugin(hbaseMetrics, hbaseAdmin, useHbaseMetrics);
        plugins.add(metricsPlugin);
        addMetricsPlugins(plugins);

        metricsStream = new PrintStream(new FileOutputStream(metricsFile));
        metrics = new Metrics(metricsStream, plugins);
        metrics.setThreadCount(workers);

        metrics.startHeader();

        metricsStream.println("Now: " + new DateTime());
        metricsStream.println("Number of threads used: " + workers);
        metricsStream
                .println("More threads might increase number of ops/sec, but typically also increases time spent");
        metricsStream.println("in each individual operation.");
        metricsStream.println();
        metricsStream.println("About the ops/sec (if present):");
        metricsStream.println("  - interval ops/sec = number of ops by the complete time of the interval");
        metricsStream.println("  - real ops/sec = number of ops by the time they took");
        metricsStream.println("The interval ops/sec looks at how many of the operations have been done in");
        metricsStream.println("the interval, but includes thus the time spent doing other kinds of operations");
        metricsStream.println("or the overhead of the test tool itself. Therefore, you would expect the");
        metricsStream.println("real ops/sec to be better (higher) than the interval ops/sec. But when using");
        metricsStream.println("multiple threads, this is not always the case, since each thread runs for the");
        metricsStream.println("duration of the interval, e.g. 3 threads running for 30s makes 90s time passed");
        metricsStream.println("by the threads together. Another issue is that sometimes operations are very");
        metricsStream.println("quick but that their time is measured with a too low granularity.");
        metricsStream.println();
        metricsStream.println("About hbaseLoad (if present): this is currently the same as the number of regions");
        metricsStream.println("   deployed on the region server.");
        metricsStream.println("About hbaseRequestCount (if present): this is number of HBase requests per seconds");
        metricsStream.println();

        outputGeneralMetricReports();

        metrics.endHeader();

        System.out.println(
                "Metrics ready, summary will be outputted every " + (metrics.getIntervalDuration() / 1000) + "s");
        System.out.println("Follow them using tail -f " + metricsFileName);
        System.out.println();
    }

    protected void addMetricsPlugins(ListMetricsPlugin plugins) {

    }

    public void finishMetrics() throws Exception {
        metrics.finish();

        metrics.startFooter();
        outputGeneralMetricReports();
        metrics.endFooter();

        hbaseMetrics.close();
        lilyMetrics.close();
    }

    private void outputGeneralMetricReports() throws Exception {
        hbaseMetrics.outputHBaseState(metricsStream);
        hbaseMetrics.outputRegionCountByServer(metricsStream);

        if (useHbaseMetrics) {
            hbaseMetrics.outputRegionServersInfo(metricsStream);
        }

        if (useLilyMetrics) {
            lilyMetrics.outputLilyServerInfo(metricsStream);
        }
    }

    public void startExecutor() {
        executor = new ThreadPoolExecutor(workers, workers, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(100));
        executor.setRejectedExecutionHandler(new WaitPolicy());
    }

    public void stopExecutor() throws InterruptedException {
        executor.shutdown();
        // There might be quite some jobs waiting in the queue, and we don't care how long they take to run
        // to an end
        boolean successfulFinish = executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        if (!successfulFinish) {
            System.out.println("Executor did not end successfully");
        }
        executor = null;
    }

    public Configuration getHBaseConf() {
        if (hbaseConf == null) {
            hbaseConf = HBaseConfiguration.create();

            // TODO
            if (zkConnectionString.contains(":")) {
                System.err.println(
                        "ATTENTION: do not include port numbers in zookeeper connection string when using features/tests that use HBase.");
            }

            hbaseConf.set("hbase.zookeeper.quorum", zkConnectionString);
        }
        return hbaseConf;
    }

    protected ZooKeeperItf getZooKeeper() throws IOException {
        if (zk == null) {
            zk = new StateWatchingZooKeeper(zkConnectionString, zkSessionTimeout);
        }
        return zk;
    }
}