HBASE-23969 Meta browser should show all `info` columns (#1485)

Signed-off-by: Nick Dimiduk <ndimiduk@apache.org>
Signed-off-by: Viraj Jasani <vjasani@apache.org>
This commit is contained in:
Mingliang Liu 2020-05-13 11:50:53 -07:00 committed by GitHub
parent a782531633
commit a40a0322a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 208 additions and 110 deletions

View File

@ -384,32 +384,42 @@ 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.*'.
@ -873,8 +883,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));
@ -966,6 +975,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.

View File

@ -493,11 +493,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.

View File

@ -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()))
@ -299,42 +299,6 @@ public class RegionStateStore {
return master.getTableDescriptors().get(tableName);
}
// ==========================================================================
// 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
// ==========================================================================

View File

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

View File

@ -69,6 +69,7 @@
<%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos" %>
<%@ 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.util.stream.Collectors" %>
<%!
/**
* @return An empty region load stamped with the passed in <code>regionInfo</code>
@ -386,69 +387,100 @@ if (fqtn != null && master.isInitialized()) {
<%
}
}
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>
<%
final boolean metaScanHasMore;
byte[] lastRow = null;
try (final MetaBrowser.Results results = metaBrowser.getResults()) {
for (final RegionReplicaInfo regionReplicaInfo : results) {
lastRow = Optional.ofNullable(regionReplicaInfo)
.map(RegionReplicaInfo::getRow)
.orElse(null);
if (regionReplicaInfo == null) {
%>
<tr>
<td colspan="6">Null result</td>
</tr>
<%
continue;
<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;
try (final MetaBrowser.Results results = metaBrowser.getResults()) {
for (final RegionReplicaInfo regionReplicaInfo : results) {
lastRow = Optional.ofNullable(regionReplicaInfo)
.map(RegionReplicaInfo::getRow)
.orElse(null);
if (regionReplicaInfo == null) {
%>
<tr>
<td colspan="6">Null result</td>
</tr>
<%
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 long seqNum = regionReplicaInfo.getSeqNum();
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 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();
}
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);
%>
<tr>
<td><%= regionNameDisplay %></td>
<td><%= startKeyDisplay %></td>
<td><%= endKeyDisplay %></td>
<td><%= replicaIdDisplay %></td>
<td><%= regionStateDisplay %></td>
<td><%= buildRegionServerLink(serverName, rsPort, regionInfo, regionState) %></td>
</tr>
<%
}
metaScanHasMore = results.hasMoreResults();
}
%>
</table>
%>
</table>
</div>
<div class="row">
<div class="col-md-4">
<ul class="pagination" style="margin: 20px 0">

View File

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