This is an automated email from the ASF dual-hosted git repository. brfrn169 pushed a commit to branch branch-2 in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-2 by this push: new 2a63d46 HBASE-24776 [hbtop] Support Batch mode (#2291) 2a63d46 is described below commit 2a63d467f4b2cceb37786dbbb756a6091b69695b Author: Toshihiro Suzuki <brfrn...@gmail.com> AuthorDate: Thu Sep 10 17:04:57 2020 +0900 HBASE-24776 [hbtop] Support Batch mode (#2291) Signed-off-by: stack <st...@apache.org> --- .../java/org/apache/hadoop/hbase/hbtop/HBTop.java | 164 +++++++++++++++++---- .../hbase/hbtop/screen/AbstractScreenView.java | 1 + .../apache/hadoop/hbase/hbtop/screen/Screen.java | 26 +++- .../hbase/hbtop/screen/top/TopScreenModel.java | 49 ++++-- .../hbase/hbtop/screen/top/TopScreenPresenter.java | 48 ++++-- .../hbase/hbtop/screen/top/TopScreenView.java | 48 ++++-- .../hadoop/hbase/hbtop/terminal/Terminal.java | 2 +- .../hbtop/terminal/impl/batch/BatchTerminal.java | 80 ++++++++++ .../batch/BatchTerminalPrinter.java} | 51 ++++--- .../hbase/hbtop/screen/top/TestTopScreenModel.java | 16 +- .../hbtop/screen/top/TestTopScreenPresenter.java | 3 +- 11 files changed, 390 insertions(+), 98 deletions(-) diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java index 34c83f5..9c1a000 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/HBTop.java @@ -17,11 +17,17 @@ */ package org.apache.hadoop.hbase.hbtop; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseInterfaceAudience; +import org.apache.hadoop.hbase.hbtop.field.Field; +import org.apache.hadoop.hbase.hbtop.field.FieldInfo; import org.apache.hadoop.hbase.hbtop.mode.Mode; import org.apache.hadoop.hbase.hbtop.screen.Screen; import org.apache.hadoop.util.Tool; @@ -56,17 +62,14 @@ public class HBTop extends Configured implements Tool { public int run(String[] args) throws Exception { long initialRefreshDelay = 3 * 1000; Mode initialMode = Mode.REGION; + List<Field> initialFields = null; + Field initialSortField = null; + Boolean initialAscendingSort = null; + List<RecordFilter> initialFilters = null; + long numberOfIterations = Long.MAX_VALUE; + boolean batchMode = false; try { - // Command line options - Options opts = new Options(); - opts.addOption("h", "help", false, - "Print usage; for help while the tool is running press 'h'"); - opts.addOption("d", "delay", true, - "The refresh delay (in seconds); default is 3 seconds"); - opts.addOption("m", "mode", true, - "The mode; n (Namespace)|t (Table)|r (Region)|s (RegionServer)" - + ", default is r (Region)"); - + Options opts = getOptions(); CommandLine commandLine = new DefaultParser().parse(opts, args); if (commandLine.hasOption("help")) { @@ -74,20 +77,6 @@ public class HBTop extends Configured implements Tool { return 0; } - if (commandLine.hasOption("delay")) { - int delay = 0; - try { - delay = Integer.parseInt(commandLine.getOptionValue("delay")); - } catch (NumberFormatException ignored) { - } - - if (delay < 1) { - LOGGER.warn("Delay set too low or invalid, using default"); - } else { - initialRefreshDelay = delay * 1000L; - } - } - if (commandLine.hasOption("mode")) { String mode = commandLine.getOptionValue("mode"); switch (mode) { @@ -107,23 +96,148 @@ public class HBTop extends Configured implements Tool { initialMode = Mode.REGION_SERVER; break; + case "u": + initialMode = Mode.USER; + break; + + case "c": + initialMode = Mode.CLIENT; + break; + default: LOGGER.warn("Mode set invalid, using default"); break; } } + + if (commandLine.hasOption("outputFieldNames")) { + initialMode.getFieldInfos().forEach(f -> System.out.println(f.getField().getHeader())); + return 0; + } + + if (commandLine.hasOption("delay")) { + int delay = 0; + try { + delay = Integer.parseInt(commandLine.getOptionValue("delay")); + } catch (NumberFormatException ignored) { + } + + if (delay < 1) { + LOGGER.warn("Delay set too low or invalid, using default"); + } else { + initialRefreshDelay = delay * 1000L; + } + } + + if (commandLine.hasOption("numberOfIterations")) { + try { + numberOfIterations = Long.parseLong(commandLine.getOptionValue("numberOfIterations")); + } catch (NumberFormatException ignored) { + LOGGER.warn("The number of iterations set invalid, ignoring"); + } + } + + if (commandLine.hasOption("sortField")) { + String sortField = commandLine.getOptionValue("sortField"); + + String field; + boolean ascendingSort; + if (sortField.startsWith("+")) { + field = sortField.substring(1); + ascendingSort = false; + } else if (sortField.startsWith("-")) { + field = sortField.substring(1); + ascendingSort = true; + } else { + field = sortField; + ascendingSort = false; + } + + Optional<FieldInfo> fieldInfo = initialMode.getFieldInfos().stream() + .filter(f -> f.getField().getHeader().equals(field)).findFirst(); + if (fieldInfo.isPresent()) { + initialSortField = fieldInfo.get().getField(); + initialAscendingSort = ascendingSort; + } else { + LOGGER.warn("The specified sort field " + field + " is not found, using default"); + } + } + + if (commandLine.hasOption("fields")) { + String[] fields = commandLine.getOptionValue("fields").split(","); + initialFields = new ArrayList<>(); + for (String field : fields) { + Optional<FieldInfo> fieldInfo = initialMode.getFieldInfos().stream() + .filter(f -> f.getField().getHeader().equals(field)).findFirst(); + if (fieldInfo.isPresent()) { + initialFields.add(fieldInfo.get().getField()); + } else { + LOGGER.warn("The specified field " + field + " is not found, ignoring"); + } + } + } + + if (commandLine.hasOption("filters")) { + String[] filters = commandLine.getOptionValue("filters").split(","); + List<Field> fields = initialMode.getFieldInfos().stream().map(FieldInfo::getField) + .collect(Collectors.toList()); + for (String filter : filters) { + RecordFilter f = RecordFilter.parse(filter, fields, false); + if (f != null) { + if (initialFilters == null) { + initialFilters = new ArrayList<>(); + } + initialFilters.add(f); + } else { + LOGGER.warn("The specified filter " + filter + " is invalid, ignoring"); + } + } + } + + if (commandLine.hasOption("batchMode")) { + batchMode = true; + } } catch (Exception e) { LOGGER.error("Unable to parse options", e); return 1; } - try (Screen screen = new Screen(getConf(), initialRefreshDelay, initialMode)) { + try (Screen screen = new Screen(getConf(), initialRefreshDelay, initialMode, initialFields, + initialSortField, initialAscendingSort, initialFilters, numberOfIterations, batchMode)) { screen.run(); } return 0; } + private Options getOptions() { + Options opts = new Options(); + opts.addOption("h", "help", false, + "Print usage; for help while the tool is running press 'h'"); + opts.addOption("d", "delay", true, + "The refresh delay (in seconds); default is 3 seconds"); + opts.addOption("m", "mode", true, + "The mode; n (Namespace)|t (Table)|r (Region)|s (RegionServer)|u (User)" + + "|c (Client), default is r"); + opts.addOption("n", "numberOfIterations", true, + "The number of iterations"); + opts.addOption("s", "sortField", true, + "The initial sort field. You can prepend a `+' or `-' to the field name to also override" + + " the sort direction. A leading `+' will force sorting high to low, whereas a `-' will" + + " ensure a low to high ordering"); + opts.addOption("O", "outputFieldNames", false, + "Print each of the available field names on a separate line, then quit"); + opts.addOption("f", "fields", true, + "Show only the given fields. Specify comma separated fields to show multiple fields"); + opts.addOption("i", "filters", true, + "The initial filters. Specify comma separated filters to set multiple filters"); + opts.addOption("b", "batchMode", false, + "Starts hbtop in Batch mode, which could be useful for sending output from hbtop to other" + + " programs or to a file. In this mode, hbtop will not accept input and runs until the" + + " iterations limit you've set with the `-n' command-line option or until killed"); + return opts; + } + private void printUsage(Options opts) { new HelpFormatter().printHelp("hbase hbtop [opts] [-D<property=value>]*", opts); System.out.println(""); diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java index cb5520e..8b55d6e 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/AbstractScreenView.java @@ -75,6 +75,7 @@ public abstract class AbstractScreenView implements ScreenView { return terminal.getTerminalPrinter(startRow); } + @Nullable protected TerminalSize getTerminalSize() { return terminal.getSize(); } diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java index aa951cf..0301664 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/Screen.java @@ -17,18 +17,23 @@ */ package org.apache.hadoop.hbase.hbtop.screen; +import edu.umd.cs.findbugs.annotations.Nullable; import java.io.Closeable; import java.io.IOException; +import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.hbtop.RecordFilter; +import org.apache.hadoop.hbase.hbtop.field.Field; import org.apache.hadoop.hbase.hbtop.mode.Mode; import org.apache.hadoop.hbase.hbtop.screen.top.TopScreenView; import org.apache.hadoop.hbase.hbtop.terminal.KeyPress; import org.apache.hadoop.hbase.hbtop.terminal.Terminal; import org.apache.hadoop.hbase.hbtop.terminal.impl.TerminalImpl; +import org.apache.hadoop.hbase.hbtop.terminal.impl.batch.BatchTerminal; import org.apache.yetus.audience.InterfaceAudience; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,15 +54,23 @@ public class Screen implements Closeable { private ScreenView currentScreenView; private Long timerTimestamp; - public Screen(Configuration conf, long initialRefreshDelay, Mode initialMode) + public Screen(Configuration conf, long initialRefreshDelay, Mode initialMode, + @Nullable List<Field> initialFields, @Nullable Field initialSortField, + @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> initialFilters, + long numberOfIterations, boolean batchMode) throws IOException { connection = ConnectionFactory.createConnection(conf); admin = connection.getAdmin(); // The first screen is the top screen - this.terminal = new TerminalImpl("hbtop"); + if (batchMode) { + terminal = new BatchTerminal(); + } else { + terminal = new TerminalImpl("hbtop"); + } currentScreenView = new TopScreenView(this, terminal, initialRefreshDelay, admin, - initialMode); + initialMode, initialFields, initialSortField, initialAscendingSort, initialFilters, + numberOfIterations); } @Override @@ -91,11 +104,8 @@ public class Screen implements Closeable { timerTimestamp = null; nextScreenView = currentScreenView.handleTimer(); } else { - if (timerTimestamp - now < SLEEP_TIMEOUT_MILLISECONDS) { - TimeUnit.MILLISECONDS.sleep(timerTimestamp - now); - } else { - TimeUnit.MILLISECONDS.sleep(SLEEP_TIMEOUT_MILLISECONDS); - } + TimeUnit.MILLISECONDS + .sleep(Math.min(timerTimestamp - now, SLEEP_TIMEOUT_MILLISECONDS)); continue; } } else { diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java index 3dd7f12..bdd52a7 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenModel.java @@ -19,13 +19,13 @@ package org.apache.hadoop.hbase.hbtop.screen.top; import static org.apache.commons.lang3.time.DateFormatUtils.ISO_8601_EXTENDED_TIME_FORMAT; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; - import org.apache.hadoop.hbase.ClusterMetrics; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.hbtop.Record; @@ -64,28 +64,55 @@ public class TopScreenModel { private boolean ascendingSort; - public TopScreenModel(Admin admin, Mode initialMode) { + public TopScreenModel(Admin admin, Mode initialMode, @Nullable List<Field> initialFields, + @Nullable Field initialSortField, @Nullable Boolean initialAscendingSort, + @Nullable List<RecordFilter> initialFilters) { this.admin = Objects.requireNonNull(admin); - switchMode(Objects.requireNonNull(initialMode), null, false); + switchMode(Objects.requireNonNull(initialMode), initialSortField, false, initialFields, + initialAscendingSort, initialFilters); } - public void switchMode(Mode nextMode, List<RecordFilter> initialFilters, - boolean keepSortFieldAndSortOrderIfPossible) { + public void switchMode(Mode nextMode, boolean keepSortFieldAndSortOrderIfPossible, + List<RecordFilter> initialFilters) { + switchMode(nextMode, null, keepSortFieldAndSortOrderIfPossible, null, null, initialFilters); + } + public void switchMode(Mode nextMode, Field initialSortField, + boolean keepSortFieldAndSortOrderIfPossible, @Nullable List<Field> initialFields, + @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> initialFilters) { currentMode = nextMode; fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos())); - fields = Collections.unmodifiableList(currentMode.getFieldInfos().stream() - .map(FieldInfo::getField).collect(Collectors.toList())); + + if (initialFields != null) { + List<Field> tmp = new ArrayList<>(initialFields); + tmp.addAll(currentMode.getFieldInfos().stream().map(FieldInfo::getField) + .filter(f -> !initialFields.contains(f)) + .collect(Collectors.toList())); + fields = Collections.unmodifiableList(tmp); + } else { + fields = Collections.unmodifiableList(currentMode.getFieldInfos().stream() + .map(FieldInfo::getField).collect(Collectors.toList())); + } if (keepSortFieldAndSortOrderIfPossible) { boolean match = fields.stream().anyMatch(f -> f == currentSortField); if (!match) { + if (initialSortField != null && initialAscendingSort != null) { + currentSortField = initialSortField; + ascendingSort = initialAscendingSort; + } else { + currentSortField = nextMode.getDefaultSortField(); + ascendingSort = false; + } + } + } else { + if (initialSortField != null && initialAscendingSort != null) { + currentSortField = initialSortField; + ascendingSort = initialAscendingSort; + } else { currentSortField = nextMode.getDefaultSortField(); ascendingSort = false; } - } else { - currentSortField = nextMode.getDefaultSortField(); - ascendingSort = false; } clearFilters(); @@ -173,7 +200,7 @@ public class TopScreenModel { if (drillDownInfo == null) { return false; } - switchMode(drillDownInfo.getNextMode(), drillDownInfo.getInitialFilters(), true); + switchMode(drillDownInfo.getNextMode(), true, drillDownInfo.getInitialFilters()); return true; } diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java index b22aee0..6fbd23f 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenPresenter.java @@ -17,6 +17,7 @@ */ package org.apache.hadoop.hbase.hbtop.screen.top; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; @@ -57,21 +58,38 @@ public class TopScreenPresenter { private final EnumMap<Field, Boolean> fieldDisplayMap = new EnumMap<>(Field.class); private final EnumMap<Field, Integer> fieldLengthMap = new EnumMap<>(Field.class); + private final long numberOfIterations; + private long iterations; + public TopScreenPresenter(TopScreenView topScreenView, long initialRefreshDelay, - TopScreenModel topScreenModel) { + TopScreenModel topScreenModel, @Nullable List<Field> initialFields, long numberOfIterations) { this.topScreenView = Objects.requireNonNull(topScreenView); this.refreshDelay = new AtomicLong(initialRefreshDelay); this.topScreenModel = Objects.requireNonNull(topScreenModel); + this.numberOfIterations = numberOfIterations; - initFieldDisplayMapAndFieldLengthMap(); + initFieldDisplayMapAndFieldLengthMap(initialFields); } public void init() { - terminalLength = topScreenView.getTerminalSize().getColumns(); - paging.updatePageSize(topScreenView.getPageSize()); + updateTerminalLengthAndPageSize(topScreenView.getTerminalSize(), topScreenView.getPageSize()); topScreenView.hideCursor(); } + private void updateTerminalLengthAndPageSize(@Nullable TerminalSize terminalSize, + @Nullable Integer pageSize) { + if (terminalSize != null) { + terminalLength = terminalSize.getColumns(); + } else { + terminalLength = Integer.MAX_VALUE; + } + if (pageSize != null) { + paging.updatePageSize(pageSize); + } else { + paging.updatePageSize(Integer.MAX_VALUE); + } + } + public long refresh(boolean force) { if (!force) { long delay = System.currentTimeMillis() - lastRefreshTimestamp; @@ -82,8 +100,7 @@ public class TopScreenPresenter { TerminalSize newTerminalSize = topScreenView.doResizeIfNecessary(); if (newTerminalSize != null) { - terminalLength = newTerminalSize.getColumns(); - paging.updatePageSize(topScreenView.getPageSize()); + updateTerminalLengthAndPageSize(newTerminalSize, topScreenView.getPageSize()); topScreenView.clearTerminal(); } @@ -98,6 +115,7 @@ public class TopScreenPresenter { topScreenView.refreshTerminal(); lastRefreshTimestamp = System.currentTimeMillis(); + iterations++; return refreshDelay.get(); } @@ -242,7 +260,7 @@ public class TopScreenPresenter { } private void switchMode(Mode nextMode) { - topScreenModel.switchMode(nextMode, null, false); + topScreenModel.switchMode(nextMode, false, null); reset(); } @@ -258,18 +276,22 @@ public class TopScreenPresenter { } private void reset() { - initFieldDisplayMapAndFieldLengthMap(); + initFieldDisplayMapAndFieldLengthMap(null); adjustFieldLength.set(true); paging.init(); horizontalScroll = 0; topScreenView.clearTerminal(); } - private void initFieldDisplayMapAndFieldLengthMap() { + private void initFieldDisplayMapAndFieldLengthMap(@Nullable List<Field> initialFields) { fieldDisplayMap.clear(); fieldLengthMap.clear(); for (FieldInfo fieldInfo : topScreenModel.getFieldInfos()) { - fieldDisplayMap.put(fieldInfo.getField(), fieldInfo.isDisplayByDefault()); + if (initialFields != null) { + fieldDisplayMap.put(fieldInfo.getField(), initialFields.contains(fieldInfo.getField())); + } else { + fieldDisplayMap.put(fieldInfo.getField(), fieldInfo.isDisplayByDefault()); + } fieldLengthMap.put(fieldInfo.getField(), fieldInfo.getDefaultLength()); } } @@ -288,7 +310,7 @@ public class TopScreenPresenter { double delay; try { - delay = Double.valueOf(inputString); + delay = Double.parseDouble(inputString); } catch (NumberFormatException e) { return goToMessageMode(screen, terminal, row, "Unacceptable floating point"); } @@ -329,4 +351,8 @@ public class TopScreenPresenter { filters.addAll(topScreenModel.getPushDownFilters()); return new FilterDisplayModeScreenView(screen, terminal, row, filters, topScreenView); } + + public boolean isIterationFinished() { + return iterations >= numberOfIterations; + } } diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java index 9a29177..da5c883 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/screen/top/TopScreenView.java @@ -23,6 +23,8 @@ import java.util.List; import java.util.stream.Collectors; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.hbtop.Record; +import org.apache.hadoop.hbase.hbtop.RecordFilter; +import org.apache.hadoop.hbase.hbtop.field.Field; import org.apache.hadoop.hbase.hbtop.mode.Mode; import org.apache.hadoop.hbase.hbtop.screen.AbstractScreenView; import org.apache.hadoop.hbase.hbtop.screen.Screen; @@ -50,13 +52,16 @@ public class TopScreenView extends AbstractScreenView { private static final int RECORD_START_ROW = 9; private final TopScreenPresenter topScreenPresenter; - private int pageSize; + private Integer pageSize; public TopScreenView(Screen screen, Terminal terminal, long initialRefreshDelay, Admin admin, - Mode initialMode) { + Mode initialMode, @Nullable List<Field> initialFields, @Nullable Field initialSortField, + @Nullable Boolean initialAscendingSort, @Nullable List<RecordFilter> initialFilters, + long numberOfIterations) { super(screen, terminal); this.topScreenPresenter = new TopScreenPresenter(this, initialRefreshDelay, - new TopScreenModel(admin, initialMode)); + new TopScreenModel(admin, initialMode, initialFields, initialSortField, + initialAscendingSort, initialFilters), initialFields, numberOfIterations); } @Override @@ -66,11 +71,12 @@ public class TopScreenView extends AbstractScreenView { setTimer(delay); } + @Nullable @Override public ScreenView handleTimer() { long delay = topScreenPresenter.refresh(false); setTimer(delay); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; } @Nullable @@ -79,39 +85,39 @@ public class TopScreenView extends AbstractScreenView { switch (keyPress.getType()) { case Enter: topScreenPresenter.refresh(true); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case ArrowUp: topScreenPresenter.arrowUp(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case ArrowDown: topScreenPresenter.arrowDown(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case ArrowLeft: topScreenPresenter.arrowLeft(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case ArrowRight: topScreenPresenter.arrowRight(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case PageUp: topScreenPresenter.pageUp(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case PageDown: topScreenPresenter.pageDown(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case Home: topScreenPresenter.home(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case End: topScreenPresenter.end(); - return this; + return topScreenPresenter.isIterationFinished() ? null : this; case Escape: return null; @@ -182,13 +188,18 @@ public class TopScreenView extends AbstractScreenView { return this; } + @Nullable @Override public TerminalSize getTerminalSize() { TerminalSize terminalSize = super.getTerminalSize(); + if (terminalSize == null) { + return null; + } updatePageSize(terminalSize); return terminalSize; } + @Nullable @Override public TerminalSize doResizeIfNecessary() { TerminalSize terminalSize = super.doResizeIfNecessary(); @@ -206,7 +217,8 @@ public class TopScreenView extends AbstractScreenView { } } - public int getPageSize() { + @Nullable + public Integer getPageSize() { return pageSize; } @@ -244,8 +256,14 @@ public class TopScreenView extends AbstractScreenView { private void showRecords(List<Header> headers, List<Record> records, Record selectedRecord) { TerminalPrinter printer = getTerminalPrinter(RECORD_START_ROW); + int size; + if (pageSize != null) { + size = pageSize; + } else { + size = records.size(); + } List<String> buf = new ArrayList<>(headers.size()); - for (int i = 0; i < pageSize; i++) { + for (int i = 0; i < size; i++) { if(i < records.size()) { Record record = records.get(i); buf.clear(); diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java index 248bb58..c834b75 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java @@ -29,7 +29,7 @@ import org.apache.yetus.audience.InterfaceAudience; public interface Terminal extends Closeable { void clear(); void refresh(); - TerminalSize getSize(); + @Nullable TerminalSize getSize(); @Nullable TerminalSize doResizeIfNecessary(); @Nullable KeyPress pollKeyPress(); CursorPosition getCursorPosition(); diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java new file mode 100644 index 0000000..19d6426 --- /dev/null +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java @@ -0,0 +1,80 @@ +/** + * 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.hadoop.hbase.hbtop.terminal.impl.batch; + +import edu.umd.cs.findbugs.annotations.Nullable; +import org.apache.hadoop.hbase.hbtop.terminal.CursorPosition; +import org.apache.hadoop.hbase.hbtop.terminal.KeyPress; +import org.apache.hadoop.hbase.hbtop.terminal.Terminal; +import org.apache.hadoop.hbase.hbtop.terminal.TerminalPrinter; +import org.apache.hadoop.hbase.hbtop.terminal.TerminalSize; + +public class BatchTerminal implements Terminal { + + private static final TerminalPrinter TERMINAL_PRINTER = new BatchTerminalPrinter(); + + @Override + public void clear() { + } + + @Override + public void refresh() { + // Add a new line + TERMINAL_PRINTER.endOfLine(); + } + + @Nullable + @Override + public TerminalSize getSize() { + return null; + } + + @Nullable + @Override + public TerminalSize doResizeIfNecessary() { + return null; + } + + @Nullable + @Override + public KeyPress pollKeyPress() { + return null; + } + + @Override + public CursorPosition getCursorPosition() { + return null; + } + + @Override + public void setCursorPosition(int column, int row) { + } + + @Override + public void hideCursor() { + } + + @Override + public TerminalPrinter getTerminalPrinter(int startRow) { + return TERMINAL_PRINTER; + } + + @Override + public void close() { + } +} diff --git a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java similarity index 54% copy from hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java copy to hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java index 248bb58..db7a9e7 100644 --- a/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/Terminal.java +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java @@ -15,25 +15,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.hadoop.hbase.hbtop.terminal; +package org.apache.hadoop.hbase.hbtop.terminal.impl.batch; -import edu.umd.cs.findbugs.annotations.Nullable; -import java.io.Closeable; -import org.apache.yetus.audience.InterfaceAudience; +import org.apache.hadoop.hbase.hbtop.terminal.TerminalPrinter; +public class BatchTerminalPrinter implements TerminalPrinter { -/** - * The terminal interface that is an abstraction of terminal screen. - */ -@InterfaceAudience.Private -public interface Terminal extends Closeable { - void clear(); - void refresh(); - TerminalSize getSize(); - @Nullable TerminalSize doResizeIfNecessary(); - @Nullable KeyPress pollKeyPress(); - CursorPosition getCursorPosition(); - void setCursorPosition(int column, int row); - void hideCursor(); - TerminalPrinter getTerminalPrinter(int startRow); + @Override + public TerminalPrinter print(String value) { + System.out.print(value); + return this; + } + + @Override + public TerminalPrinter startHighlight() { + return this; + } + + @Override + public TerminalPrinter stopHighlight() { + return this; + } + + @Override + public TerminalPrinter startBold() { + return this; + } + + @Override + public TerminalPrinter stopBold() { + return this; + } + + @Override + public void endOfLine() { + System.out.println(); + } } diff --git a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java index 08a399c..85b9010 100644 --- a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java +++ b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenModel.java @@ -63,7 +63,7 @@ public class TestTopScreenModel { @Before public void setup() throws IOException { when(admin.getClusterMetrics()).thenReturn(TestUtils.createDummyClusterMetrics()); - topScreenModel = new TopScreenModel(admin, Mode.REGION); + topScreenModel = new TopScreenModel(admin, Mode.REGION, null, null, null, null); fields = Mode.REGION.getFieldInfos().stream() .map(FieldInfo::getField) @@ -84,17 +84,17 @@ public class TestTopScreenModel { TestUtils.assertRecordsInRegionMode(topScreenModel.getRecords()); // Namespace Mode - topScreenModel.switchMode(Mode.NAMESPACE, null, false); + topScreenModel.switchMode(Mode.NAMESPACE, false, null); topScreenModel.refreshMetricsData(); TestUtils.assertRecordsInNamespaceMode(topScreenModel.getRecords()); // Table Mode - topScreenModel.switchMode(Mode.TABLE, null, false); + topScreenModel.switchMode(Mode.TABLE, false, null); topScreenModel.refreshMetricsData(); TestUtils.assertRecordsInTableMode(topScreenModel.getRecords()); // Namespace Mode - topScreenModel.switchMode(Mode.REGION_SERVER, null, false); + topScreenModel.switchMode(Mode.REGION_SERVER, false, null); topScreenModel.refreshMetricsData(); TestUtils.assertRecordsInRegionServerMode(topScreenModel.getRecords()); } @@ -168,7 +168,7 @@ public class TestTopScreenModel { @Test public void testSwitchMode() { - topScreenModel.switchMode(Mode.TABLE, null, false); + topScreenModel.switchMode(Mode.TABLE, false, null); assertThat(topScreenModel.getCurrentMode(), is(Mode.TABLE)); // Test for initialFilters @@ -176,7 +176,7 @@ public class TestTopScreenModel { RecordFilter.parse("TABLE==table1", fields, true), RecordFilter.parse("TABLE==table2", fields, true)); - topScreenModel.switchMode(Mode.TABLE, initialFilters, false); + topScreenModel.switchMode(Mode.TABLE, false, initialFilters); assertThat(topScreenModel.getFilters().size(), is(initialFilters.size())); for (int i = 0; i < topScreenModel.getFilters().size(); i++) { @@ -186,13 +186,13 @@ public class TestTopScreenModel { // Test when keepSortFieldAndSortOrderIfPossible is true topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields); - topScreenModel.switchMode(Mode.NAMESPACE, null, true); + topScreenModel.switchMode(Mode.NAMESPACE, true, null); assertThat(topScreenModel.getCurrentSortField(), is(Field.NAMESPACE)); } @Test public void testDrillDown() { - topScreenModel.switchMode(Mode.TABLE, null, false); + topScreenModel.switchMode(Mode.TABLE, false, null); topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields); topScreenModel.refreshMetricsData(); diff --git a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java index 6bd214a..d218dd5 100644 --- a/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java +++ b/hbase-hbtop/src/test/java/org/apache/hadoop/hbase/hbtop/screen/top/TestTopScreenPresenter.java @@ -95,7 +95,8 @@ public class TestTopScreenPresenter { when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS); when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY); - topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, topScreenModel); + topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, topScreenModel, + null, Long.MAX_VALUE); } @Test