alluxio-master-2.x/stress/shell/src/main/java/alluxio/stress/cli/MasterBatchTask.java
/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.stress.cli;

import alluxio.stress.BaseParameters;
import alluxio.stress.master.MasterBatchTaskParameters;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParametersDelegate;
import com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Multiple tasks runner for Master StressBench.
 */
public class MasterBatchTask extends BatchTask {
  private static final Logger LOG = LoggerFactory.getLogger(MasterBatchTask.class);
  // Target throughput is set to a huge number to reach the maximum throughput of the task.
  private static final int TARGET_THROUGHPUT  = 1_000_000;

  @ParametersDelegate
  private final BaseParameters mBaseParameter = new BaseParameters();
  @ParametersDelegate
  private final MasterBatchTaskParameters mParameter = new MasterBatchTaskParameters();

  @Override
  public void run(String[] args) {
    JCommander jc = new JCommander(this);
    jc.setProgramName(this.getClass().getSimpleName());
    try {
      jc.parse(args);
    } catch (Exception e) {
      LOG.error("Failed to parse command: ", e);
      System.out.println(getDescription());
      throw e;
    }

    if (mParameter.mWriteType.equals("ALL")) {
      System.err.format("Parameter write-type ALL is not supported in batch task %s",
          mParameter.mTaskName);
      return;
    }

    if (mParameter.mStopCount != -1 && !(mParameter.mWarmup.equals("0")
        || mParameter.mWarmup.equals("0s"))) {
      System.out.println("Warning: when using stop-count parameter to claim the files "
          + "to be operated, the operations executed in warmup time will not be calculated in"
          + "the final result. The calculated operations will be less than expected.");
    }

    List<String[]> command = getCommand();
    for (String[] arg : command) {
      System.out.println("-----------------------------------------------------");
      System.out.format("Now executing command : %s on MasterStressBench...%n", arg[1]);
      // If one individual task fails, the pipeline will try to move on and finish
      try {
        StressMasterBench bench = new StressMasterBench();
        String jsonResult = bench.run(arg);
        System.out.println("Task finished successfully. The result is following :");
        System.out.println(jsonResult);
      } catch (Exception e) {
        System.err.format("Failed to finish the %s operation%n", arg[1]);
        e.printStackTrace();
      }
    }
    System.out.println("-----------------------------------------------------");
    System.out.println("All tasks finished. You can find the test results in the outputs above.");
  }

  private List<String[]> getCommand() {
    List<String[]> commandList = new ArrayList<>();

    if (mParameter.mTaskName.equals("MasterComprehensiveFileBatchTask")) {
      String[] operations = {"CreateFile", "ListDir", "ListDirLocated", "GetBlockLocations",
          "GetFileStatus", "OpenFile", "DeleteFile"};
      for (String op : operations) {
        List<String> command = new ArrayList<>(Arrays.asList(
            "--operation", op,
            "--base", mParameter.mBasePath,
            "--threads", String.valueOf(mParameter.mThreads),
            "--stop-count", String.valueOf(mParameter.mStopCount),
            "--target-throughput", String.valueOf(TARGET_THROUGHPUT),
            "--warmup", mParameter.mWarmup,
            "--create-file-size", mParameter.mCreateFileSize,
            "--write-type", mParameter.mWriteType,
            "--clients", String.valueOf(mParameter.mClients),
            "--client-type", mParameter.mClientType.toString(),
            "--read-type", mParameter.mReadType.toString(),
            "--fixed-count", String.valueOf(mParameter.mStopCount)
        ));

        // add all base parameters
        command.addAll(mBaseParameter.toBatchTaskArgumentString());

        commandList.add(command.toArray(new String[0]));
      }
    }
    return commandList;
  }

  private String getDescription() {
    return String.join("\n", ImmutableList.of(
        "BatchTaskRunner is a tool to execute pre-defined group of MasterStressBench tasks",
        "",
        "Example:",
        "# this would run `CreateFile', 'ListDir', 'ListDirLocated', 'GetBlockLocations', "
            + "'GetFileStatus', 'OpenFile', 'DeleteFile' operations for 1000 files with size 1KB"
            + " in 10 threads and record the throughput. The file will be created in directory"
            + " alluxio:///stress-master-base",
        "$ bin/alluxio runClass alluxio.stress.cli.BatchTaskRunner"
            + " MasterComprehensiveFileBatchTask --num-files 1000 --threads 10 --create-file-size"
            + " 1k --base alluxio:///stress-master-base --warmup 0s",
        ""
    ));
  }
}
