| <%-- |
| /** |
| * 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. |
| */ |
| --%> |
| <%@ page contentType="text/html;charset=UTF-8" |
| import="java.time.Instant" |
| import="java.time.ZoneId" |
| import="java.util.Date" |
| import="java.util.List" |
| import="java.util.Map" |
| import="java.util.stream.Collectors" |
| import="java.time.ZonedDateTime" |
| import="java.time.format.DateTimeFormatter" |
| %> |
| <%@ page import="org.apache.hadoop.fs.Path" %> |
| <%@ page import="org.apache.hadoop.hbase.client.RegionInfo" %> |
| <%@ page import="org.apache.hadoop.hbase.master.HbckChore" %> |
| <%@ page import="org.apache.hadoop.hbase.master.HMaster" %> |
| <%@ page import="org.apache.hadoop.hbase.ServerName" %> |
| <%@ page import="org.apache.hadoop.hbase.util.Bytes" %> |
| <%@ page import="org.apache.hadoop.hbase.util.Pair" %> |
| <%@ page import="org.apache.hadoop.hbase.master.CatalogJanitor" %> |
| <%@ page import="org.apache.hadoop.hbase.master.CatalogJanitor.Report" %> |
| <% |
| HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER); |
| pageContext.setAttribute("pageTitle", "HBase Master HBCK Report: " + master.getServerName()); |
| HbckChore hbckChore = master.getHbckChore(); |
| Map<String, Pair<ServerName, List<ServerName>>> inconsistentRegions = null; |
| Map<String, ServerName> orphanRegionsOnRS = null; |
| Map<String, Path> orphanRegionsOnFS = null; |
| long startTimestamp = 0; |
| long endTimestamp = 0; |
| if (hbckChore != null) { |
| inconsistentRegions = hbckChore.getInconsistentRegions(); |
| orphanRegionsOnRS = hbckChore.getOrphanRegionsOnRS(); |
| orphanRegionsOnFS = hbckChore.getOrphanRegionsOnFS(); |
| startTimestamp = hbckChore.getCheckingStartTimestamp(); |
| endTimestamp = hbckChore.getCheckingEndTimestamp(); |
| } |
| ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(startTimestamp), |
| ZoneId.systemDefault()); |
| String iso8601start = startTimestamp == 0? "-1": zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); |
| zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(endTimestamp), |
| ZoneId.systemDefault()); |
| String iso8601end = startTimestamp == 0? "-1": zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); |
| CatalogJanitor cj = master.getCatalogJanitor(); |
| CatalogJanitor.Report report = cj == null? null: cj.getLastReport(); |
| %> |
| <jsp:include page="header.jsp"> |
| <jsp:param name="pageTitle" value="${pageTitle}"/> |
| </jsp:include> |
| |
| <div class="container-fluid content"> |
| |
| <% if (!master.isInitialized()) { %> |
| <div class="row"> |
| <div class="page-header"> |
| <h1>Master is not initialized</h1> |
| </div> |
| </div> |
| <jsp:include page="redirect.jsp" /> |
| <% } else { %> |
| |
| <div class="row"> |
| <div class="page-header"> |
| <p><span>This page displays two reports: the 'HBCK Chore Report' and the 'CatalogJanitor Consistency Issues' report. Only titles show if there are no problems to report. Note some conditions are transitory as regions migrate.</span></p> |
| </div> |
| </div> |
| <div class="row"> |
| <div class="page-header"> |
| <h1>HBCK Chore Report</h1> |
| <p> |
| <% if (hbckChore.isDisabled()) { %> |
| <span>HBCK chore is currently disabled. Set hbase.master.hbck.chore.interval > 0 in the config & do a rolling-restart to enable it.</span> |
| <% } else if (startTimestamp == 0 && endTimestamp == 0){ %> |
| <span>No report created. Execute <i>hbck_chore_run</i> in hbase shell to generate a new sub-report.</span> |
| <% } else if (startTimestamp > 0 && endTimestamp == 0){ %> |
| <span>Checking started at <%= iso8601start %>. Please wait for checking to generate a new sub-report.</span> |
| <% } else { %> |
| <span>Checking started at <%= iso8601start %> and generated report at <%= iso8601end %>. Execute <i>hbck_chore_run</i> in hbase shell to generate a new sub-report.</span> |
| <% } %> |
| </p> |
| </div> |
| </div> |
| |
| |
| |
| <% if (inconsistentRegions != null && inconsistentRegions.size() > 0) { %> |
| <div class="row"> |
| <div class="page-header"> |
| <h2>Inconsistent Regions</h2> |
| </div> |
| </div> |
| <p> |
| <span> |
| There are three cases: 1. Master thought this region opened, but no regionserver reported it (Fix: use assigns |
| command); 2. Master thought this region opened on Server1, but regionserver reported Server2 (Fix: |
| need to check the server is still exist. If not, schedule SCP for it. If exist, restart Server2 and Server1): |
| 3. More than one regionservers reported opened this region (Fix: restart the RegionServers). |
| Notice: the reported online regionservers may be not right when there are regions in transition. |
| Please check them in regionserver's web UI. |
| </span> |
| </p> |
| |
| <table class="table table-striped"> |
| <tr> |
| <th>Region Encoded Name</th> |
| <th>Location in META</th> |
| <th>Reported Online RegionServers</th> |
| </tr> |
| <% for (Map.Entry<String, Pair<ServerName, List<ServerName>>> entry : inconsistentRegions.entrySet()) { %> |
| <tr> |
| <td><%= entry.getKey() %></td> |
| <td><%= entry.getValue().getFirst() %></td> |
| <td><%= entry.getValue().getSecond().stream().map(ServerName::getServerName) |
| .collect(Collectors.joining(", ")) %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= inconsistentRegions.size() %> region(s) in set.</p> |
| </table> |
| <% } %> |
| |
| <% if (orphanRegionsOnRS != null && orphanRegionsOnRS.size() > 0) { %> |
| <div class="row"> |
| <div class="page-header"> |
| <h2>Orphan Regions on RegionServer</h2> |
| </div> |
| </div> |
| |
| <table class="table table-striped"> |
| <tr> |
| <th>Region Encoded Name</th> |
| <th>Reported Online RegionServer</th> |
| </tr> |
| <% for (Map.Entry<String, ServerName> entry : orphanRegionsOnRS.entrySet()) { %> |
| <tr> |
| <td><%= entry.getKey() %></td> |
| <td><%= entry.getValue() %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= orphanRegionsOnRS.size() %> region(s) in set.</p> |
| </table> |
| <% } %> |
| |
| <% if (orphanRegionsOnFS != null && orphanRegionsOnFS.size() > 0) { %> |
| <div class="row"> |
| <div class="page-header"> |
| <h2>Orphan Regions on FileSystem</h2> |
| </div> |
| </div> |
| |
| <table class="table table-striped"> |
| <tr> |
| <th>Region Encoded Name</th> |
| <th>FileSystem Path</th> |
| </tr> |
| <% for (Map.Entry<String, Path> entry : orphanRegionsOnFS.entrySet()) { %> |
| <tr> |
| <td><%= entry.getKey() %></td> |
| <td><%= entry.getValue() %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= orphanRegionsOnFS.size() %> region(s) in set.</p> |
| </table> |
| <% } %> |
| |
| <% |
| zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), |
| ZoneId.systemDefault()); |
| String iso8601Now = zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); |
| String iso8601reportTime = "-1"; |
| if (report != null) { |
| zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(report.getCreateTime()), |
| ZoneId.systemDefault()); |
| iso8601reportTime = zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); |
| } |
| %> |
| <div class="row inner_header"> |
| <div class="page-header"> |
| <h1>CatalogJanitor <em>hbase:meta</em> Consistency Issues</h1> |
| <p> |
| <% if (report != null) { %> |
| <span>Report created: <%= iso8601reportTime %> (now=<%= iso8601Now %>). Run <i>catalogjanitor_run</i> in hbase shell to generate a new sub-report.</span></p> |
| <% } else { %> |
| <span>No report created. Run <i>catalogjanitor_run</i> in hbase shell to generate a new sub-report.</span> |
| <% } %> |
| </div> |
| </div> |
| <% if (report != null && !report.isEmpty()) { %> |
| <% if (!report.getHoles().isEmpty()) { %> |
| <div class="row inner_header"> |
| <div class="page-header"> |
| <h2>Holes</h2> |
| </div> |
| </div> |
| <table class="table table-striped"> |
| <tr> |
| <th>RegionInfo</th> |
| <th>RegionInfo</th> |
| </tr> |
| <% for (Pair<RegionInfo, RegionInfo> p : report.getHoles()) { %> |
| <tr> |
| <td><%= p.getFirst() %></td> |
| <td><%= p.getSecond() %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= report.getHoles().size() %> hole(s).</p> |
| </table> |
| <% } %> |
| <% if (!report.getOverlaps().isEmpty()) { %> |
| <div class="row inner_header"> |
| <div class="page-header"> |
| <h2>Overlaps</h2> |
| </div> |
| </div> |
| <table class="table table-striped"> |
| <tr> |
| <th>RegionInfo</th> |
| <th>Other RegionInfo</th> |
| </tr> |
| <% for (Pair<RegionInfo, RegionInfo> p : report.getOverlaps()) { %> |
| <tr> |
| <td><%= p.getFirst() %></td> |
| <td><%= p.getSecond() %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= report.getOverlaps().size() %> overlap(s).</p> |
| </table> |
| <% } %> |
| <% if (!report.getUnknownServers().isEmpty()) { %> |
| <div class="row inner_header"> |
| <div class="page-header"> |
| <h2>Unknown Servers</h2> |
| </div> |
| </div> |
| <table class="table table-striped"> |
| <tr> |
| <th>RegionInfo</th> |
| <th>ServerName</th> |
| </tr> |
| <% for (Pair<RegionInfo, ServerName> p: report.getUnknownServers()) { %> |
| <tr> |
| <td><%= p.getFirst() %></td> |
| <td><%= p.getSecond() %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= report.getUnknownServers().size() %> unknown servers(s).</p> |
| </table> |
| <% } %> |
| <% if (!report.getEmptyRegionInfo().isEmpty()) { %> |
| <div class="row inner_header"> |
| <div class="page-header"> |
| <h2>Empty <em>info:regioninfo</em></h2> |
| </div> |
| </div> |
| <table class="table table-striped"> |
| <tr> |
| <th>Row</th> |
| </tr> |
| <% for (byte [] row: report.getEmptyRegionInfo()) { %> |
| <tr> |
| <td><%= Bytes.toStringBinary(row) %></td> |
| </tr> |
| <% } %> |
| |
| <p><%= report.getEmptyRegionInfo().size() %> emptyRegionInfo(s).</p> |
| </table> |
| <% } %> |
| <% } %> |
| |
| <% } %> |
| </div> |
| |
| <jsp:include page="footer.jsp"/> |