This is an automated email from the ASF dual-hosted git repository. ndimiduk 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 5893c4f HBASE-23969 Meta browser should show all `info` columns (#1710) 5893c4f is described below commit 5893c4f393f4ef407e73aa44164d0ff1a7ec2ba6 Author: Mingliang Liu <lium...@apache.org> AuthorDate: Mon May 18 11:48:36 2020 -0700 HBASE-23969 Meta browser should show all `info` columns (#1710) Signed-off-by: Nick Dimiduk <ndimi...@apache.org> Signed-off-by: Viraj Jasani <vjas...@apache.org> --- .../org/apache/hadoop/hbase/MetaTableAccessor.java | 52 +++++++-- .../java/org/apache/hadoop/hbase/HConstants.java | 8 +- .../hbase/master/assignment/RegionStateStore.java | 40 +------ .../hbase/master/webapp/RegionReplicaInfo.java | 60 ++++++++++- .../main/resources/hbase-webapps/master/table.jsp | 116 +++++++++++++-------- .../resources/hbase-webapps/static/css/hbase.css | 4 + 6 files changed, 189 insertions(+), 91 deletions(-) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java index e345483..dd0d1ff 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java @@ -383,33 +383,43 @@ public class MetaTableAccessor { } /** - * @return Deserialized regioninfo values taken from column values that match + * @return Deserialized values of <qualifier,regioninfo> pairs taken from column values that match * the regex 'info:merge.*' in array of <code>cells</code>. */ @Nullable - public static List<RegionInfo> getMergeRegions(Cell [] cells) { + public static Map<String, RegionInfo> getMergeRegionsWithName(Cell [] cells) { if (cells == null) { return null; } - List<RegionInfo> regionsToMerge = null; + Map<String, RegionInfo> regionsToMerge = null; for (Cell cell: cells) { if (!isMergeQualifierPrefix(cell)) { continue; } // Ok. This cell is that of a info:merge* column. RegionInfo ri = RegionInfo.parseFromOrNull(cell.getValueArray(), cell.getValueOffset(), - cell.getValueLength()); + cell.getValueLength()); if (ri != null) { if (regionsToMerge == null) { - regionsToMerge = new ArrayList<>(); + regionsToMerge = new LinkedHashMap<>(); } - regionsToMerge.add(ri); + regionsToMerge.put(Bytes.toString(CellUtil.cloneQualifier(cell)), ri); } } return regionsToMerge; } /** + * @return Deserialized regioninfo values taken from column values that match + * the regex 'info:merge.*' in array of <code>cells</code>. + */ + @Nullable + public static List<RegionInfo> getMergeRegions(Cell [] cells) { + Map<String, RegionInfo> mergeRegionsWithName = getMergeRegionsWithName(cells); + return (mergeRegionsWithName == null) ? null : new ArrayList<>(mergeRegionsWithName.values()); + } + + /** * @return True if any merge regions present in <code>cells</code>; i.e. * the column in <code>cell</code> matches the regex 'info:merge.*'. */ @@ -904,8 +914,7 @@ public class MetaTableAccessor { * @param replicaId the replicaId of the region * @return a byte[] for sn column qualifier */ - @VisibleForTesting - static byte[] getServerNameColumn(int replicaId) { + public static byte[] getServerNameColumn(int replicaId) { return replicaId == 0 ? HConstants.SERVERNAME_QUALIFIER : Bytes.toBytes(HConstants.SERVERNAME_QUALIFIER_STR + META_REPLICA_ID_DELIMITER + String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)); @@ -998,6 +1007,33 @@ public class MetaTableAccessor { } /** + * Returns the {@link ServerName} from catalog table {@link Result} where the region is + * transitioning on. It should be the same as {@link MetaTableAccessor#getServerName(Result,int)} + * if the server is at OPEN state. + * + * @param r Result to pull the transitioning server name from + * @return A ServerName instance or {@link MetaTableAccessor#getServerName(Result,int)} + * if necessary fields not found or empty. + */ + @Nullable + public static ServerName getTargetServerName(final Result r, final int replicaId) { + final Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY, + getServerNameColumn(replicaId)); + if (cell == null || cell.getValueLength() == 0) { + RegionLocations locations = MetaTableAccessor.getRegionLocations(r); + if (locations != null) { + HRegionLocation location = locations.getRegionLocation(replicaId); + if (location != null) { + return location.getServerName(); + } + } + return null; + } + return ServerName.parseServerName(Bytes.toString(cell.getValueArray(), cell.getValueOffset(), + cell.getValueLength())); + } + + /** * The latest seqnum that the server writing to meta observed when opening the region. * E.g. the seqNum when the result of {@link #getServerName(Result, int)} was written. * @param r Result to pull the seqNum from diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java index b8098f4..fdc3532 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java @@ -535,11 +535,15 @@ public final class HConstants { public static final byte [] SERVERNAME_QUALIFIER = Bytes.toBytes(SERVERNAME_QUALIFIER_STR); + /** The lower-half split region column qualifier string. */ + public static final String SPLITA_QUALIFIER_STR = "splitA"; /** The lower-half split region column qualifier */ - public static final byte [] SPLITA_QUALIFIER = Bytes.toBytes("splitA"); + public static final byte [] SPLITA_QUALIFIER = Bytes.toBytes(SPLITA_QUALIFIER_STR); + /** The upper-half split region column qualifier String. */ + public static final String SPLITB_QUALIFIER_STR = "splitB"; /** The upper-half split region column qualifier */ - public static final byte [] SPLITB_QUALIFIER = Bytes.toBytes("splitB"); + public static final byte [] SPLITB_QUALIFIER = Bytes.toBytes(SPLITB_QUALIFIER_STR); /** * Merge qualifier prefix. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java index 808b2e5..c353161 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStateStore.java @@ -134,7 +134,7 @@ public class RegionStateStore { final State state = getRegionState(result, regionInfo); final ServerName lastHost = hrl.getServerName(); - final ServerName regionLocation = getRegionServer(result, replicaId); + ServerName regionLocation = MetaTableAccessor.getTargetServerName(result, replicaId); final long openSeqNum = hrl.getSeqNum(); // TODO: move under trace, now is visible for debugging @@ -199,7 +199,7 @@ public class RegionStateStore { put.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) .setRow(put.getRow()) .setFamily(HConstants.CATALOG_FAMILY) - .setQualifier(getServerNameColumn(replicaId)) + .setQualifier(MetaTableAccessor.getServerNameColumn(replicaId)) .setTimestamp(put.getTimestamp()) .setType(Cell.Type.Put) .setValue(Bytes.toBytes(regionLocation.getServerName())) @@ -300,42 +300,6 @@ public class RegionStateStore { } // ========================================================================== - // Server Name - // ========================================================================== - - /** - * Returns the {@link ServerName} from catalog table {@link Result} - * where the region is transitioning. It should be the same as - * {@link MetaTableAccessor#getServerName(Result,int)} if the server is at OPEN state. - * @param r Result to pull the transitioning server name from - * @return A ServerName instance or {@link MetaTableAccessor#getServerName(Result,int)} - * if necessary fields not found or empty. - */ - static ServerName getRegionServer(final Result r, int replicaId) { - final Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY, - getServerNameColumn(replicaId)); - if (cell == null || cell.getValueLength() == 0) { - RegionLocations locations = MetaTableAccessor.getRegionLocations(r); - if (locations != null) { - HRegionLocation location = locations.getRegionLocation(replicaId); - if (location != null) { - return location.getServerName(); - } - } - return null; - } - return ServerName.parseServerName(Bytes.toString(cell.getValueArray(), - cell.getValueOffset(), cell.getValueLength())); - } - - private static byte[] getServerNameColumn(int replicaId) { - return replicaId == 0 - ? HConstants.SERVERNAME_QUALIFIER - : Bytes.toBytes(HConstants.SERVERNAME_QUALIFIER_STR + META_REPLICA_ID_DELIMITER - + String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)); - } - - // ========================================================================== // Region State // ========================================================================== diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/webapp/RegionReplicaInfo.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/webapp/RegionReplicaInfo.java index 554d49b..3e47d2a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/webapp/RegionReplicaInfo.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/webapp/RegionReplicaInfo.java @@ -18,13 +18,16 @@ package org.apache.hadoop.hbase.master.webapp; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.RegionLocations; @@ -34,6 +37,7 @@ import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.master.assignment.RegionStateStore; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.PairOfSameType; import org.apache.yetus.audience.InterfaceAudience; /** @@ -45,6 +49,11 @@ public final class RegionReplicaInfo { private final RegionInfo regionInfo; private final RegionState.State regionState; private final ServerName serverName; + private final long seqNum; + /** See {@link org.apache.hadoop.hbase.HConstants#SERVERNAME_QUALIFIER_STR}. */ + private final ServerName targetServerName; + private final Map<String, RegionInfo> mergeRegionInfo; + private final Map<String, RegionInfo> splitRegionInfo; private RegionReplicaInfo(final Result result, final HRegionLocation location) { this.row = result != null ? result.getRow() : null; @@ -53,6 +62,26 @@ public final class RegionReplicaInfo { ? RegionStateStore.getRegionState(result, regionInfo) : null; this.serverName = location != null ? location.getServerName() : null; + this.seqNum = (location != null) ? location.getSeqNum() : HConstants.NO_SEQNUM; + this.targetServerName = (result != null && regionInfo != null) + ? MetaTableAccessor.getTargetServerName(result, regionInfo.getReplicaId()) + : null; + this.mergeRegionInfo = (result != null) + ? MetaTableAccessor.getMergeRegionsWithName(result.rawCells()) + : null; + + if (result != null) { + PairOfSameType<RegionInfo> daughterRegions = MetaTableAccessor.getDaughterRegions(result); + this.splitRegionInfo = new LinkedHashMap<>(); + if (daughterRegions.getFirst() != null) { + splitRegionInfo.put(HConstants.SPLITA_QUALIFIER_STR, daughterRegions.getFirst()); + } + if (daughterRegions.getSecond() != null) { + splitRegionInfo.put(HConstants.SPLITB_QUALIFIER_STR, daughterRegions.getSecond()); + } + } else { + this.splitRegionInfo = null; + } } public static List<RegionReplicaInfo> from(final Result result) { @@ -102,6 +131,22 @@ public final class RegionReplicaInfo { return serverName; } + public long getSeqNum() { + return seqNum; + } + + public ServerName getTargetServerName() { + return targetServerName; + } + + public Map<String, RegionInfo> getMergeRegionInfo() { + return mergeRegionInfo; + } + + public Map<String, RegionInfo> getSplitRegionInfo() { + return splitRegionInfo; + } + @Override public boolean equals(Object other) { if (this == other) { @@ -119,6 +164,10 @@ public final class RegionReplicaInfo { .append(regionInfo, that.regionInfo) .append(regionState, that.regionState) .append(serverName, that.serverName) + .append(seqNum, that.seqNum) + .append(targetServerName, that.targetServerName) + .append(mergeRegionInfo, that.mergeRegionInfo) + .append(splitRegionInfo, that.splitRegionInfo) .isEquals(); } @@ -129,15 +178,24 @@ public final class RegionReplicaInfo { .append(regionInfo) .append(regionState) .append(serverName) + .append(seqNum) + .append(targetServerName) + .append(mergeRegionInfo) + .append(splitRegionInfo) .toHashCode(); } - @Override public String toString() { + @Override + public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append("row", Bytes.toStringBinary(row)) .append("regionInfo", regionInfo) .append("regionState", regionState) .append("serverName", serverName) + .append("seqNum", seqNum) + .append("transitioningOnServerName", targetServerName) + .append("merge*", mergeRegionInfo) + .append("split*", splitRegionInfo) .toString(); } } diff --git a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp index 5a40139..8f9673c 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp @@ -70,6 +70,7 @@ <%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas" %> <%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota" %> <%@ page import="java.net.URLEncoder" %> +<%@ page import="java.util.stream.Collectors" %> <%! /** * @return An empty region load stamped with the passed in <code>regionInfo</code> @@ -385,16 +386,27 @@ <% } } + + String regionInfoColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.REGIONINFO_QUALIFIER_STR; + String serverColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SERVER_QUALIFIER_STR; + String startCodeColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.STARTCODE_QUALIFIER_STR; + String serverNameColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SERVERNAME_QUALIFIER_STR; + String seqNumColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SEQNUM_QUALIFIER_STR; %> - <table class="table table-striped"> - <tr> - <th>RegionName</th> - <th>Start Key</th> - <th>End Key</th> - <th>Replica ID</th> - <th>RegionState</th> - <th>ServerName</th> - </tr> + <div style="overflow-x: auto"> + <table class="table table-striped nowrap"> + <tr> + <th title="Region name, stored in <%= regionInfoColumnName %> column">RegionName</th> + <th title="The startKey of this region">Start Key</th> + <th title="The endKey of this region">End Key</th> + <th title="Region replica id">Replica ID</th> + <th title="State of the region while undergoing transitions">RegionState</th> + <th title="Server hosting this region replica, stored in <%= serverColumnName %> column">Server</th> + <th title="The seqNum for the region at the time the server opened this region replica, stored in <%= seqNumColumnName %>">Sequence Number</th> + <th title="The server to which the region is transiting, stored in <%= serverNameColumnName %> column">Target Server</th> + <th title="The parents regions if this region is undergoing a merge">info:merge*</th> + <th title="The daughter regions if this region is split">info:split*</th> + </tr> <% final boolean metaScanHasMore; byte[] lastRow = null; @@ -405,49 +417,69 @@ .orElse(null); if (regionReplicaInfo == null) { %> - <tr> - <td colspan="6">Null result</td> - </tr> + <tr> + <td colspan="6">Null result</td> + </tr> <% - continue; - } + continue; + } + + final String regionNameDisplay = regionReplicaInfo.getRegionName() != null + ? Bytes.toStringBinary(regionReplicaInfo.getRegionName()) + : ""; + final String startKeyDisplay = regionReplicaInfo.getStartKey() != null + ? Bytes.toStringBinary(regionReplicaInfo.getStartKey()) + : ""; + final String endKeyDisplay = regionReplicaInfo.getEndKey() != null + ? Bytes.toStringBinary(regionReplicaInfo.getEndKey()) + : ""; + final String replicaIdDisplay = regionReplicaInfo.getReplicaId() != null + ? regionReplicaInfo.getReplicaId().toString() + : ""; + final String regionStateDisplay = regionReplicaInfo.getRegionState() != null + ? regionReplicaInfo.getRegionState().toString() + : ""; + + final RegionInfo regionInfo = regionReplicaInfo.getRegionInfo(); + final ServerName serverName = regionReplicaInfo.getServerName(); + final RegionState.State regionState = regionReplicaInfo.getRegionState(); + final int rsPort = master.getRegionServerInfoPort(serverName); - final String regionNameDisplay = regionReplicaInfo.getRegionName() != null - ? Bytes.toStringBinary(regionReplicaInfo.getRegionName()) - : ""; - final String startKeyDisplay = regionReplicaInfo.getStartKey() != null - ? Bytes.toStringBinary(regionReplicaInfo.getStartKey()) - : ""; - final String endKeyDisplay = regionReplicaInfo.getEndKey() != null - ? Bytes.toStringBinary(regionReplicaInfo.getEndKey()) - : ""; - final String replicaIdDisplay = regionReplicaInfo.getReplicaId() != null - ? regionReplicaInfo.getReplicaId().toString() - : ""; - final String regionStateDisplay = regionReplicaInfo.getRegionState() != null - ? regionReplicaInfo.getRegionState().toString() - : ""; + final long seqNum = regionReplicaInfo.getSeqNum(); - final RegionInfo regionInfo = regionReplicaInfo.getRegionInfo(); - final ServerName serverName = regionReplicaInfo.getServerName(); - final RegionState.State regionState = regionReplicaInfo.getRegionState(); - final int rsPort = master.getRegionServerInfoPort(serverName); + final String regionSpanFormat = "<span title=" + HConstants.CATALOG_FAMILY_STR + ":%s>%s</span>"; + final String targetServerName = regionReplicaInfo.getTargetServerName().toString(); + final Map<String, RegionInfo> mergeRegions = regionReplicaInfo.getMergeRegionInfo(); + final String mergeRegionNames = (mergeRegions == null) ? "" : + mergeRegions.entrySet().stream() + .map(entry -> String.format(regionSpanFormat, entry.getKey(), entry.getValue().getRegionNameAsString())) + .collect(Collectors.joining("<br/>")); + final Map<String, RegionInfo> splitRegions = regionReplicaInfo.getSplitRegionInfo(); + final String splitName = (splitRegions == null) ? "" : + splitRegions.entrySet().stream() + .map(entry -> String.format(regionSpanFormat, entry.getKey(), entry.getValue().getRegionNameAsString())) + .collect(Collectors.joining("<br/>")); %> - <tr> - <td><%= regionNameDisplay %></td> - <td><%= startKeyDisplay %></td> - <td><%= endKeyDisplay %></td> - <td><%= replicaIdDisplay %></td> - <td><%= regionStateDisplay %></td> - <td><%= buildRegionServerLink(serverName, rsPort, regionInfo, regionState) %></td> - </tr> + <tr> + <td title="<%= regionInfoColumnName %>"><%= regionNameDisplay %></td> + <td title="startKey"><%= startKeyDisplay %></td> + <td title="endKey"><%= endKeyDisplay %></td> + <td title="replicaId"><%= replicaIdDisplay %></td> + <td title="regionState"><%= regionStateDisplay %></td> + <td title="<%= serverColumnName + "," + startCodeColumnName %>"><%= buildRegionServerLink(serverName, rsPort, regionInfo, regionState) %></td> + <td title="<%= seqNumColumnName %>"><%= seqNum %></td> + <td title="<%= serverNameColumnName %>"><%= targetServerName %></td> + <td><%= mergeRegionNames %></td> + <td><%= splitName %></td> + </tr> <% } metaScanHasMore = results.hasMoreResults(); } %> - </table> + </table> + </div> <div class="row"> <div class="col-md-4"> <ul class="pagination" style="margin: 20px 0"> diff --git a/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css b/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css index 04eb496..182f2ae 100644 --- a/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css +++ b/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css @@ -54,3 +54,7 @@ table.tablesorter thead tr .headerSortUp { table.tablesorter thead tr .headerSortDown { background-image: url(desc.gif); } + +table.nowrap th, table.nowrap td { + white-space: nowrap; +}