org.apache.blur.shell.DiscoverFileBufferSizeUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.blur.shell.DiscoverFileBufferSizeUtil.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.blur.shell;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;

import org.apache.blur.thirdparty.thrift_0_9_0.TException;
import org.apache.blur.thrift.generated.Blur.Iface;
import org.apache.blur.thrift.generated.BlurException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class DiscoverFileBufferSizeUtil extends Command {

    @Override
    public void doit(PrintWriter out, Iface client, String[] args)
            throws CommandException, TException, BlurException {
        CommandLine cmd = parse(args, out);
        if (cmd == null) {
            throw new CommandException(name() + " missing required arguments");
        }
        Option[] options = cmd.getOptions();
        for (Option option : options) {
            out.println(option);
            String opt = option.getOpt();
            String value = option.getValue();
            System.out.println(opt + " " + value);

        }

        Path path = new Path(cmd.getOptionValue("p"));
        long size = Long.parseLong(cmd.getOptionValue("s", "1000000000"));// 1GB
        int sampleSize = Integer.parseInt(cmd.getOptionValue("S", "10"));// 10
        int warmupSize = Integer.parseInt(cmd.getOptionValue("W", "3"));// 3
        int min = Integer.parseInt(cmd.getOptionValue("n", "12"));// 12
        int max = Integer.parseInt(cmd.getOptionValue("x", "19"));// 19
        int readSamplesPerPass = Integer.parseInt(cmd.getOptionValue("r", "1000"));// 1000

        Configuration configuration = new Configuration();
        FileSystem fileSystem;
        try {
            fileSystem = path.getFileSystem(configuration);
        } catch (IOException e) {
            if (Main.debug) {
                e.printStackTrace();
            }
            throw new CommandException(e.getMessage());
        }
        Random random = new Random();
        Map<Integer, Long> writingResults;
        try {
            writingResults = runWritingTest(out, path, fileSystem, random, sampleSize, warmupSize, size, min, max);
        } catch (IOException e) {
            if (Main.debug) {
                e.printStackTrace();
            }
            throw new CommandException(e.getMessage());
        }
        Map<Integer, Long> readingResults;
        try {
            readingResults = runReadingTest(out, path, fileSystem, random, sampleSize, warmupSize, size, min, max,
                    readSamplesPerPass);
        } catch (IOException e) {
            if (Main.debug) {
                e.printStackTrace();
            }
            throw new CommandException(e.getMessage());
        }

        out.println("Printing Results for Writing");
        printResults(out, writingResults);

        out.println("Printing Results for Reading");
        printResults(out, readingResults);
    }

    @SuppressWarnings("static-access")
    public CommandLine parse(String[] otherArgs, Writer out) {
        Options options = new Options();
        options.addOption(OptionBuilder.withDescription("The path to write temp files.").hasArg().isRequired(true)
                .create("p"));
        options.addOption(OptionBuilder.withDescription("The size of the temp files (1 GB by default).").hasArg()
                .create("s"));
        options.addOption(OptionBuilder.withDescription("Number of cycles of the test. (10 by default)").hasArg()
                .create("S"));
        options.addOption(
                OptionBuilder.withDescription("Number of warmup cycles. (3 by default)").hasArg().create("W"));
        options.addOption(OptionBuilder.withDescription("Min buffer size power of 2 (12 by default 4KB)").hasArg()
                .create("n"));
        options.addOption(OptionBuilder.withDescription("Max buffer size power of 2 (19 by default 512KB)").hasArg()
                .create("x"));
        options.addOption(
                OptionBuilder.withDescription("Number of random read samples during read test. (1000 by default)")
                        .hasArg().create("r"));
        options.addOption(OptionBuilder.withDescription("Displays help for this command.").create("h"));

        CommandLineParser parser = new PosixParser();
        CommandLine cmd = null;
        try {
            cmd = parser.parse(options, otherArgs);
            if (cmd.hasOption("h")) {
                HelpFormatter formatter = new HelpFormatter();
                PrintWriter pw = new PrintWriter(out, true);
                formatter.printHelp(pw, HelpFormatter.DEFAULT_WIDTH, name(), null, options,
                        HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, null, false);
                return null;
            }
        } catch (ParseException e) {
            HelpFormatter formatter = new HelpFormatter();
            PrintWriter pw = new PrintWriter(out, true);
            formatter.printHelp(pw, HelpFormatter.DEFAULT_WIDTH, name(), null, options,
                    HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, null, false);
            return null;
        }
        return cmd;
    }

    @Override
    public String description() {
        return "Tune the buffer sizes for your filesystem.  Run -h for full argument list.";
    }

    @Override
    public String usage() {
        return "-p <tmp path>";
    }

    @Override
    public String name() {
        return "fstune";
    }

    private static void printResults(PrintWriter out, Map<Integer, Long> results) {
        int bestBuffer = getTheBest(results);
        for (Entry<Integer, Long> e : results.entrySet()) {
            int bufSize = e.getKey();
            Long time = e.getValue();
            if (bufSize == bestBuffer) {
                out.print("*");
            } else {
                out.print(" ");
            }
            out.println(" Buffer size [" + bufSize + "] took [" + (time) / 1000000.0 + " ms]");
            out.flush();
        }
    }

    private static Map<Integer, Long> runReadingTest(PrintWriter out, Path path, FileSystem fileSystem,
            Random random, int sampleSize, int warmupSize, long size, int min, int max, int readSamples)
            throws IOException {
        out.println("Warming up JVM for Reading.");
        out.flush();
        for (int i = 0; i < warmupSize; i++) {
            testReadBuffer(out, "Warmup Read Pass [" + i + "]", random, fileSystem, path, size, min, max,
                    readSamples);
        }
        Map<Integer, Long> readingResults = new TreeMap<Integer, Long>();
        for (int s = 0; s < sampleSize; s++) {
            add(readingResults, testReadBuffer(out, "Read Pass [" + s + "]", random, fileSystem, path, size, min,
                    max, readSamples));
        }
        return readingResults;
    }

    private static Map<Integer, Long> runWritingTest(PrintWriter out, Path path, FileSystem fileSystem,
            Random random, int sampleSize, int warmupSize, long size, int min, int max) throws IOException {
        out.println("Warming up JVM for Writing.");
        out.flush();
        for (int i = 0; i < warmupSize; i++) {
            testWriteBuffer(out, "Warmup Write Pass [" + i + "]", random, fileSystem, path, size, min, max);
        }
        Map<Integer, Long> writingResults = new TreeMap<Integer, Long>();
        for (int s = 0; s < sampleSize; s++) {
            add(writingResults,
                    testWriteBuffer(out, "Write Pass [" + s + "]", random, fileSystem, path, size, min, max));
        }
        return writingResults;
    }

    private static void add(Map<Integer, Long> results, Map<Integer, Long> newResults) {
        for (Entry<Integer, Long> e : newResults.entrySet()) {
            Long value = results.get(e.getKey());
            if (value == null) {
                results.put(e.getKey(), e.getValue());
            } else {
                results.put(e.getKey(), e.getValue() + value);
            }
        }
    }

    private static Integer getTheBest(Map<Integer, Long> results) {
        long lowestTime = Long.MAX_VALUE;
        Integer bestKey = null;
        for (Entry<Integer, Long> e : results.entrySet()) {
            Long value = e.getValue();
            if (value < lowestTime) {
                lowestTime = value;
                bestKey = e.getKey();
            }
        }
        return bestKey;
    }

    private static Map<Integer, Long> testWriteBuffer(PrintWriter out, String prefix, Random random,
            FileSystem fileSystem, Path path, long size, int min, int max) throws IOException {
        Map<Integer, Long> results = new TreeMap<Integer, Long>();
        for (int i = min; i <= max; i++) {
            int bufSize = (int) Math.pow(2, i);
            out.println(prefix + " Creating [" + size + "] length file for write testing using buffer size of ["
                    + bufSize + "]");
            out.flush();
            FSDataOutputStream outputStream = fileSystem.create(new Path(path, "test.data"), true, bufSize);
            long time = writeFile(out, random, bufSize, outputStream, size);
            outputStream.close();
            results.put(bufSize, time);
            out.println(prefix + " Buffer size [" + bufSize + "] took [" + time / 1000000.0 + " ms]");
            out.flush();
        }
        return results;
    }

    private static Map<Integer, Long> testReadBuffer(PrintWriter out, String prefix, Random random,
            FileSystem fileSystem, Path path, long length, int min, int max, int readSamples) throws IOException {
        FSDataOutputStream outputStream = fileSystem.create(new Path(path, "test.data"), true, 8192);
        writeFile(out, random, 8192, outputStream, length);
        outputStream.close();

        Map<Integer, Long> results = new TreeMap<Integer, Long>();
        for (int i = min; i <= max; i++) {
            int bufSize = (int) Math.pow(2, i);
            out.println(prefix + " Reading [" + length + "] length file for reading test using buffer size of ["
                    + bufSize + "]");
            out.flush();
            FSDataInputStream inputStream = fileSystem.open(new Path(path, "test.data"), bufSize);
            long time = readFile(out, random, bufSize, inputStream, length, readSamples);
            inputStream.close();
            results.put(bufSize, time);
            out.println(prefix + " Buffer size [" + bufSize + "] took [" + time / 1000000.0 + " ms]");
            out.flush();
        }
        return results;
    }

    private static long readFile(PrintWriter out, Random random, int bufSize, FSDataInputStream inputStream,
            long length, int readSamples) throws IOException {
        byte[] buf = new byte[bufSize];
        long start = System.nanoTime();
        long time = 0;
        for (int i = 0; i < readSamples; i++) {
            long now = System.nanoTime();
            if (start + 5000000000l < now) {
                double complete = (((double) i / (double) readSamples) * 100.0);
                out.println(complete + "% Complete");
                out.flush();
                start = System.nanoTime();
            }
            random.nextBytes(buf);
            long position = getPosition(bufSize, random, length);
            long s = System.nanoTime();
            int offset = 0;
            int len = bufSize;
            while (len > 0) {
                int amount = inputStream.read(position, buf, offset, len);
                len -= amount;
                offset += amount;
                position += amount;
            }
            long e = System.nanoTime();
            time += (e - s);
            length -= len;
        }
        return time;
    }

    private static long getPosition(int bufSize, Random random, long length) {
        return Math.abs(random.nextLong()) % (length - bufSize);
    }

    private static long writeFile(PrintWriter out, Random random, int bufSize, FSDataOutputStream outputStream,
            long length) throws IOException {
        byte[] buf = new byte[bufSize];
        final long origLength = length;
        long start = System.nanoTime();
        long time = 0;
        while (length > 0) {
            long now = System.nanoTime();
            if (start + 5000000000l < now) {
                double complete = ((origLength - length) / (double) origLength) * 100.0;
                out.println(complete + "% Complete");
                out.flush();
                start = System.nanoTime();
            }
            random.nextBytes(buf);
            int len = (int) Math.min(length, bufSize);
            long s = System.nanoTime();
            outputStream.write(buf, 0, len);
            long e = System.nanoTime();
            time += (e - s);
            length -= len;
        }
        return time;
    }
}