Repository: tajo Updated Branches: refs/heads/master 704a61ccb -> 294104d28
TAJO-2033: Printing out query status with progress bar in TSQL. Closes #924 Signed-off-by: Jihoon Son <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/tajo/repo Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/294104d2 Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/294104d2 Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/294104d2 Branch: refs/heads/master Commit: 294104d2805f8c8a18b92f9255403e73ae5fabb2 Parents: 704a61c Author: Dongkyu Hwangbo <[email protected]> Authored: Tue Feb 16 17:00:17 2016 +0900 Committer: Jihoon Son <[email protected]> Committed: Tue Feb 16 17:01:06 2016 +0900 ---------------------------------------------------------------------- CHANGES | 3 + .../cli/tsql/DefaultTajoCliOutputFormatter.java | 114 ++++++++++++++++++- .../java/org/apache/tajo/cli/tsql/TajoCli.java | 10 +- 3 files changed, 122 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tajo/blob/294104d2/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index a6f993a..ff4ca46 100644 --- a/CHANGES +++ b/CHANGES @@ -192,6 +192,9 @@ Release 0.12.0 - unreleased TASKS + TAJO-2033: Printing out query status with progress bar in TSQL. + (Dongkyu Hwangbo via jihoon) + TAJO-2076: Add backward compatibility testing with hadoop on travis. (jinho) TAJO-2074: Upgrade hadoop and netty. (jinho) http://git-wip-us.apache.org/repos/asf/tajo/blob/294104d2/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/DefaultTajoCliOutputFormatter.java ---------------------------------------------------------------------- diff --git a/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/DefaultTajoCliOutputFormatter.java b/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/DefaultTajoCliOutputFormatter.java index 03aa4cc..0de0809 100644 --- a/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/DefaultTajoCliOutputFormatter.java +++ b/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/DefaultTajoCliOutputFormatter.java @@ -18,26 +18,37 @@ package org.apache.tajo.cli.tsql; +import jline.TerminalFactory; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.tajo.QueryId; import org.apache.tajo.SessionVars; import org.apache.tajo.TajoConstants; +import org.apache.tajo.TajoProtos; import org.apache.tajo.catalog.TableDesc; import org.apache.tajo.catalog.statistics.TableStats; import org.apache.tajo.client.QueryStatus; import org.apache.tajo.util.FileUtil; +import org.fusesource.jansi.Ansi; import java.io.InputStream; import java.io.PrintWriter; import java.sql.ResultSet; import java.sql.ResultSetMetaData; +import static com.google.common.base.Strings.repeat; +import static java.lang.Math.max; +import static java.lang.Math.min; +import static org.fusesource.jansi.Ansi.ansi; +import static org.fusesource.jansi.internal.CLibrary.STDOUT_FILENO; +import static org.fusesource.jansi.internal.CLibrary.isatty; + public class DefaultTajoCliOutputFormatter implements TajoCliOutputFormatter { private int printPauseRecords; private boolean printPause; private boolean printErrorTrace; private String nullChar; public static final char QUIT_COMMAND = 'q'; + public static final boolean REAL_TERMINAL = detectRealTerminal(); @Override public void init(TajoCli.TajoCliContext context) { @@ -146,10 +157,70 @@ public class DefaultTajoCliOutputFormatter implements TajoCliOutputFormatter { @Override public void printProgress(PrintWriter sout, QueryStatus status) { - sout.println("Progress: " + (int)(status.getProgress() * 100.0f) - + "%, response time: " - + getResponseTimeReadable((float)((status.getFinishTime() - status.getSubmitTime()) / 1000.0))); - sout.flush(); + int terminalWidth = TerminalFactory.get().getWidth(); + int progressWidth = (min(terminalWidth, 100) - 75) + 17; // progress bar is 17-42 characters wide + + int progress = (int)(status.getProgress() * 100.0f); + String responseTime = getResponseTimeReadable((float)((status.getFinishTime() - status.getSubmitTime()) / 1000.0)); + String progressBar = formatProgressBar(progressWidth, progress); + + reprintProgressLine(sout, progressBar, progress, responseTime, status); + } + + public String formatProgressBar(int width, int progress) { + if (progress == 0) { + return repeat(" ", width); + } + + // compute nominal lengths + int completeLength = min(width, ceil(progress * width, 100)); + int remainLength = width; + int runningLength = 1; + + // adjust to fix rounding errors + if (((completeLength + runningLength + remainLength) != width) && (remainLength > 0)) { + remainLength = max(0, width - completeLength - runningLength); + } + + if (((completeLength + runningLength + remainLength) > width) && (progress > 0)) { + completeLength = max(0, width - runningLength - remainLength); + } + + return repeat("=", completeLength) + repeat(">", runningLength) + repeat(" ", remainLength); + } + + private int ceil(int dividend, int divisor) { + return ((dividend + divisor) - 1) / divisor; + } + + public void reprintProgressLine(PrintWriter out, String progressBar, int progress, String responseTime, + QueryStatus status) { + // [=====>> ] 10% 3.18 sec + String lineFormat = "[%s] %d%% %s"; + + if (isRealTerminal()) { + if (status.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) { + progressBar = "@|green " + progressBar + "|@"; + } + else if (status.getState() == TajoProtos.QueryState.QUERY_ERROR || + status.getState() == TajoProtos.QueryState.QUERY_FAILED || + status.getState() == TajoProtos.QueryState.QUERY_KILLED) { + progressBar = "@|red " + progressBar + "|@"; + } + + String line = String.format(lineFormat, progressBar, progress, responseTime); + out.print(ansi().eraseLine(Ansi.Erase.ALL).a('\r').render(line)); + } + else { + String line = String.format(lineFormat, progressBar, progress, responseTime); + out.print('\n' + line); + } + + out.flush(); + } + + public boolean isRealTerminal() { + return REAL_TERMINAL; } @Override @@ -206,4 +277,39 @@ public class DefaultTajoCliOutputFormatter implements TajoCliOutputFormatter { return message; } + + /** + * borrowed from Presto + */ + private static boolean detectRealTerminal() { + // If the jansi.passthrough property is set, then don't interpret + // any of the ansi sequences. + if (Boolean.parseBoolean(System.getProperty("jansi.passthrough"))) { + return true; + } + + // If the jansi.strip property is set, then we just strip + // the ansi escapes. + if (Boolean.parseBoolean(System.getProperty("jansi.strip"))) { + return false; + } + + String os = System.getProperty("os.name"); + if (os.startsWith("Windows")) { + // We could support this, but we'd need a windows box + return true; + } + + // We must be on some unix variant.. + try { + // check if standard out is a terminal + if (isatty(STDOUT_FILENO) == 0) { + return false; + } + } + catch (NoClassDefFoundError | UnsatisfiedLinkError ignore) { + // These errors happen if the JNI lib is not available for your platform. + } + return true; + } } http://git-wip-us.apache.org/repos/asf/tajo/blob/294104d2/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/TajoCli.java ---------------------------------------------------------------------- diff --git a/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/TajoCli.java b/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/TajoCli.java index 5ba12c0..436b941 100644 --- a/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/TajoCli.java +++ b/tajo-cli/src/main/java/org/apache/tajo/cli/tsql/TajoCli.java @@ -601,6 +601,7 @@ public class TajoCli implements Closeable { // query execute ResultSet res = null; QueryStatus status = null; + boolean isProgressPrinting = false; try { int initRetries = 0; @@ -613,8 +614,11 @@ public class TajoCli implements Closeable { continue; } - if (TajoClientUtil.isQueryRunning(status.getState()) || status.getState() == QueryState.QUERY_SUCCEEDED) { + if (TajoClientUtil.isQueryRunning(status.getState())) { displayFormatter.printProgress(sout, status); + if (!isProgressPrinting) { + isProgressPrinting = true; + } } if (TajoClientUtil.isQueryComplete(status.getState()) && status.getState() != QueryState.QUERY_KILL_WAIT) { @@ -625,6 +629,10 @@ public class TajoCli implements Closeable { } } + if (isProgressPrinting) { + displayFormatter.printProgress(sout, status); + sout.println(); // to print out query result in next line + } if (status.getState() == QueryState.QUERY_ERROR || status.getState() == QueryState.QUERY_FAILED) { displayFormatter.printErrorMessage(sout, status); wasError = true;
