You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by nd...@apache.org on 2020/05/18 19:00:20 UTC

[hbase] branch branch-2.3 updated: HBASE-23969 Meta browser should show all `info` columns (#1710)

This is an automated email from the ASF dual-hosted git repository.

ndimiduk pushed a commit to branch branch-2.3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2.3 by this push:
     new 36a8e85  HBASE-23969 Meta browser should show all `info` columns (#1710)
36a8e85 is described below

commit 36a8e858db3b02eeb2752443ebfb9953eba22d1a
Author: Mingliang Liu <li...@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 <nd...@apache.org>
    Signed-off-by: Viraj Jasani <vj...@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;
+}