From f8078009e9e8cadee76fd38d1e35ea6812b866de Mon Sep 17 00:00:00 2001 From: Toshihiro Suzuki Date: Sat, 20 Mar 2021 11:16:26 +0900 Subject: [PATCH] HBASE-25258 Backport HBASE-24776 "[hbtop] Support Batch mode" to branch-1 (#3065) Signed-off-by: stack stack@apache.org --- .../org/apache/hadoop/hbase/hbtop/HBTop.java | 169 +++++++++++++++--- .../hbtop/screen/AbstractScreenView.java | 1 + .../hadoop/hbase/hbtop/screen/Screen.java | 26 ++- .../hbtop/screen/top/TopScreenModel.java | 44 +++-- .../hbtop/screen/top/TopScreenPresenter.java | 46 +++-- .../hbase/hbtop/screen/top/TopScreenView.java | 48 +++-- .../hadoop/hbase/hbtop/terminal/Terminal.java | 2 +- .../terminal/impl/batch/BatchTerminal.java | 80 +++++++++ .../impl/batch/BatchTerminalPrinter.java | 55 ++++++ .../hbtop/screen/top/TestTopScreenModel.java | 16 +- .../screen/top/TestTopScreenPresenter.java | 3 +- 11 files changed, 412 insertions(+), 78 deletions(-) create mode 100644 hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminal.java create mode 100644 hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java 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 ac05bb2b92d..b0f4710edb6 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,6 +17,8 @@ */ package org.apache.hadoop.hbase.hbtop; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import org.apache.commons.cli.BasicParser; @@ -30,6 +32,8 @@ import org.apache.hadoop.conf.Configured; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseInterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience; +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; @@ -55,17 +59,14 @@ public class HBTop extends Configured implements Tool { public int run(String[] args) throws Exception { long initialRefreshDelay = 3 * 1000; Mode initialMode = Mode.REGION; + List initialFields = null; + Field initialSortField = null; + Boolean initialAscendingSort = null; + List 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 BasicParser().parse(opts, args); if (commandLine.hasOption("help")) { @@ -73,20 +74,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) { - LOG.warn("Delay set too low or invalid, using default"); - } else { - initialRefreshDelay = delay * 1000L; - } - } - if (commandLine.hasOption("mode")) { String mode = commandLine.getOptionValue("mode"); switch (mode) { @@ -111,18 +98,150 @@ public class HBTop extends Configured implements Tool { break; } } + + if (commandLine.hasOption("outputFieldNames")) { + for (FieldInfo fieldInfo : initialMode.getFieldInfos()) { + System.out.println(fieldInfo.getField().getHeader()); + } + return 0; + } + + if (commandLine.hasOption("delay")) { + int delay = 0; + try { + delay = Integer.parseInt(commandLine.getOptionValue("delay")); + } catch (NumberFormatException ignored) { + } + + if (delay < 1) { + LOG.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) { + LOG.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; + } + + FieldInfo fieldInfo = null; + for (FieldInfo info : initialMode.getFieldInfos()) { + if (info.getField().getHeader().equals(field)) { + fieldInfo = info; + break; + } + } + if (fieldInfo != null) { + initialSortField = fieldInfo.getField(); + initialAscendingSort = ascendingSort; + } else { + LOG.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) { + FieldInfo fieldInfo = null; + for (FieldInfo info : initialMode.getFieldInfos()) { + if (info.getField().getHeader().equals(field)) { + fieldInfo = info; + break; + } + } + if (fieldInfo != null) { + initialFields.add(fieldInfo.getField()); + } else { + LOG.warn("The specified field " + field + " is not found, ignoring"); + } + } + } + + if (commandLine.hasOption("filters")) { + String[] filters = commandLine.getOptionValue("filters").split(","); + + List fields = new ArrayList<>(); + for (FieldInfo fieldInfo : initialMode.getFieldInfos()) { + fields.add(fieldInfo.getField()); + } + + for (String filter : filters) { + RecordFilter f = RecordFilter.parse(filter, fields, false); + if (f != null) { + if (initialFilters == null) { + initialFilters = new ArrayList<>(); + } + initialFilters.add(f); + } else { + LOG.warn("The specified filter " + filter + " is invalid, ignoring"); + } + } + } + + if (commandLine.hasOption("batchMode")) { + batchMode = true; + } } catch (Exception e) { LOG.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), 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]*", 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 32dfb53e17c..8c885a449ee 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 bbcbba2fca4..7629052a9f3 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,8 +17,10 @@ */ 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.commons.logging.Log; @@ -28,11 +30,14 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience; 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; /** * This dispatches key presses and timers to the current {@link ScreenView}. @@ -51,15 +56,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 initialFields, @Nullable Field initialSortField, + @Nullable Boolean initialAscendingSort, @Nullable List 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 @@ -93,11 +106,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 f795c4a8bde..05780da1723 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 @@ -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.Collections; import java.util.Comparator; @@ -61,20 +62,34 @@ public class TopScreenModel { private boolean ascendingSort; - public TopScreenModel(Admin admin, Mode initialMode) { + public TopScreenModel(Admin admin, Mode initialMode, @Nullable List initialFields, + @Nullable Field initialSortField, @Nullable Boolean initialAscendingSort, + @Nullable List 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 initialFilters, - boolean keepSortFieldAndSortOrderIfPossible) { + public void switchMode(Mode nextMode, boolean keepSortFieldAndSortOrderIfPossible, + List initialFilters) { + switchMode(nextMode, null, keepSortFieldAndSortOrderIfPossible, null, null, initialFilters); + } + public void switchMode(Mode nextMode, Field initialSortField, + boolean keepSortFieldAndSortOrderIfPossible, @Nullable List initialFields, + @Nullable Boolean initialAscendingSort, @Nullable List initialFilters) { currentMode = nextMode; fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos())); fields = new ArrayList<>(); for (FieldInfo fieldInfo : currentMode.getFieldInfos()) { - fields.add(fieldInfo.getField()); + if (initialFields != null) { + if (initialFields.contains(fieldInfo.getField())) { + fields.add(fieldInfo.getField()); + } + } else { + fields.add(fieldInfo.getField()); + } } fields = Collections.unmodifiableList(fields); @@ -88,13 +103,22 @@ public class TopScreenModel { } 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(); @@ -197,7 +221,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 02c35b872a2..266166cd746 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; @@ -56,21 +57,38 @@ public class TopScreenPresenter { private final EnumMap fieldDisplayMap = new EnumMap<>(Field.class); private final EnumMap fieldLengthMap = new EnumMap<>(Field.class); + private final long numberOfIterations; + private long iterations; + public TopScreenPresenter(TopScreenView topScreenView, long initialRefreshDelay, - TopScreenModel topScreenModel) { + TopScreenModel topScreenModel, @Nullable List 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; @@ -81,8 +99,7 @@ public class TopScreenPresenter { TerminalSize newTerminalSize = topScreenView.doResizeIfNecessary(); if (newTerminalSize != null) { - terminalLength = newTerminalSize.getColumns(); - paging.updatePageSize(topScreenView.getPageSize()); + updateTerminalLengthAndPageSize(newTerminalSize, topScreenView.getPageSize()); topScreenView.clearTerminal(); } @@ -97,6 +114,7 @@ public class TopScreenPresenter { topScreenView.refreshTerminal(); lastRefreshTimestamp = System.currentTimeMillis(); + iterations++; return refreshDelay.get(); } @@ -260,7 +278,7 @@ public class TopScreenPresenter { } private void switchMode(Mode nextMode) { - topScreenModel.switchMode(nextMode, null, false); + topScreenModel.switchMode(nextMode, false, null); reset(); } @@ -276,18 +294,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 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()); } } @@ -353,4 +375,8 @@ public class TopScreenPresenter { return new FilterDisplayModeScreenView(screen, terminal, row, topScreenModel.getFilters(), 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 6d9348b588d..b24b4dfbf32 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 @@ -25,6 +25,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hbase.classification.InterfaceAudience; 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 initialFields, @Nullable Field initialSortField, + @Nullable Boolean initialAscendingSort, @Nullable List 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
headers, List records, Record selectedRecord) { TerminalPrinter printer = getTerminalPrinter(RECORD_START_ROW); + int size; + if (pageSize != null) { + size = pageSize; + } else { + size = records.size(); + } List 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 8da71afb767..44c77d5507c 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.hadoop.hbase.classification.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 00000000000..19d64260e22 --- /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/impl/batch/BatchTerminalPrinter.java b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java new file mode 100644 index 00000000000..afae5e8ecf8 --- /dev/null +++ b/hbase-hbtop/src/main/java/org/apache/hadoop/hbase/hbtop/terminal/impl/batch/BatchTerminalPrinter.java @@ -0,0 +1,55 @@ +/** + * 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 org.apache.hadoop.hbase.hbtop.terminal.AbstractTerminalPrinter; +import org.apache.hadoop.hbase.hbtop.terminal.TerminalPrinter; + +public class BatchTerminalPrinter extends AbstractTerminalPrinter { + + @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 9dec53586b2..5b6f88432de 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 @@ -56,7 +56,7 @@ public class TestTopScreenModel { @Before public void setup() throws IOException { when(admin.getClusterStatus()).thenReturn(TestUtils.createDummyClusterStatus()); - topScreenModel = new TopScreenModel(admin, Mode.REGION); + topScreenModel = new TopScreenModel(admin, Mode.REGION, null, null, null, null); fields = new ArrayList<>(); for (FieldInfo fieldInfo : Mode.REGION.getFieldInfos()) { @@ -78,17 +78,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()); } @@ -162,7 +162,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 @@ -170,7 +170,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++) { @@ -180,13 +180,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 b16b260eb1d..8bb036eb6cb 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 @@ -94,7 +94,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