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;

Reply via email to