HBASE-25258 Backport HBASE-24776 "[hbtop] Support Batch mode" to branch-1 (#3065)

Signed-off-by: stack stack@apache.org
This commit is contained in:
Toshihiro Suzuki 2021-03-20 11:16:26 +09:00 committed by GitHub
parent bea87b30ec
commit f8078009e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 412 additions and 78 deletions

View File

@ -17,6 +17,8 @@
*/ */
package org.apache.hadoop.hbase.hbtop; package org.apache.hadoop.hbase.hbtop;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.apache.commons.cli.BasicParser; 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.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseInterfaceAudience; import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceAudience; 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.mode.Mode;
import org.apache.hadoop.hbase.hbtop.screen.Screen; import org.apache.hadoop.hbase.hbtop.screen.Screen;
import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.Tool;
@ -55,17 +59,14 @@ public class HBTop extends Configured implements Tool {
public int run(String[] args) throws Exception { public int run(String[] args) throws Exception {
long initialRefreshDelay = 3 * 1000; long initialRefreshDelay = 3 * 1000;
Mode initialMode = Mode.REGION; 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 { try {
// Command line options Options opts = 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 (Region)");
CommandLine commandLine = new BasicParser().parse(opts, args); CommandLine commandLine = new BasicParser().parse(opts, args);
if (commandLine.hasOption("help")) { if (commandLine.hasOption("help")) {
@ -73,20 +74,6 @@ public class HBTop extends Configured implements Tool {
return 0; 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")) { if (commandLine.hasOption("mode")) {
String mode = commandLine.getOptionValue("mode"); String mode = commandLine.getOptionValue("mode");
switch (mode) { switch (mode) {
@ -111,18 +98,150 @@ public class HBTop extends Configured implements Tool {
break; 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<Field> 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) { } catch (Exception e) {
LOG.error("Unable to parse options", e); LOG.error("Unable to parse options", e);
return 1; 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(); screen.run();
} }
return 0; 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) { private void printUsage(Options opts) {
new HelpFormatter().printHelp("hbase hbtop [opts] [-D<property=value>]*", opts); new HelpFormatter().printHelp("hbase hbtop [opts] [-D<property=value>]*", opts);
System.out.println(""); System.out.println("");

View File

@ -75,6 +75,7 @@ public abstract class AbstractScreenView implements ScreenView {
return terminal.getTerminalPrinter(startRow); return terminal.getTerminalPrinter(startRow);
} }
@Nullable
protected TerminalSize getTerminalSize() { protected TerminalSize getTerminalSize() {
return terminal.getSize(); return terminal.getSize();
} }

View File

@ -17,8 +17,10 @@
*/ */
package org.apache.hadoop.hbase.hbtop.screen; package org.apache.hadoop.hbase.hbtop.screen;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log; 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.Admin;
import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory; 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.mode.Mode;
import org.apache.hadoop.hbase.hbtop.screen.top.TopScreenView; import org.apache.hadoop.hbase.hbtop.screen.top.TopScreenView;
import org.apache.hadoop.hbase.hbtop.terminal.KeyPress; import org.apache.hadoop.hbase.hbtop.terminal.KeyPress;
import org.apache.hadoop.hbase.hbtop.terminal.Terminal; 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.TerminalImpl;
import org.apache.hadoop.hbase.hbtop.terminal.impl.batch.BatchTerminal;
/** /**
* This dispatches key presses and timers to the current {@link ScreenView}. * This dispatches key presses and timers to the current {@link ScreenView}.
@ -51,15 +56,23 @@ public class Screen implements Closeable {
private ScreenView currentScreenView; private ScreenView currentScreenView;
private Long timerTimestamp; 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 { throws IOException {
connection = ConnectionFactory.createConnection(conf); connection = ConnectionFactory.createConnection(conf);
admin = connection.getAdmin(); admin = connection.getAdmin();
// The first screen is the top screen // 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, currentScreenView = new TopScreenView(this, terminal, initialRefreshDelay, admin,
initialMode); initialMode, initialFields, initialSortField, initialAscendingSort, initialFilters,
numberOfIterations);
} }
@Override @Override
@ -93,11 +106,8 @@ public class Screen implements Closeable {
timerTimestamp = null; timerTimestamp = null;
nextScreenView = currentScreenView.handleTimer(); nextScreenView = currentScreenView.handleTimer();
} else { } else {
if (timerTimestamp - now < SLEEP_TIMEOUT_MILLISECONDS) { TimeUnit.MILLISECONDS
TimeUnit.MILLISECONDS.sleep(timerTimestamp - now); .sleep(Math.min(timerTimestamp - now, SLEEP_TIMEOUT_MILLISECONDS));
} else {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIMEOUT_MILLISECONDS);
}
continue; continue;
} }
} else { } else {

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.hbase.hbtop.screen.top; package org.apache.hadoop.hbase.hbtop.screen.top;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -61,20 +62,34 @@ public class TopScreenModel {
private boolean ascendingSort; 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); 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, public void switchMode(Mode nextMode, boolean keepSortFieldAndSortOrderIfPossible,
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; currentMode = nextMode;
fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos())); fieldInfos = Collections.unmodifiableList(new ArrayList<>(currentMode.getFieldInfos()));
fields = new ArrayList<>(); fields = new ArrayList<>();
for (FieldInfo fieldInfo : currentMode.getFieldInfos()) { 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); fields = Collections.unmodifiableList(fields);
@ -88,13 +103,22 @@ public class TopScreenModel {
} }
if (!match) { 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(); currentSortField = nextMode.getDefaultSortField();
ascendingSort = false; ascendingSort = false;
} }
} else {
currentSortField = nextMode.getDefaultSortField();
ascendingSort = false;
} }
clearFilters(); clearFilters();
@ -197,7 +221,7 @@ public class TopScreenModel {
if (drillDownInfo == null) { if (drillDownInfo == null) {
return false; return false;
} }
switchMode(drillDownInfo.getNextMode(), drillDownInfo.getInitialFilters(), true); switchMode(drillDownInfo.getNextMode(), true, drillDownInfo.getInitialFilters());
return true; return true;
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.hbase.hbtop.screen.top; package org.apache.hadoop.hbase.hbtop.screen.top;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
@ -56,21 +57,38 @@ public class TopScreenPresenter {
private final EnumMap<Field, Boolean> fieldDisplayMap = new EnumMap<>(Field.class); private final EnumMap<Field, Boolean> fieldDisplayMap = new EnumMap<>(Field.class);
private final EnumMap<Field, Integer> fieldLengthMap = 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, public TopScreenPresenter(TopScreenView topScreenView, long initialRefreshDelay,
TopScreenModel topScreenModel) { TopScreenModel topScreenModel, @Nullable List<Field> initialFields, long numberOfIterations) {
this.topScreenView = Objects.requireNonNull(topScreenView); this.topScreenView = Objects.requireNonNull(topScreenView);
this.refreshDelay = new AtomicLong(initialRefreshDelay); this.refreshDelay = new AtomicLong(initialRefreshDelay);
this.topScreenModel = Objects.requireNonNull(topScreenModel); this.topScreenModel = Objects.requireNonNull(topScreenModel);
this.numberOfIterations = numberOfIterations;
initFieldDisplayMapAndFieldLengthMap(); initFieldDisplayMapAndFieldLengthMap(initialFields);
} }
public void init() { public void init() {
terminalLength = topScreenView.getTerminalSize().getColumns(); updateTerminalLengthAndPageSize(topScreenView.getTerminalSize(), topScreenView.getPageSize());
paging.updatePageSize(topScreenView.getPageSize());
topScreenView.hideCursor(); 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) { public long refresh(boolean force) {
if (!force) { if (!force) {
long delay = System.currentTimeMillis() - lastRefreshTimestamp; long delay = System.currentTimeMillis() - lastRefreshTimestamp;
@ -81,8 +99,7 @@ public class TopScreenPresenter {
TerminalSize newTerminalSize = topScreenView.doResizeIfNecessary(); TerminalSize newTerminalSize = topScreenView.doResizeIfNecessary();
if (newTerminalSize != null) { if (newTerminalSize != null) {
terminalLength = newTerminalSize.getColumns(); updateTerminalLengthAndPageSize(newTerminalSize, topScreenView.getPageSize());
paging.updatePageSize(topScreenView.getPageSize());
topScreenView.clearTerminal(); topScreenView.clearTerminal();
} }
@ -97,6 +114,7 @@ public class TopScreenPresenter {
topScreenView.refreshTerminal(); topScreenView.refreshTerminal();
lastRefreshTimestamp = System.currentTimeMillis(); lastRefreshTimestamp = System.currentTimeMillis();
iterations++;
return refreshDelay.get(); return refreshDelay.get();
} }
@ -260,7 +278,7 @@ public class TopScreenPresenter {
} }
private void switchMode(Mode nextMode) { private void switchMode(Mode nextMode) {
topScreenModel.switchMode(nextMode, null, false); topScreenModel.switchMode(nextMode, false, null);
reset(); reset();
} }
@ -276,18 +294,22 @@ public class TopScreenPresenter {
} }
private void reset() { private void reset() {
initFieldDisplayMapAndFieldLengthMap(); initFieldDisplayMapAndFieldLengthMap(null);
adjustFieldLength.set(true); adjustFieldLength.set(true);
paging.init(); paging.init();
horizontalScroll = 0; horizontalScroll = 0;
topScreenView.clearTerminal(); topScreenView.clearTerminal();
} }
private void initFieldDisplayMapAndFieldLengthMap() { private void initFieldDisplayMapAndFieldLengthMap(@Nullable List<Field> initialFields) {
fieldDisplayMap.clear(); fieldDisplayMap.clear();
fieldLengthMap.clear(); fieldLengthMap.clear();
for (FieldInfo fieldInfo : topScreenModel.getFieldInfos()) { 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()); fieldLengthMap.put(fieldInfo.getField(), fieldInfo.getDefaultLength());
} }
} }
@ -353,4 +375,8 @@ public class TopScreenPresenter {
return new FilterDisplayModeScreenView(screen, terminal, row, topScreenModel.getFilters(), return new FilterDisplayModeScreenView(screen, terminal, row, topScreenModel.getFilters(),
topScreenView); topScreenView);
} }
public boolean isIterationFinished() {
return iterations >= numberOfIterations;
}
} }

View File

@ -25,6 +25,8 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.hbtop.Record; 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.mode.Mode;
import org.apache.hadoop.hbase.hbtop.screen.AbstractScreenView; import org.apache.hadoop.hbase.hbtop.screen.AbstractScreenView;
import org.apache.hadoop.hbase.hbtop.screen.Screen; 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 static final int RECORD_START_ROW = 9;
private final TopScreenPresenter topScreenPresenter; private final TopScreenPresenter topScreenPresenter;
private int pageSize; private Integer pageSize;
public TopScreenView(Screen screen, Terminal terminal, long initialRefreshDelay, Admin admin, 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); super(screen, terminal);
this.topScreenPresenter = new TopScreenPresenter(this, initialRefreshDelay, this.topScreenPresenter = new TopScreenPresenter(this, initialRefreshDelay,
new TopScreenModel(admin, initialMode)); new TopScreenModel(admin, initialMode, initialFields, initialSortField,
initialAscendingSort, initialFilters), initialFields, numberOfIterations);
} }
@Override @Override
@ -66,11 +71,12 @@ public class TopScreenView extends AbstractScreenView {
setTimer(delay); setTimer(delay);
} }
@Nullable
@Override @Override
public ScreenView handleTimer() { public ScreenView handleTimer() {
long delay = topScreenPresenter.refresh(false); long delay = topScreenPresenter.refresh(false);
setTimer(delay); setTimer(delay);
return this; return topScreenPresenter.isIterationFinished() ? null : this;
} }
@Nullable @Nullable
@ -79,39 +85,39 @@ public class TopScreenView extends AbstractScreenView {
switch (keyPress.getType()) { switch (keyPress.getType()) {
case Enter: case Enter:
topScreenPresenter.refresh(true); topScreenPresenter.refresh(true);
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case ArrowUp: case ArrowUp:
topScreenPresenter.arrowUp(); topScreenPresenter.arrowUp();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case ArrowDown: case ArrowDown:
topScreenPresenter.arrowDown(); topScreenPresenter.arrowDown();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case ArrowLeft: case ArrowLeft:
topScreenPresenter.arrowLeft(); topScreenPresenter.arrowLeft();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case ArrowRight: case ArrowRight:
topScreenPresenter.arrowRight(); topScreenPresenter.arrowRight();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case PageUp: case PageUp:
topScreenPresenter.pageUp(); topScreenPresenter.pageUp();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case PageDown: case PageDown:
topScreenPresenter.pageDown(); topScreenPresenter.pageDown();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case Home: case Home:
topScreenPresenter.home(); topScreenPresenter.home();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case End: case End:
topScreenPresenter.end(); topScreenPresenter.end();
return this; return topScreenPresenter.isIterationFinished() ? null : this;
case Escape: case Escape:
return null; return null;
@ -182,13 +188,18 @@ public class TopScreenView extends AbstractScreenView {
return this; return this;
} }
@Nullable
@Override @Override
public TerminalSize getTerminalSize() { public TerminalSize getTerminalSize() {
TerminalSize terminalSize = super.getTerminalSize(); TerminalSize terminalSize = super.getTerminalSize();
if (terminalSize == null) {
return null;
}
updatePageSize(terminalSize); updatePageSize(terminalSize);
return terminalSize; return terminalSize;
} }
@Nullable
@Override @Override
public TerminalSize doResizeIfNecessary() { public TerminalSize doResizeIfNecessary() {
TerminalSize terminalSize = super.doResizeIfNecessary(); TerminalSize terminalSize = super.doResizeIfNecessary();
@ -206,7 +217,8 @@ public class TopScreenView extends AbstractScreenView {
} }
} }
public int getPageSize() { @Nullable
public Integer getPageSize() {
return pageSize; return pageSize;
} }
@ -244,8 +256,14 @@ public class TopScreenView extends AbstractScreenView {
private void showRecords(List<Header> headers, List<Record> records, Record selectedRecord) { private void showRecords(List<Header> headers, List<Record> records, Record selectedRecord) {
TerminalPrinter printer = getTerminalPrinter(RECORD_START_ROW); TerminalPrinter printer = getTerminalPrinter(RECORD_START_ROW);
int size;
if (pageSize != null) {
size = pageSize;
} else {
size = records.size();
}
List<String> buf = new ArrayList<>(headers.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()) { if(i < records.size()) {
Record record = records.get(i); Record record = records.get(i);
buf.clear(); buf.clear();

View File

@ -29,7 +29,7 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience;
public interface Terminal extends Closeable { public interface Terminal extends Closeable {
void clear(); void clear();
void refresh(); void refresh();
TerminalSize getSize(); @Nullable TerminalSize getSize();
@Nullable TerminalSize doResizeIfNecessary(); @Nullable TerminalSize doResizeIfNecessary();
@Nullable KeyPress pollKeyPress(); @Nullable KeyPress pollKeyPress();
CursorPosition getCursorPosition(); CursorPosition getCursorPosition();

View File

@ -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() {
}
}

View File

@ -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();
}
}

View File

@ -56,7 +56,7 @@ public class TestTopScreenModel {
@Before @Before
public void setup() throws IOException { public void setup() throws IOException {
when(admin.getClusterStatus()).thenReturn(TestUtils.createDummyClusterStatus()); 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<>(); fields = new ArrayList<>();
for (FieldInfo fieldInfo : Mode.REGION.getFieldInfos()) { for (FieldInfo fieldInfo : Mode.REGION.getFieldInfos()) {
@ -78,17 +78,17 @@ public class TestTopScreenModel {
TestUtils.assertRecordsInRegionMode(topScreenModel.getRecords()); TestUtils.assertRecordsInRegionMode(topScreenModel.getRecords());
// Namespace Mode // Namespace Mode
topScreenModel.switchMode(Mode.NAMESPACE, null, false); topScreenModel.switchMode(Mode.NAMESPACE, false, null);
topScreenModel.refreshMetricsData(); topScreenModel.refreshMetricsData();
TestUtils.assertRecordsInNamespaceMode(topScreenModel.getRecords()); TestUtils.assertRecordsInNamespaceMode(topScreenModel.getRecords());
// Table Mode // Table Mode
topScreenModel.switchMode(Mode.TABLE, null, false); topScreenModel.switchMode(Mode.TABLE, false, null);
topScreenModel.refreshMetricsData(); topScreenModel.refreshMetricsData();
TestUtils.assertRecordsInTableMode(topScreenModel.getRecords()); TestUtils.assertRecordsInTableMode(topScreenModel.getRecords());
// Namespace Mode // Namespace Mode
topScreenModel.switchMode(Mode.REGION_SERVER, null, false); topScreenModel.switchMode(Mode.REGION_SERVER, false, null);
topScreenModel.refreshMetricsData(); topScreenModel.refreshMetricsData();
TestUtils.assertRecordsInRegionServerMode(topScreenModel.getRecords()); TestUtils.assertRecordsInRegionServerMode(topScreenModel.getRecords());
} }
@ -162,7 +162,7 @@ public class TestTopScreenModel {
@Test @Test
public void testSwitchMode() { public void testSwitchMode() {
topScreenModel.switchMode(Mode.TABLE, null, false); topScreenModel.switchMode(Mode.TABLE, false, null);
assertThat(topScreenModel.getCurrentMode(), is(Mode.TABLE)); assertThat(topScreenModel.getCurrentMode(), is(Mode.TABLE));
// Test for initialFilters // Test for initialFilters
@ -170,7 +170,7 @@ public class TestTopScreenModel {
RecordFilter.parse("TABLE==table1", fields, true), RecordFilter.parse("TABLE==table1", fields, true),
RecordFilter.parse("TABLE==table2", 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())); assertThat(topScreenModel.getFilters().size(), is(initialFilters.size()));
for (int i = 0; i < topScreenModel.getFilters().size(); i++) { for (int i = 0; i < topScreenModel.getFilters().size(); i++) {
@ -180,13 +180,13 @@ public class TestTopScreenModel {
// Test when keepSortFieldAndSortOrderIfPossible is true // Test when keepSortFieldAndSortOrderIfPossible is true
topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields); topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields);
topScreenModel.switchMode(Mode.NAMESPACE, null, true); topScreenModel.switchMode(Mode.NAMESPACE, true, null);
assertThat(topScreenModel.getCurrentSortField(), is(Field.NAMESPACE)); assertThat(topScreenModel.getCurrentSortField(), is(Field.NAMESPACE));
} }
@Test @Test
public void testDrillDown() { public void testDrillDown() {
topScreenModel.switchMode(Mode.TABLE, null, false); topScreenModel.switchMode(Mode.TABLE, false, null);
topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields); topScreenModel.setSortFieldAndFields(Field.NAMESPACE, fields);
topScreenModel.refreshMetricsData(); topScreenModel.refreshMetricsData();

View File

@ -94,7 +94,8 @@ public class TestTopScreenPresenter {
when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS); when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS);
when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY); when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY);
topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, topScreenModel); topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, topScreenModel,
null, Long.MAX_VALUE);
} }
@Test @Test