You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by pa...@apache.org on 2025/11/24 13:37:03 UTC
(hbase) 01/03: HBASE-29223 Migrate Master Status Jamon page back to JSP (#6875)
This is an automated email from the ASF dual-hosted git repository.
paksyd pushed a commit to branch HBASE-29223-jamon-jsp-MasterStatus-branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git
commit c3ef85df585fc6dfd63fc005c5512290f1ea6f9b
Author: Dávid Paksy <pa...@apache.org>
AuthorDate: Wed Oct 8 13:16:33 2025 +0200
HBASE-29223 Migrate Master Status Jamon page back to JSP (#6875)
The JSP code is equivalent to the Jamon code, just changed the syntax back to JSP.
Request attributes are used to transfer data between JSP pages.
Tried to preserve the code as much as possible but did some changes:
Sub-templates were usually extracted to separate JSP file (and included with `<jsp:include`), in some case it was extracted as Java method.
Extracted some sections from master page to separate JSP pages:
- Software Attributes
- Warnings
Extracted the long JavaScript from the master page which executes on page load to separate JS file.
Extracted some frequently used static methods to a new util class: `MasterStatusUtil`. Also added unit tests for the static methods in `MasterStatusUtil`.
Changed the Master Status page back to `/master.jsp` again. Now made sure that `/master-status` redirects to `/master.jsp`.
Signed-off-by: Istvan Toth <st...@apache.org>
(cherry picked from commit be400115fb8bec896f4ff1bc048b2ff63a05b49d)
---
.../tmpl/master/AssignmentManagerStatusTmpl.jamon | 128 ----
.../hbase/tmpl/master/BackupMasterStatusTmpl.jamon | 70 --
.../hbase/tmpl/master/MasterStatusTmpl.jamon | 808 ---------------------
.../hadoop/hbase/tmpl/master/RSGroupListTmpl.jamon | 393 ----------
.../hbase/tmpl/master/RegionServerListTmpl.jamon | 545 --------------
.../hbase/tmpl/master/RegionVisualizerTmpl.jamon | 119 ---
.../hbase/tmpl/regionserver/RSStatusTmpl.jamon | 2 +-
.../hbase/master/http/MasterStatusConstants.java} | 28 +-
.../hbase/master/http/MasterStatusServlet.java | 62 +-
...terStatusServlet.java => MasterStatusUtil.java} | 78 +-
.../hadoop/hbase/master/http/RegionVisualizer.java | 2 +-
.../master/assignmentManagerStatus.jsp | 117 +++
.../hbase-webapps/master/backupMasterStatus.jsp | 66 ++
.../hbase-webapps/master/catalogTables.jsp | 84 +++
.../hbase-webapps/master/deadRegionServers.jsp | 96 +++
.../main/resources/hbase-webapps/master/header.jsp | 4 +-
.../main/resources/hbase-webapps/master/index.html | 2 +-
.../main/resources/hbase-webapps/master/master.jsp | 144 +++-
.../resources/hbase-webapps/master/peerConfigs.jsp | 82 +++
.../hbase-webapps/master/regionServerList.jsp | 90 +++
.../master/regionServerListBaseStats.jsp | 134 ++++
.../master/regionServerListCompactionStats.jsp | 78 ++
.../{master.jsp => regionServerListEmptyStat.jsp} | 20 +-
.../master/regionServerListMemoryStats.jsp | 90 +++
.../master/regionServerListReplicationStats.jsp | 90 +++
.../master/regionServerListRequestStats.jsp | 75 ++
.../master/regionServerListStoreStats.jsp | 108 +++
.../hbase-webapps/master/regionVisualizer.jsp | 120 +++
.../main/resources/hbase-webapps/master/rits.jsp | 6 +-
.../resources/hbase-webapps/master/rsGroupList.jsp | 79 ++
.../hbase-webapps/master/rsGroupListBaseStats.jsp | 101 +++
.../master/rsGroupListCompactStats.jsp | 73 ++
.../master/rsGroupListMemoryStats.jsp | 85 +++
.../master/rsGroupListRequestStats.jsp | 66 ++
.../hbase-webapps/master/rsGroupListStoreStats.jsp | 102 +++
.../hbase-webapps/master/softwareAttributes.jsp | 173 +++++
.../hbase-webapps/master/tablesDetailed.jsp | 9 +-
.../resources/hbase-webapps/master/taskMonitor.jsp | 90 +++
.../master/taskMonitorRenderTasks.jsp | 87 +++
.../resources/hbase-webapps/master/userTables.jsp | 117 +++
.../resources/hbase-webapps/master/warnings.jsp | 86 +++
.../hbase-webapps/static/js/masterStatusInit.js | 126 ++++
.../org/apache/hadoop/hbase/TestInfoServers.java | 5 +-
.../hbase/master/http/TestMasterStatusPage.java | 186 +++++
.../hbase/master/http/TestMasterStatusServlet.java | 159 ----
.../hbase/master/http/TestMasterStatusUtil.java | 255 +++++++
46 files changed, 3095 insertions(+), 2345 deletions(-)
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/AssignmentManagerStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/AssignmentManagerStatusTmpl.jamon
deleted file mode 100644
index ee899a7340d..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/AssignmentManagerStatusTmpl.jamon
+++ /dev/null
@@ -1,128 +0,0 @@
-<%doc>
-
-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.
-</%doc>
-<%import>
-java.util.Map;
-java.util.Set;
-java.util.SortedSet;
-java.util.concurrent.atomic.AtomicInteger;
-java.util.stream.Collectors;
-org.apache.hadoop.conf.Configuration;
-org.apache.hadoop.hbase.HBaseConfiguration;
-org.apache.hadoop.hbase.HConstants;
-org.apache.hadoop.hbase.ServerName;
-org.apache.hadoop.hbase.client.RegionInfo;
-org.apache.hadoop.hbase.client.RegionInfoDisplay;
-org.apache.hadoop.hbase.master.RegionState;
-org.apache.hadoop.hbase.master.assignment.AssignmentManager;
-org.apache.hadoop.hbase.master.assignment.AssignmentManager.RegionInTransitionStat;
-org.apache.hadoop.hbase.master.assignment.RegionStates.RegionFailedOpen;
-org.apache.hadoop.hbase.util.Pair;
-</%import>
-<%args>
-AssignmentManager assignmentManager;
-int limit = 100;
-</%args>
-
-<%java>
-SortedSet<RegionState> rit = assignmentManager.getRegionStates()
- .getRegionsInTransitionOrderedByTimestamp();
-</%java>
-
-<%if !rit.isEmpty() %>
-<%java>
-long currentTime = System.currentTimeMillis();
-RegionInTransitionStat ritStat = assignmentManager.computeRegionInTransitionStat();
-
-int numOfRITs = rit.size();
-int ritsPerPage = Math.min(5, numOfRITs);
-int numOfPages = (int) Math.ceil(numOfRITs * 1.0 / ritsPerPage);
-</%java>
- <section>
- <h2><a name="rit">Regions in Transition</a></h2>
- <p><a href="/rits.jsp"><% numOfRITs %> region(s) in transition.</a>
- <%if ritStat.hasRegionsTwiceOverThreshold() %>
- <span class="label label-danger" style="font-size:100%;font-weight:normal">
- <%elseif ritStat.hasRegionsOverThreshold() %>
- <span class="label label-warning" style="font-size:100%;font-weight:normal">
- <%else>
- <span>
- </%if>
- <% ritStat.getTotalRITsOverThreshold() %> region(s) in transition for
- more than <% ritStat.getRITThreshold() %> milliseconds.
- </span>
- </p>
- <div class="tabbable">
- <div class="tab-content">
- <%java int recordItr = 0; %>
- <%for RegionState rs : rit %>
- <%if (recordItr % ritsPerPage) == 0 %>
- <%if recordItr == 0 %>
- <div class="tab-pane active" id="tab_rits<% (recordItr / ritsPerPage) + 1 %>">
- <%else>
- <div class="tab-pane" id="tab_rits<% (recordItr / ritsPerPage) + 1 %>">
- </%if>
- <table class="table table-striped" style="margin-bottom:0px;"><tr><th>Region</th>
- <th>State</th><th>RIT time (ms)</th> <th>Retries </th></tr>
- </%if>
-
- <%if ritStat.isRegionTwiceOverThreshold(rs.getRegion()) %>
- <tr class="alert alert-danger" role="alert">
- <%elseif ritStat.isRegionOverThreshold(rs.getRegion()) %>
- <tr class="alert alert-warning" role="alert">
- <%else>
- <tr>
- </%if>
- <%java>
- String retryStatus = "0";
- RegionFailedOpen regionFailedOpen = assignmentManager
- .getRegionStates().getFailedOpen(rs.getRegion());
- if (regionFailedOpen != null) {
- retryStatus = Integer.toString(regionFailedOpen.getRetries());
- } else if (rs.getState() == RegionState.State.FAILED_OPEN) {
- retryStatus = "Failed";
- }
- </%java>
- <td><% rs.getRegion().getEncodedName() %></td><td>
- <% RegionInfoDisplay.getDescriptiveNameFromRegionStateForDisplay(rs,
- assignmentManager.getConfiguration()) %></td>
- <td><% (currentTime - rs.getStamp()) %> </td>
- <td> <% retryStatus %> </td>
- </tr>
- <%java recordItr++; %>
- <%if (recordItr % ritsPerPage) == 0 %>
- </table>
- </div>
- </%if>
- </%for>
-
- <%if (recordItr % ritsPerPage) != 0 %>
- <%for ; (recordItr % ritsPerPage) != 0 ; recordItr++ %>
- <tr><td colspan="3" style="height:61px"></td></tr>
- </%for>
- </table>
- </div>
- </%if>
- </div>
- <input type="hidden" id ="rit_page_num" value="<% numOfRITs %>" />
- <input type="hidden" id ="rit_per_page" value="<% ritsPerPage %>" />
- <nav id="rit_pagination"></nav>
- </div>
- </section>
- </%if>
-
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/BackupMasterStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/BackupMasterStatusTmpl.jamon
deleted file mode 100644
index 21af264bbe3..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/BackupMasterStatusTmpl.jamon
+++ /dev/null
@@ -1,70 +0,0 @@
-<%doc>
-
-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.
-</%doc>
-<%args>
-HMaster master;
-</%args>
-<%import>
-java.util.*;
-org.apache.hadoop.hbase.ServerName;
-org.apache.hadoop.hbase.ClusterMetrics;
-org.apache.hadoop.hbase.master.HMaster;
-org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
-</%import>
-<%if (!master.isActiveMaster()) %>
- <%java>
- ServerName active_master = master.getActiveMaster().orElse(null);
- Preconditions.checkState(active_master != null, "Failed to retrieve active master's ServerName!");
- int activeInfoPort = master.getActiveMasterInfoPort();
- </%java>
- <div class="row inner_header">
- <div class="page-header">
- <h1>Backup Master <small><% master.getServerName().getHostname() %></small></h1>
- </div>
- </div>
- <h4>Current Active Master: <a href="//<% active_master.getHostname() %>:<% activeInfoPort %>/master-status"
- target="_blank"><% active_master.getHostname() %></a><h4>
-<%else>
- <h2>Backup Masters</h2>
-
- <table class="table table-striped">
- <tr>
- <th>ServerName</th>
- <th>Port</th>
- <th>Start Time</th>
- </tr>
- <%java>
- Collection<ServerName> backup_masters = master.getBackupMasters();
- ServerName [] backupServerNames = backup_masters.toArray(new ServerName[backup_masters.size()]);
- Arrays.sort(backupServerNames);
- for (ServerName serverName : backupServerNames) {
- int infoPort = master.getBackupMasterInfoPort(serverName);
- </%java>
- <tr>
- <td><a href="//<% serverName.getHostname() %>:<% infoPort %>/master-status"
- target="_blank"><% serverName.getHostname() %></a>
- </td>
- <td><% serverName.getPort() %></td>
- <td><% new Date(serverName.getStartcode()) %></td>
- </tr>
- <%java>
- }
- </%java>
- <tr><td>Total:<% backupServerNames.length %></td>
- </table>
-</%if>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon
deleted file mode 100644
index d1b3f8719d2..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon
+++ /dev/null
@@ -1,808 +0,0 @@
-<%doc>
-
-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.
-</%doc>
-<%args>
-HMaster master;
-Map<String, Integer> frags = null;
-ServerName metaLocation = null;
-List<ServerName> servers = null;
-Set<ServerName> deadServers = null;
-boolean catalogJanitorEnabled = true;
-String filter = "general";
-String format = "html";
-ServerManager serverManager = null;
-AssignmentManager assignmentManager = null;
-</%args>
-<%import>
-java.util.*;
-java.net.URLEncoder;
-java.io.IOException;
-org.apache.hadoop.hbase.client.replication.ReplicationPeerConfigUtil;
-org.apache.hadoop.hbase.client.RegionInfo;
-org.apache.hadoop.hbase.client.TableDescriptor;
-org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
-org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
-org.apache.hadoop.hbase.HBaseConfiguration;
-org.apache.hadoop.hbase.HConstants;
-org.apache.hadoop.hbase.HTableDescriptor;
-org.apache.hadoop.hbase.NamespaceDescriptor;
-org.apache.hadoop.hbase.ServerName;
-org.apache.hadoop.hbase.TableName;
-org.apache.hadoop.hbase.RSGroupTableAccessor;
-org.apache.hadoop.hbase.client.Admin;
-org.apache.hadoop.hbase.client.MasterSwitchType;
-org.apache.hadoop.hbase.client.TableState;
-org.apache.hadoop.hbase.master.assignment.AssignmentManager;
-org.apache.hadoop.hbase.master.DeadServer;
-org.apache.hadoop.hbase.master.HMaster;
-org.apache.hadoop.hbase.master.RegionState;
-org.apache.hadoop.hbase.master.ServerManager;
-org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
-org.apache.hadoop.hbase.protobuf.ProtobufUtil;
-org.apache.hadoop.hbase.quotas.QuotaUtil;
-org.apache.hadoop.hbase.security.access.PermissionStorage;
-org.apache.hadoop.hbase.security.visibility.VisibilityConstants;
-org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription;
-org.apache.hadoop.hbase.tool.CanaryTool;
-org.apache.hadoop.hbase.util.Bytes;
-org.apache.hadoop.hbase.util.CommonFSUtils;
-org.apache.hadoop.hbase.util.JvmVersion;
-org.apache.hadoop.hbase.util.PrettyPrinter;
-org.apache.hadoop.util.StringUtils;
-org.apache.hadoop.hbase.util.Strings;
-</%import>
-
-<%if format.equals("json") %>
- <& ../common/TaskMonitorTmpl; filter = filter; format = "json" &>
- <%java return; %>
-</%if>
-<%java>
-ServerManager serverManager = master.getServerManager();
-AssignmentManager assignmentManager = master.getAssignmentManager();
-</%java>
-
-<%class>
- public String formatZKString() {
- StringBuilder quorums = new StringBuilder();
- String zkQuorum = master.getZooKeeper().getQuorum();
-
- if (null == zkQuorum) {
- return quorums.toString();
- }
-
- String[] zks = zkQuorum.split(",");
-
- if (zks.length == 0) {
- return quorums.toString();
- }
-
- for(int i = 0; i < zks.length; ++i) {
- quorums.append(zks[i].trim());
-
- if (i != (zks.length - 1)) {
- quorums.append("<br/>");
- }
- }
-
- return quorums.toString();
- }
-</%class>
-
-<%class>
- public static String getUserTables(HMaster master, List<TableDescriptor> tables){
- if (master.isInitialized()){
- try {
- Map<String, TableDescriptor> descriptorMap = master.getTableDescriptors().getAll();
- if (descriptorMap != null) {
- for (TableDescriptor desc : descriptorMap.values()) {
- if (!desc.getTableName().isSystemTable()) {
- tables.add(desc);
- }
- }
- }
- } catch (IOException e) {
- return "Got user tables error, " + e.getMessage();
- }
- }
- return null;
- }
-</%class>
-
-<!DOCTYPE html>
-<?xml version="1.0" encoding="UTF-8" ?>
-<html lang="en">
- <head>
- <meta charset="utf-8">
- <title><%if master.isActiveMaster() %>Master: <%else>Backup Master: </%if>
- <% master.getServerName().getHostname() %></title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta name="description" content="">
- <link href="/static/css/bootstrap.min.css" rel="stylesheet">
- <link href="/static/css/hbase.css" rel="stylesheet">
- <link rel="shortcut icon" href="/static/favicon.ico">
- </head>
-
- <body>
-
- <nav class="navbar navbar-expand-md navbar-light fixed-top bg-light">
- <div class="container-fluid">
- <a class="navbar-brand" href="/master-status"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a>
- <button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
- <span class="navbar-toggler-icon"></span>
- </button>
- <div class="collapse navbar-collapse">
- <ul class="navbar-nav">
- <li class="nav-item">
- <a class="nav-link active" href="/master-status">Home</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="/tablesDetailed.jsp">Table Details</a>
- </li>
- <%if master.isActiveMaster() %>
- <li class="nav-item"><a class="nav-link" href="/procedures.jsp">Procedures & Locks</a></li>
- <li class="nav-item"><a class="nav-link" href="/hbck.jsp">HBCK Report</a></li>
- <li class="nav-item"><a class="nav-link" href="/operationDetails.jsp">Operation Details</a></li>
- <%if master.getConfiguration().getBoolean(QuotaUtil.QUOTA_CONF_KEY, false) %>
- <li class="nav-item"><a class="nav-link" href="/quotas.jsp">Quotas</a></li>
- </%if>
- </%if>
- <li class="nav-item"><a class="nav-link" href="/processMaster.jsp">Process Metrics</a></li>
- <li class="nav-item"><a class="nav-link" href="/logs/">Local Logs</a></li>
- <li class="nav-item"><a class="nav-link" href="/logLevel">Log Level</a></li>
- <li class="nav-item"><a class="nav-link" href="/dump">Debug Dump</a></li>
- <li class="nav-item dropdown">
- <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
- Metrics <span class="caret"></span>
- </a>
- <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
- <a class="dropdown-item" target="_blank" href="/jmx">JMX</a>
- <a class="dropdown-item" target="_blank" href="/jmx?description=true">JMX with description</a>
- <a class="dropdown-item" target="_blank" href="/prometheus">Prometheus</a>
- <a class="dropdown-item" target="_blank" href="/prometheus?description=true">Prometheus with description</a>
- </div>
- </li>
- <li class="nav-item"><a class="nav-link" href="/prof">Profiler</a></li>
- <%if HBaseConfiguration.isShowConfInServlet()%>
- <li class="nav-item"><a class="nav-link" href="/conf">HBase Configuration</a></li>
- </%if>
- <li class="nav-item"><a class="nav-link" href="/startupProgress.jsp">Startup Progress</a></li>
- </ul>
- </div><!--/.navbar-collapse -->
- </div><!--/.container-fluid -->
- </nav>
-
- <div class="container-fluid content">
- <%if master.isActiveMaster() %>
- <div class="row inner_header top_header">
- <div class="page-header">
- <h1>Master <small><% master.getServerName().getHostname() %></small></h1>
- </div>
- </div>
-
- <div class="row">
- <!-- Various warnings that cluster admins should be aware of -->
- <%if JvmVersion.isBadJvmVersion() %>
- <div class="alert alert-danger" role="alert">
- Your current JVM version <% System.getProperty("java.version") %> is known to be
- unstable with HBase. Please see the
- <a href="http://hbase.apache.org/book.html#trouble.log.gc">HBase Reference Guide</a>
- for details.
- </div>
- </%if>
- <%if master.isInitialized() && !catalogJanitorEnabled %>
- <div class="alert alert-danger" role="alert">
- Please note that your cluster is running with the CatalogJanitor disabled. It can be
- re-enabled from the hbase shell by running the command 'catalogjanitor_switch true'
- </div>
- </%if>
- <%if master.isInMaintenanceMode() %>
- <div class="alert alert-warning" role="alert">
- Your Master is in maintenance mode. This is because hbase.master.maintenance_mode is
- set to true. Under the maintenance mode, no quota or no Master coprocessor is loaded.
- </div>
- </%if>
- <%if !master.isBalancerOn() %>
- <div class="alert alert-warning" role="alert">
- The Load Balancer is not enabled which will eventually cause performance degradation
- in HBase as Regions will not be distributed across all RegionServers. The balancer
- is only expected to be disabled during rolling upgrade scenarios.
- </div>
- </%if>
- <%if !master.isSplitOrMergeEnabled(MasterSwitchType.SPLIT) %>
- <div class="alert alert-warning" role="alert">
- Region splits are disabled. This may be the result of HBCK aborting while
- running in repair mode. Manually enable splits from the HBase shell,
- or re-run HBCK in repair mode.
- </div>
- </%if>
- <%if !master.isSplitOrMergeEnabled(MasterSwitchType.MERGE) %>
- <div class="alert alert-warning" role="alert">
- Region merges are disabled. This may be the result of HBCK aborting while
- running in repair mode. Manually enable merges from the HBase shell,
- or re-run HBCK in repair mode.
- </div>
- </%if>
- <%if master.getAssignmentManager() != null %>
- <& AssignmentManagerStatusTmpl; assignmentManager=master.getAssignmentManager()&>
- </%if>
- <%if !master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null %>
- <%if master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null &&
- serverManager.getOnlineServersList().size() > 0 %>
- <section>
- <h2><a name="rsgroup">RSGroup</a></h2>
- <& RSGroupListTmpl; master= master; serverManager= serverManager&>
- </section>
- </%if>
- </%if>
- </div>
- <div class="row">
- <section>
- <h2><a name="regionservers">Region Servers</a></h2>
- <& RegionServerListTmpl; master= master; servers = servers &>
-
- <%if (deadServers != null) %>
- <& deadRegionServers &>
- </%if>
- </section>
- </div>
- <div class="row">
- <section>
- <& BackupMasterStatusTmpl; master = master &>
- </section>
- </div>
- <div class="row">
- <section>
- <h2><a name="tables">Tables</a></h2>
- <div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" href="#tab_userTables" data-bs-toggle="tab" role="tab">User Tables</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_catalogTables" data-bs-toggle="tab" role="tab">System Tables</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_userSnapshots" data-bs-toggle="tab" role="tab">Snapshots</a>
- </li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_userTables" role="tabpanel">
- <%if (metaLocation != null) %>
- <& userTables &>
- </%if>
- </div>
- <div class="tab-pane" id="tab_catalogTables" role="tabpanel">
- <%if (metaLocation != null) %>
- <& catalogTables &>
- </%if>
- </div>
- <div class="tab-pane" id="tab_userSnapshots" role="tabpanel">
- </div>
- </div>
- </div>
- </section>
- </div>
- <div class="row">
- <section>
- <h2><a name="region_visualizer"></a>Region Visualizer</h2>
- <& RegionVisualizerTmpl &>
- </section>
- </div>
- <div class="row">
- <section>
- <h2><a name="peers">Peers</a></h2>
- <& peerConfigs &>
- </section>
- </div>
- <%else>
- <section>
- <& BackupMasterStatusTmpl; master = master &>
- </section>
- </%if>
-
-
- <section>
- <& ../common/TaskMonitorTmpl; filter = filter; parent = "/master-status" &>
- </section>
-
- <section>
- <h2><a name="attributes">Software Attributes</a></h2>
- <table id="attributes_table" class="table table-striped">
- <tr>
- <th>Attribute Name</th>
- <th>Value</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>JVM Version</td>
- <td><% JvmVersion.getVersion() %></td>
- <td>JVM vendor and version</td>
- </tr>
- <tr>
- <td>HBase Version</td>
- <td><% org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, revision=<% org.apache.hadoop.hbase.util.VersionInfo.getRevision() %></td><td>HBase version and revision</td>
- </tr>
- <tr>
- <td>HBase Compiled</td>
- <td><% org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <% org.apache.hadoop.hbase.util.VersionInfo.getUser() %></td>
- <td>When HBase version was compiled and by whom</td>
- </tr>
- <tr>
- <td>HBase Source Checksum</td>
- <td><% org.apache.hadoop.hbase.util.VersionInfo.getSrcChecksum() %></td>
- <td>HBase source SHA512 checksum</td>
- </tr>
- <tr>
- <td>Hadoop Version</td>
- <td><% org.apache.hadoop.util.VersionInfo.getVersion() %>, revision=<% org.apache.hadoop.util.VersionInfo.getRevision() %></td>
- <td>Hadoop version and revision</td>
- </tr>
- <tr>
- <td>Hadoop Compiled</td>
- <td><% org.apache.hadoop.util.VersionInfo.getDate() %>, <% org.apache.hadoop.util.VersionInfo.getUser() %></td>
- <td>When Hadoop version was compiled and by whom</td>
- </tr>
- <tr>
- <td>Hadoop Source Checksum</td>
- <td><% org.apache.hadoop.util.VersionInfo.getSrcChecksum() %></td>
- <td>Hadoop source MD5 checksum</td>
- </tr>
- <tr>
- <td>ZooKeeper Client Version</td>
- <td><% org.apache.zookeeper.Version.getVersion() %>, revision=<% org.apache.zookeeper.Version.getRevisionHash() %></td>
- <td>ZooKeeper client version and revision hash</td>
- </tr>
- <tr>
- <td>ZooKeeper Client Compiled</td>
- <td><% org.apache.zookeeper.Version.getBuildDate() %></td>
- <td>When ZooKeeper client version was compiled</td>
- </tr>
- <tr>
- <td>ZooKeeper Quorum</td>
- <%escape #n>
- <td> <% formatZKString() %> </td>
- <td>Addresses of all registered ZK servers. For more, see <a href="/zk.jsp">zk dump</a>.</td>
- </tr>
- <tr>
- <td>ZooKeeper Base Path</td>
- <td> <% master.getZooKeeper().getZNodePaths().baseZNode %></td>
- <td>Root node of this cluster in ZK.</td>
- </tr>
- <tr>
- <td>Cluster Key</td>
- <td> <% formatZKString() %>:<% master.getZooKeeper().getZNodePaths().baseZNode %></td>
- <td>Key to add this cluster as a peer for replication. Use 'help "add_peer"' in the shell for details.</td>
- </tr>
- <tr>
- <td>HBase Root Directory</td>
- <td><% CommonFSUtils.getRootDir(master.getConfiguration()).toString() %></td>
- <td>Location of HBase home directory</td>
- </tr>
- <tr>
- <td>HMaster Start Time</td>
- <td><% new Date(master.getMasterStartTime()) %></td>
- <td>Date stamp of when this HMaster was started</td>
- </tr>
- <%if master.isActiveMaster() %>
- <tr>
- <td>HMaster Active Time</td>
- <td><% new Date(master.getMasterActiveTime()) %></td>
- <td>Date stamp of when this HMaster became active</td>
- </tr>
- <tr>
- <td>HBase Cluster ID</td>
- <td><% master.getClusterId() != null ? master.getClusterId() : "Not set" %></td>
- <td>Unique identifier generated for each HBase cluster</td>
- </tr>
- <tr>
- <td>Load average</td>
- <td><% master.getServerManager() == null ? "0.00" :
- StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %></td>
- <td>Average number of regions per regionserver. Naive computation.</td>
- </tr>
- <%if frags != null %>
- <tr>
- <td>Fragmentation</td>
- <td><% frags.get("-TOTAL-") != null ? frags.get("-TOTAL-").intValue() + "%" : "n/a" %></td>
- <td>Overall fragmentation of all tables, including hbase:meta</td>
- </tr>
- </%if>
- <tr>
- <td>Coprocessors</td>
- <td><% master.getMasterCoprocessorHost() == null ? "[]" :
- java.util.Arrays.toString(master.getMasterCoprocessors()) %></td>
- <td>Coprocessors currently loaded by the master</td>
- </tr>
- <tr>
- <td>LoadBalancer</td>
- <td><% master.getLoadBalancerClassName() %></td>
- <td>LoadBalancer to be used in the Master</td>
- </tr>
- </%if>
- </table>
- </section>
- </div>
- </div> <!-- /container -->
-
- <script src="/static/js/jquery.min.js" type="text/javascript"></script>
- <script src="/static/js/jquery.tablesorter.min.js" type="text/javascript"></script>
- <script src="/static/js/parser-date-iso8601.min.js" type="text/javascript"></script>
- <script src="/static/js/bootstrap.bundle.min.js" type="text/javascript"></script>
- <script src="/static/js/tab.js" type="text/javascript"></script>
- <script src="/static/js/jqSpager.js" type="text/javascript"></script>
- <script>
- $(document).ready(function()
- {
- $.tablesorter.addParser(
- {
- id: 'filesize',
- is: function(s) {
- return s.match(new RegExp( /([\.0-9]+)\ (B|KB|MB|GB|TB)/ ));
- },
- format: function(s) {
- var suf = s.match(new RegExp( /(KB|B|GB|MB|TB)$/ ))[1];
- var num = parseFloat(s.match( new RegExp( /([\.0-9]+)\ (B|KB|MB|GB|TB)/ ))[0]);
- switch(suf) {
- case 'B':
- return num;
- case 'KB':
- return num * 1024;
- case 'MB':
- return num * 1024 * 1024;
- case 'GB':
- return num * 1024 * 1024 * 1024;
- case 'TB':
- return num * 1024 * 1024 * 1024 * 1024;
- }
- },
- type: 'numeric'
- });
- $.tablesorter.addParser(
- {
- id: "separator",
- is: function (s) {
- return /^[0-9]?[0-9,]*$/.test(s);
- }, format: function (s) {
- return $.tablesorter.formatFloat( s.replace(/,/g,'') );
- }, type: "numeric"
- });
- $.tablesorter.addParser(
- {
- id: "dateTime",
- is: function (s) {
- return /^([a-zA-Z]{3}\s){2}\d{2}\s\d{2}:\d{2}:\d{2}\s[a-zA-Z]{3}\s\d{4}$/.test(s);
- }, format: function (s) {
- var split = s.split(" ");
- var time = Date.parse(split[1] + " " + split[2] + " " + split[3] + " " + split[5]);
- return $.tablesorter.formatFloat(time);
- }, type: "numeric"
- });
- $("#baseStatsTable").tablesorter({
- headers: {
- '.cls_dateTime': {sorter: 'dateTime'},
- '.cls_separator': {sorter: 'separator'}
- }
- });
- $("#memoryStatsTable").tablesorter({
- headers: {
- '.cls_filesize': {sorter: 'filesize'}
- }
- });
- $("#requestStatsTable").tablesorter({
- headers: {
- '.cls_separator': {sorter: 'separator'}
- }
- });
- $("#storeStatsTable").tablesorter({
- headers: {
- '.cls_separator': {sorter: 'separator'},
- '.cls_filesize': {sorter: 'filesize'}
- }
- });
- $("#compactionStatsTable").tablesorter({
- headers: {
- '.cls_separator': {sorter: 'separator'}
- }
- });
-
- $("#userTables").tablesorter();
-
- function showRitPages() {
- if (!$("#rit_page_num")) {
- return;
- }
- var ritTotalNum = parseInt($("#rit_page_num").val());
- if (!ritTotalNum || ritTotalNum < 1) {
- return;
- }
- var ritPerPage = parseInt($("#rit_per_page").val());
-
- $("#rit_pagination").sPage({
- page:1,
- total:ritTotalNum,
- pageSize:ritPerPage,
- noData: false,
- showPN:true,
- prevPage:"prev",
- nextPage:"next",
- fastForward: 5,
- backFun:function(page){
- $("div[id^='tab_rits']").removeClass('active');
- $("#tab_rits"+page).addClass('active');
- }
- });
-
- }
- showRitPages();
-
- }
- );
- </script>
- </body>
-</html>
-
-<%def catalogTables>
-<%java>
- List<TableDescriptor> sysTables = master.isInitialized() ?
- master.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR) : null;
-</%java>
-<%if (sysTables != null && sysTables.size() > 0)%>
-<table class="table table-striped">
-<tr>
- <th>Table Name</th>
- <%if (frags != null) %>
- <th title="Fragmentation - Will be 0% after a major compaction and fluctuate during normal usage.">Frag.</th>
- </%if>
- <th>Description</th>
-</tr>
-<%for TableDescriptor systemTable : sysTables%>
-<tr>
-<%java>TableName tableName = systemTable.getTableName();</%java>
- <td><a href="table.jsp?name=<% tableName %>"><% tableName %></a></td>
- <%if (frags != null)%>
- <td align="center"><% frags.get(tableName.getNameAsString()) != null ? frags.get(tableName.getNameAsString())
- .intValue() + "%" : "n/a" %></td>
- </%if>
- <%java>String description = null;
- if (tableName.equals(TableName.META_TABLE_NAME)){
- description = "The hbase:meta table holds references to all User Table regions.";
- } else if (tableName.equals(CanaryTool.DEFAULT_WRITE_TABLE_NAME)){
- description = "The hbase:canary table is used to sniff the write availbility of"
- + " each regionserver.";
- } else if (tableName.equals(PermissionStorage.ACL_TABLE_NAME)){
- description = "The hbase:acl table holds information about acl.";
- } else if (tableName.equals(VisibilityConstants.LABELS_TABLE_NAME)){
- description = "The hbase:labels table holds information about visibility labels.";
- } else if (tableName.equals(TableName.NAMESPACE_TABLE_NAME)){
- description = "The hbase:namespace table holds information about namespaces.";
- } else if (tableName.equals(QuotaUtil.QUOTA_TABLE_NAME)){
- description = "The hbase:quota table holds quota information about number" +
- " or size of requests in a given time frame.";
- } else if (tableName.equals(TableName.valueOf("hbase:rsgroup"))){
- description = "The hbase:rsgroup table holds information about regionserver groups.";
- } else if (tableName.equals(TableName.valueOf("hbase:replication"))) {
- description = "The hbase:replication table tracks cross cluster replication through " +
- "WAL file offsets.";
- }
- </%java>
- <td><% description %></td>
-</tr>
-</%for>
-</table>
-</%if>
-</%def>
-
-<%def userTables>
-<%java>
- List<TableDescriptor> tables = new ArrayList<TableDescriptor>();
- String errorMessage = getUserTables(master, tables);
-</%java>
-<%if (tables.size() == 0 && errorMessage != null)%>
-<p> <% errorMessage %> </p>
-</%if>
-
-<%if (tables != null && tables.size() > 0)%>
-<table id="userTables" class="tablesorter table table-striped">
-<thead>
- <tr>
- <th style="vertical-align: middle;" rowspan="2">Namespace</th>
- <th style="vertical-align: middle;" rowspan="2">Name</th>
- <%if (frags != null) %>
- <th title="Fragmentation - Will be 0% after a major compaction and fluctuate during normal usage.">Frag.</th>
- </%if>
- <th style="vertical-align:middle;" rowspan="2">State</th>
- <th style="text-align: center" colspan="7">Regions</th>
- <th style="vertical-align:middle;" rowspan="2">Description</th>
- </tr>
- <tr>
- <th>OPEN</th>
- <th>OPENING</th>
- <th>CLOSED</th>
- <th>CLOSING</th>
- <th>OFFLINE</th>
- <th>SPLIT</th>
- <th>Other</th>
- </tr>
-</thead>
-<tbody>
- <%for TableDescriptor desc : tables%>
- <%java>
- HTableDescriptor htDesc = new HTableDescriptor(desc);
- TableName tableName = htDesc.getTableName();
- TableState tableState = master.getTableStateManager().getTableState(tableName);
- Map<RegionState.State, List<RegionInfo>> tableRegions =
- master.getAssignmentManager().getRegionStates()
- .getRegionByStateOfTable(tableName);
- int openRegionsCount = tableRegions.get(RegionState.State.OPEN).size();
- int openingRegionsCount = tableRegions.get(RegionState.State.OPENING).size();
- int closedRegionsCount = tableRegions.get(RegionState.State.CLOSED).size();
- int closingRegionsCount = tableRegions.get(RegionState.State.CLOSING).size();
- int offlineRegionsCount = tableRegions.get(RegionState.State.OFFLINE).size();
- int splitRegionsCount = tableRegions.get(RegionState.State.SPLIT).size();
- int otherRegionsCount = 0;
- for (List<RegionInfo> list: tableRegions.values()) {
- otherRegionsCount += list.size();
- }
- // now subtract known states
- otherRegionsCount = otherRegionsCount - openRegionsCount
- - offlineRegionsCount - splitRegionsCount
- - openingRegionsCount - closedRegionsCount
- - closingRegionsCount;
- String encodedTableName = URLEncoder.encode(tableName.getNameAsString());
- </%java>
- <tr>
- <td><% tableName.getNamespaceAsString() %></td>
- <%if (tableState.isDisabledOrDisabling()) %> <td><a style="color:red;" href=table.jsp?name=<% encodedTableName %>><% URLEncoder.encode(tableName.getQualifierAsString()) %></a></td> <%else><td><a href=table.jsp?name=<% encodedTableName %>><% URLEncoder.encode(tableName.getQualifierAsString()) %></a></td> </%if>
- <%if (frags != null) %>
- <td align="center"><% frags.get(tableName.getNameAsString()) != null ? frags.get(tableName.getNameAsString()).intValue() + "%" : "n/a" %></td>
- </%if>
- <%if (tableState.isDisabledOrDisabling()) %> <td style="color:red;"><% tableState.getState().name() %></td> <%else><td><% tableState.getState() %></td> </%if>
- <td><% openRegionsCount %></td>
- <%if (openingRegionsCount > 0) %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<% encodedTableName %>&scan_region_state=OPENING"><% openingRegionsCount %></td> <%else><td><% openingRegionsCount %></td> </%if>
- <%if (closedRegionsCount > 0) %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<% encodedTableName %>&scan_region_state=CLOSED"><% closedRegionsCount %></td> <%else><td><% closedRegionsCount %></td> </%if>
- <%if (closingRegionsCount > 0) %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<% encodedTableName %>&scan_region_state=CLOSING"><% closingRegionsCount %></td> <%else><td><% closingRegionsCount %></td> </%if>
- <%if (offlineRegionsCount > 0) %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<% encodedTableName %>&scan_region_state=OFFLINE"><% offlineRegionsCount %></td> <%else><td><% offlineRegionsCount %></td> </%if>
- <%if (splitRegionsCount > 0) %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<% encodedTableName %>&scan_region_state=SPLIT"><% splitRegionsCount %></td> <%else><td><% splitRegionsCount %></td> </%if>
- <td><% otherRegionsCount %></td>
- <td><% htDesc.toStringCustomizedValues() %></td>
- </tr>
- </%for>
- <p><% tables.size() %> table(s) in set. [<a href=tablesDetailed.jsp>Details</a>]. Click count below to
- see list of regions currently in 'state' designated by the column title. For 'Other' Region state,
- browse to <a href="/table.jsp?name=hbase%3Ameta">hbase:meta</a> and adjust filter on 'Meta Entries' to
- query on states other than those listed here. Queries may take a while if the <i>hbase:meta</i> table
- is large.</p>
-</tbody>
-</table>
-</%if>
-</%def>
-
-
-
-<%def deadRegionServers>
-
-<%if (deadServers != null && deadServers.size() > 0)%>
-<h2>Dead Region Servers</h2>
-<table class="table table-striped">
- <tr>
- <th></th>
- <th>ServerName</th>
- <th>Stop time</th>
- <%if !master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
- && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
- && master.getServerManager().getOnlineServersList().size() > 0 %>
- <th>RSGroup</th>
- </%if>
- </tr>
- <%java>
- List<RSGroupInfo> groups = null;
- DeadServer deadServerUtil = master.getServerManager().getDeadServers();
- if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
- && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
- && master.getServerManager().getOnlineServersList().size() > 0) {
- groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
- }
- ServerName [] deadServerNames = deadServers.toArray(new ServerName[deadServers.size()]);
- Arrays.sort(deadServerNames);
- for (ServerName deadServerName: deadServerNames) {
- String rsGroupName = null;
- if (groups != null){
- for (RSGroupInfo rsGroupInfo : groups) {
- if (rsGroupInfo.containsServer(deadServerName.getAddress())) {
- rsGroupName = rsGroupInfo.getName();
- break;
- }
- }
- if (rsGroupName == null) {
- rsGroupName = RSGroupInfo.DEFAULT_GROUP;
- }
- }
- </%java>
- <tr>
- <th></th>
- <td><% deadServerName %></td>
- <td><% deadServerUtil.getTimeOfDeath(deadServerName) %></td>
- <%if rsGroupName != null %>
- <td><% rsGroupName %></td>
- </%if>
- </tr>
- <%java>
- }
- </%java>
- <tr>
- <th>Total: </th>
- <td>servers: <% deadServers.size() %></td>
- <th></th>
- </tr>
-</table>
-</%if>
-</%def>
-
-<%def peerConfigs>
-<%java>
- List<ReplicationPeerDescription> peers = null;
- if (master.getReplicationPeerManager() != null) {
- peers = master.getReplicationPeerManager().listPeers(null);
- }
-</%java>
-<table class="table table-striped">
- <tr>
- <th>Peer Id</th>
- <th>Cluster Key</th>
- <th>Endpoint</th>
- <th>State</th>
- <th>IsSerial</th>
- <th>Bandwidth</th>
- <th>ReplicateAll</th>
- <th>Namespaces</th>
- <th>Exclude Namespaces</th>
- <th>Table Cfs</th>
- <th>Exclude Table Cfs</th>
- </tr>
-<%if (peers != null && peers.size() > 0)%>
- <%for ReplicationPeerDescription peer : peers %>
- <%java>
- String peerId = peer.getPeerId();
- ReplicationPeerConfig peerConfig = peer.getPeerConfig();
- </%java>
- <tr>
- <td><% peerId %></td>
- <td><% peerConfig.getClusterKey() %></td>
- <td><% peerConfig.getReplicationEndpointImpl() %></td>
- <td><% peer.isEnabled() ? "ENABLED" : "DISABLED" %></td>
- <td><% peerConfig.isSerial() %></td>
- <td><% peerConfig.getBandwidth() == 0? "UNLIMITED" : Strings.humanReadableInt(peerConfig.getBandwidth()) %></td>
- <td><% peerConfig.replicateAllUserTables() %></td>
- <td>
- <% peerConfig.getNamespaces() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getNamespaces()).replaceAll(";", "; ") %>
- </td>
- <td>
- <% peerConfig.getExcludeNamespaces() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getExcludeNamespaces()).replaceAll(";", "; ") %>
- </td>
- <td>
- <% peerConfig.getTableCFsMap() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getTableCFsMap()).replaceAll(";", "; ") %>
- </td>
- <td>
- <% peerConfig.getExcludeTableCFsMap() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getExcludeTableCFsMap()).replaceAll(";", "; ") %>
- </td>
- </tr>
- </%for>
-</%if>
-<tr><td>Total: <% (peers != null) ? peers.size() : 0 %></td></tr>
-</table>
-</%def>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RSGroupListTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RSGroupListTmpl.jamon
deleted file mode 100644
index a00576786db..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RSGroupListTmpl.jamon
+++ /dev/null
@@ -1,393 +0,0 @@
-<%doc>
-Copyright The Apache Software Foundation
-
-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.
- </%doc>
-
-<%args>
-HMaster master;
-ServerManager serverManager;
-</%args>
-
-<%import>
- java.util.Collections;
- java.util.List;
- java.util.Map;
- java.util.Set;
- java.util.stream.Collectors;
- org.apache.hadoop.hbase.master.HMaster;
- org.apache.hadoop.hbase.RegionMetrics;
- org.apache.hadoop.hbase.ServerMetrics;
- org.apache.hadoop.hbase.Size;
- org.apache.hadoop.hbase.RSGroupTableAccessor;
- org.apache.hadoop.hbase.master.ServerManager;
- org.apache.hadoop.hbase.net.Address;
- org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
- org.apache.hadoop.util.StringUtils;
- org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix;
-</%import>
-<%java>
-List<RSGroupInfo> groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
-</%java>
-<%if (groups != null && groups.size() > 0)%>
-
-<%java>
-RSGroupInfo [] rsGroupInfos = groups.toArray(new RSGroupInfo[groups.size()]);
-Map<Address, ServerMetrics> collectServers = Collections.emptyMap();
-if (master.getServerManager() != null) {
- collectServers =
- master.getServerManager().getOnlineServers().entrySet().stream()
- .collect(Collectors.toMap(p -> p.getKey().getAddress(), Map.Entry::getValue));
-}
-</%java>
-
-<div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item"><a class="nav-link active" href="#tab_rsgroup_baseStats" data-bs-toggle="tab" role="tab">Base Stats</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_memoryStats" data-bs-toggle="tab" role="tab">Memory</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_requestStats" data-bs-toggle="tab" role="tab">Requests</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_storeStats" data-bs-toggle="tab" role="tab">Storefiles</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_compactStats" data-bs-toggle="tab" role="tab">Compactions</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_rsgroup_baseStats" role="tabpanel">
- <& rsgroup_baseStats; rsGroupInfos = rsGroupInfos; collectServers= collectServers &>
- </div>
- <div class="tab-pane" id="tab_rsgroup_memoryStats" role="tabpanel">
- <& rsgroup_memoryStats; rsGroupInfos = rsGroupInfos; collectServers= collectServers &>
- </div>
- <div class="tab-pane" id="tab_rsgroup_requestStats" role="tabpanel">
- <& rsgroup_requestStats; rsGroupInfos = rsGroupInfos; collectServers= collectServers &>
- </div>
- <div class="tab-pane" id="tab_rsgroup_storeStats" role="tabpanel">
- <& rsgroup_storeStats; rsGroupInfos = rsGroupInfos; collectServers= collectServers &>
- </div>
- <div class="tab-pane" id="tab_rsgroup_compactStats" role="tabpanel">
- <& rsgroup_compactStats; rsGroupInfos = rsGroupInfos; collectServers= collectServers &>
- </div>
- </div>
-</div>
-
-</%if>
-
-<%def rsgroup_baseStats>
-<%args>
- RSGroupInfo [] rsGroupInfos;
- Map<Address, ServerMetrics> collectServers;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>RSGroup Name</th>
- <th>Num. Online Servers</th>
- <th>Num. Dead Servers</th>
- <th>Num. Tables</th>
- <th>Requests Per Second</th>
- <th>Num. Regions</th>
- <th>Average Load</th>
-</tr>
-<%java>
- int totalOnlineServers = 0;
- int totalDeadServers = 0;
- int totalTables = 0;
- int totalRequests = 0;
- int totalRegions = 0;
- for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
- String rsGroupName = rsGroupInfo.getName();
- int onlineServers = 0;
- int deadServers = 0;
- int tables = 0;
- long requestsPerSecond = 0;
- int numRegionsOnline = 0;
- Set<Address> servers = rsGroupInfo.getServers();
- for (Address server : servers) {
- ServerMetrics sl = collectServers.get(server);
- if (sl != null) {
- requestsPerSecond += sl.getRequestCountPerSecond();
- numRegionsOnline += sl.getRegionMetrics().size();
- //rsgroup total
- totalRegions += sl.getRegionMetrics().size();
- totalRequests += sl.getRequestCountPerSecond();
- totalOnlineServers++;
- onlineServers++;
- } else {
- totalDeadServers++;
- deadServers++;
- }
- }
- tables = rsGroupInfo.getTables().size();
- totalTables += tables;
- double avgLoad = onlineServers == 0 ? 0 :
- (double)numRegionsOnline / (double)onlineServers;
-</%java>
-<tr>
- <td><& rsGroupLink; rsGroupName=rsGroupName; &></td>
- <td><% onlineServers %></td>
- <td><% deadServers %></td>
- <td><% tables %></td>
- <td><% requestsPerSecond %></td>
- <td><% numRegionsOnline %></td>
- <td><% StringUtils.limitDecimalTo2(avgLoad) %></td>
-</tr>
-<%java>
-}
-</%java>
-<tr><td>Total:<% rsGroupInfos.length %></td>
-<td><% totalOnlineServers %></td>
-<td><% totalDeadServers %></td>
-<td><% totalTables %></td>
-<td><% totalRequests %></td>
-<td><% totalRegions %></td>
-<td><% StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %></td>
-</tr>
-</table>
-</%def>
-
-<%def rsgroup_memoryStats>
-<%args>
- RSGroupInfo [] rsGroupInfos;
- Map<Address, ServerMetrics> collectServers;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>RSGroup Name</th>
- <th>Used Heap</th>
- <th>Max Heap</th>
- <th>Memstore Size</th>
-
-</tr>
-<%java>
- final String ZEROMB = "0 MB";
- for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
- String usedHeapStr = ZEROMB;
- String maxHeapStr = ZEROMB;
- String memstoreSizeStr = ZEROMB;
- String rsGroupName = rsGroupInfo.getName();
- long usedHeap = 0;
- long maxHeap = 0;
- long memstoreSize = 0;
- for (Address server : rsGroupInfo.getServers()) {
- ServerMetrics sl = collectServers.get(server);
- if (sl != null) {
- usedHeap += (long) sl.getUsedHeapSize().get(Size.Unit.MEGABYTE);
- maxHeap += (long) sl.getMaxHeapSize().get(Size.Unit.MEGABYTE);
- memstoreSize += (long) sl.getRegionMetrics().values().stream().mapToDouble(
- rm -> rm.getMemStoreSize().get(Size.Unit.MEGABYTE)).sum();
- }
- }
-
- if (usedHeap > 0) {
- usedHeapStr = TraditionalBinaryPrefix.long2String(usedHeap
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (maxHeap > 0) {
- maxHeapStr = TraditionalBinaryPrefix.long2String(maxHeap
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (memstoreSize > 0) {
- memstoreSizeStr = TraditionalBinaryPrefix.long2String(memstoreSize
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
-</%java>
-<tr>
- <td><& rsGroupLink; rsGroupName=rsGroupName; &></td>
- <td><% usedHeapStr %></td>
- <td><% maxHeapStr %></td>
- <td><% memstoreSizeStr %></td>
-
-</tr>
-<%java>
-}
-</%java>
-</table>
-</%def>
-
-<%def rsgroup_requestStats>
-<%args>
- RSGroupInfo [] rsGroupInfos;
- Map<Address, ServerMetrics> collectServers;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>RSGroup Name</th>
- <th>Request Per Second</th>
- <th>Read Request Count</th>
- <th>Write Request Count</th>
-</tr>
-<%java>
- for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
- String rsGroupName = rsGroupInfo.getName();
- long requestsPerSecond = 0;
- long readRequests = 0;
- long writeRequests = 0;
- for (Address server : rsGroupInfo.getServers()) {
- ServerMetrics sl = collectServers.get(server);
- if (sl != null) {
- for (RegionMetrics rm : sl.getRegionMetrics().values()) {
- readRequests += rm.getReadRequestCount();
- writeRequests += rm.getWriteRequestCount();
- }
- requestsPerSecond += sl.getRequestCountPerSecond();
- }
- }
-</%java>
-<tr>
-<td><& rsGroupLink; rsGroupName=rsGroupName; &></td>
-<td><% requestsPerSecond %></td>
-<td><% readRequests %></td>
-<td><% writeRequests %></td>
-</tr>
-<%java>
-}
-</%java>
-</table>
-</%def>
-
-
-<%def rsgroup_storeStats>
-<%args>
- RSGroupInfo [] rsGroupInfos;
- Map<Address, ServerMetrics> collectServers;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>RSGroup Name</th>
- <th>Num. Stores</th>
- <th>Num. Storefiles</th>
- <th>Storefile Size Uncompressed</th>
- <th>Storefile Size</th>
- <th>Index Size</th>
- <th>Bloom Size</th>
-</tr>
-<%java>
- final String ZEROKB = "0 KB";
- final String ZEROMB = "0 MB";
- for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
- String uncompressedStorefileSizeStr = ZEROMB;
- String storefileSizeStr = ZEROMB;
- String indexSizeStr = ZEROKB;
- String bloomSizeStr = ZEROKB;
- String rsGroupName = rsGroupInfo.getName();
- int numStores = 0;
- long numStorefiles = 0;
- long uncompressedStorefileSize = 0;
- long storefileSize = 0;
- long indexSize = 0;
- long bloomSize = 0;
- int count = 0;
- for (Address server : rsGroupInfo.getServers()) {
- ServerMetrics sl = collectServers.get(server);
- if (sl != null) {
- for (RegionMetrics rm : sl.getRegionMetrics().values()) {
- numStores += rm.getStoreCount();
- numStorefiles += rm.getStoreFileCount();
- uncompressedStorefileSize += rm.getUncompressedStoreFileSize().get(Size.Unit.MEGABYTE);
- storefileSize += rm.getStoreFileSize().get(Size.Unit.MEGABYTE);
- indexSize += rm.getStoreFileUncompressedDataIndexSize().get(Size.Unit.KILOBYTE);
- bloomSize += rm.getBloomFilterSize().get(Size.Unit.KILOBYTE);
- }
- count++;
- }
- }
- if (uncompressedStorefileSize > 0) {
- uncompressedStorefileSizeStr = TraditionalBinaryPrefix.
- long2String(uncompressedStorefileSize * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (storefileSize > 0) {
- storefileSizeStr = TraditionalBinaryPrefix.
- long2String(storefileSize * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (indexSize > 0) {
- indexSizeStr = TraditionalBinaryPrefix.
- long2String(indexSize * TraditionalBinaryPrefix.KILO.value, "B", 1);
- }
- if (bloomSize > 0) {
- bloomSizeStr = TraditionalBinaryPrefix.
- long2String(bloomSize * TraditionalBinaryPrefix.KILO.value, "B", 1);
- }
-</%java>
-<tr>
-<td><& rsGroupLink; rsGroupName=rsGroupName; &></td>
-<td><% numStores %></td>
-<td><% numStorefiles %></td>
-<td><% uncompressedStorefileSizeStr %></td>
-<td><% storefileSizeStr %></td>
-<td><% indexSizeStr %></td>
-<td><% bloomSizeStr %></td>
-</tr>
-<%java>
-}
-</%java>
-</table>
-</%def>
-
-<%def rsgroup_compactStats>
-<%args>
- RSGroupInfo [] rsGroupInfos;
- Map<Address, ServerMetrics> collectServers;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>RSGroup Name</th>
- <th>Num. Compacting Cells</th>
- <th>Num. Compacted Cells</th>
- <th>Remaining Cells</th>
- <th>Compaction Progress</th>
-</tr>
-<%java>
- for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
- String rsGroupName = rsGroupInfo.getName();
- int numStores = 0;
- long totalCompactingCells = 0;
- long totalCompactedCells = 0;
- long remainingCells = 0;
- long compactionProgress = 0;
- for (Address server : rsGroupInfo.getServers()) {
- ServerMetrics sl = collectServers.get(server);
- if (sl != null) {
- for (RegionMetrics rl : sl.getRegionMetrics().values()) {
- totalCompactingCells += rl.getCompactingCellCount();
- totalCompactedCells += rl.getCompactedCellCount();
- }
- }
- }
- remainingCells = totalCompactingCells - totalCompactedCells;
- String percentDone = "";
- if (totalCompactingCells > 0) {
- percentDone = String.format("%.2f", 100 *
- ((float) totalCompactedCells / totalCompactingCells)) + "%";
- }
-</%java>
-<tr>
-<td><& rsGroupLink; rsGroupName=rsGroupName; &></td>
-<td><% totalCompactingCells %></td>
-<td><% totalCompactedCells %></td>
-<td><% remainingCells %></td>
-<td><% percentDone %></td>
-</tr>
-<%java>
-}
-</%java>
-</table>
-</%def>
-
-
-<%def rsGroupLink>
- <%args>
- String rsGroupName;
- </%args>
- <a href=rsgroup.jsp?name=<% rsGroupName %>><% rsGroupName %></a>
-</%def>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionServerListTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionServerListTmpl.jamon
deleted file mode 100644
index 2f1da65bf69..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionServerListTmpl.jamon
+++ /dev/null
@@ -1,545 +0,0 @@
-<%doc>
-Copyright The Apache Software Foundation
-
-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.
- </%doc>
-
-<%args>
-List<ServerName> servers = null;
-HMaster master;
-</%args>
-
-<%import>
- java.util.*;
- org.apache.hadoop.hbase.master.HMaster;
- org.apache.hadoop.hbase.procedure2.util.StringUtils;
- org.apache.hadoop.hbase.replication.ReplicationLoadSource;
- org.apache.hadoop.hbase.RegionMetrics;
- org.apache.hadoop.hbase.RSGroupTableAccessor;
- org.apache.hadoop.hbase.ServerMetrics;
- org.apache.hadoop.hbase.ServerName;
- org.apache.hadoop.hbase.Size;
- org.apache.hadoop.hbase.net.Address;
- org.apache.hadoop.hbase.rsgroup.RSGroupInfo;
- org.apache.hadoop.hbase.util.VersionInfo;
- org.apache.hadoop.hbase.util.Pair;
- org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix;
-</%import>
-
-<%if (servers != null && servers.size() > 0)%>
-
-<%java>
-ServerName [] serverNames = servers.toArray(new ServerName[servers.size()]);
-Arrays.sort(serverNames);
-</%java>
-
-<div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item">
- <a class="nav-link active" href="#tab_baseStats" data-bs-toggle="tab" role="tab">Base Stats</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_memoryStats" data-bs-toggle="tab" role="tab">Memory</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_requestStats" data-bs-toggle="tab" role="tab">Requests</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_storeStats" data-bs-toggle="tab" role="tab">Storefiles</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_compactStats" data-bs-toggle="tab" role="tab">Compactions</a>
- </li>
- <li class="nav-item">
- <a class="nav-link" href="#tab_replicationStats" data-bs-toggle="tab" role="tab">Replications</a>
- </li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_baseStats" role="tabpanel">
- <& baseStats; serverNames = serverNames; &>
- </div>
- <div class="tab-pane" id="tab_memoryStats" role="tabpanel">
- <& memoryStats; serverNames = serverNames; &>
- </div>
- <div class="tab-pane" id="tab_requestStats" role="tabpanel">
- <& requestStats; serverNames = serverNames; &>
- </div>
- <div class="tab-pane" id="tab_storeStats" role="tabpanel">
- <& storeStats; serverNames = serverNames; &>
- </div>
- <div class="tab-pane" id="tab_compactStats" role="tabpanel">
- <& compactionStats; serverNames = serverNames; &>
- </div>
- <div class="tab-pane" id="tab_replicationStats" role="tabpanel">
- <& replicationStats; serverNames = serverNames; &>
- </div>
- </div>
-</div>
-
-</%if>
-
-<%def baseStats>
-<%args>
- ServerName [] serverNames;
-</%args>
-<table id="baseStatsTable" class="tablesorter table table-striped">
-<thead>
-<tr>
- <th>ServerName</th>
- <th>State</th>
- <th class="cls_dateTime">Start time</th>
- <th>Last contact</th>
- <th>Version</th>
- <th class="cls_separator">Requests Per Second</th>
- <th class="cls_separator">Num. Regions</th>
- <%if !master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null %>
- <%if master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null &&
- master.getServerManager().getOnlineServersList().size() > 0 %>
- <th>RSGroup</th>
- </%if>
- </%if>
-</tr>
-</thead>
-<tbody>
-<%java>
- int totalRegions = 0;
- int totalRequestsPerSecond = 0;
- int inconsistentNodeNum = 0;
- String state = "Normal";
- String masterVersion = VersionInfo.getVersion();
- Set<ServerName> decommissionedServers = new HashSet<>(master.listDecommissionedRegionServers());
-
- String rsGroupName = "default";
- List<RSGroupInfo> groups;
- Map<Address, RSGroupInfo> server2GroupMap = new HashMap<>();
- if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
- && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
- && master.getServerManager().getOnlineServersList().size() > 0) {
- groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
- groups.forEach(group -> {
- group.getServers().forEach(address -> server2GroupMap.put(address, group));
- });
- }
-
- for (ServerName serverName: serverNames) {
- if (decommissionedServers.contains(serverName)) {
- state = "Decommissioned";
- }
- ServerMetrics sl = master.getServerManager().getLoad(serverName);
- String version = master.getRegionServerVersion(serverName);
- if (!masterVersion.equals(version)) {
- inconsistentNodeNum ++;
- }
-
- double requestsPerSecond = 0.0;
- int numRegionsOnline = 0;
- long lastContact = 0;
-
- if (sl != null) {
- requestsPerSecond = sl.getRequestCountPerSecond();
- numRegionsOnline = sl.getRegionMetrics().size();
- totalRegions += sl.getRegionMetrics().size();
- totalRequestsPerSecond += sl.getRequestCountPerSecond();
- lastContact = (System.currentTimeMillis() - sl.getReportTimestamp())/1000;
- }
- long startcode = serverName.getStartcode();
-
- if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
- && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
- && master.getServerManager().getOnlineServersList().size() > 0) {
- rsGroupName = server2GroupMap.get(serverName.getAddress()).getName();
- }
-</%java>
-<tr>
- <td><& serverNameLink; serverName=serverName; &></td>
- <td><% state %></td>
- <td><% new Date(startcode) %></td>
- <td><% TraditionalBinaryPrefix.long2String(lastContact, "s", 1) %></td>
- <td><% version %></td>
- <td><% String.format("%,.0f", requestsPerSecond) %></td>
- <td><% String.format("%,d", numRegionsOnline) %></td>
- <%if !master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null %>
- <%if master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null &&
- master.getServerManager().getOnlineServersList().size() > 0 %>
- <td><% rsGroupName %></td>
- </%if>
- </%if>
-</tr>
-<%java>
-}
-</%java>
-</tbody>
-<tr><td>Total:<% servers.size() %></td>
-<td></td>
-<td></td>
-<td></td>
-<%if inconsistentNodeNum > 0%>
- <td style="color:red;"><% inconsistentNodeNum %> nodes with inconsistent version</td>
-<%else>
- <td></td>
-</%if>
-<td><% totalRequestsPerSecond %></td>
-<td><% totalRegions %></td>
-</tr>
-</table>
-</%def>
-
-<%def memoryStats>
-<%args>
- ServerName [] serverNames;
-</%args>
-<table id="memoryStatsTable" class="tablesorter table table-striped">
-<thead>
-<tr>
- <th>ServerName</th>
- <th class="cls_filesize">Used Heap</th>
- <th class="cls_filesize">Max Heap</th>
- <th class="cls_filesize">Memstore Size</th>
-
-</tr>
-</thead>
-<tbody>
-<%java>
-final String ZEROMB = "0 MB";
-for (ServerName serverName: serverNames) {
- String usedHeapStr = ZEROMB;
- String maxHeapStr = ZEROMB;
- String memStoreSizeMBStr = ZEROMB;
- ServerMetrics sl = master.getServerManager().getLoad(serverName);
- if (sl != null) {
- long memStoreSizeMB = 0;
- for (RegionMetrics rl : sl.getRegionMetrics().values()) {
- memStoreSizeMB += rl.getMemStoreSize().get(Size.Unit.MEGABYTE);
- }
- if (memStoreSizeMB > 0) {
- memStoreSizeMBStr = TraditionalBinaryPrefix.long2String(memStoreSizeMB
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
-
- double usedHeapSizeMB = sl.getUsedHeapSize().get(Size.Unit.MEGABYTE);
- if (usedHeapSizeMB > 0) {
- usedHeapStr = TraditionalBinaryPrefix.long2String((long) usedHeapSizeMB
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- double maxHeapSizeMB = sl.getMaxHeapSize().get(Size.Unit.MEGABYTE);
- if (maxHeapSizeMB > 0) {
- maxHeapStr = TraditionalBinaryPrefix.long2String((long) maxHeapSizeMB
- * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
-</%java>
-<tr>
- <td><& serverNameLink; serverName=serverName; &></td>
- <td><% usedHeapStr %></td>
- <td><% maxHeapStr %></td>
- <td><% memStoreSizeMBStr %></td>
-</tr>
-<%java>
- } else {
-</%java>
-<& emptyStat; serverName=serverName; &>
-<%java>
- }
-}
-</%java>
-</tbody>
-</table>
-</%def>
-
-
-<%def requestStats>
-<%args>
- ServerName [] serverNames;
- </%args>
-<table id="requestStatsTable" class="tablesorter table table-striped">
-<thead>
-<tr>
- <th>ServerName</th>
- <th class="cls_separator">Request Per Second</th>
- <th class="cls_separator">Read Request Count</th>
- <th class="cls_separator">Filtered Read Request Count</th>
- <th class="cls_separator">Write Request Count</th>
-</tr>
-</thead>
-<tbody>
-<%java>
-for (ServerName serverName: serverNames) {
-
-ServerMetrics sl = master.getServerManager().getLoad(serverName);
-if (sl != null) {
- long readRequestCount = 0;
- long writeRequestCount = 0;
- long filteredReadRequestCount = 0;
- for (RegionMetrics rl : sl.getRegionMetrics().values()) {
- readRequestCount += rl.getReadRequestCount();
- writeRequestCount += rl.getWriteRequestCount();
- filteredReadRequestCount += rl.getFilteredReadRequestCount();
- }
-</%java>
-<tr>
-<td><& serverNameLink; serverName=serverName; &></td>
-<td><% String.format("%,d", sl.getRequestCountPerSecond()) %></td>
-<td><% String.format("%,d", readRequestCount) %></td>
-<td><% String.format("%,d", filteredReadRequestCount) %></td>
-<td><% String.format("%,d", writeRequestCount) %></td>
-</tr>
-<%java>
- } else {
- </%java>
-<& emptyStat; serverName=serverName; &>
-<%java>
- }
-}
-</%java>
-</tbody>
-</table>
-</%def>
-
-
-<%def storeStats>
-<%args>
- ServerName [] serverNames;
- </%args>
-<table id="storeStatsTable" class="tablesorter table table-striped">
-<thead>
-<tr>
- <th>ServerName</th>
- <th class="cls_separator">Num. Stores</th>
- <th class="cls_separator">Num. Storefiles</th>
- <th class="cls_filesize">Storefile Size Uncompressed</th>
- <th class="cls_filesize">Storefile Size</th>
- <th class="cls_filesize">Index Size</th>
- <th class="cls_filesize">Bloom Size</th>
-</tr>
-</thead>
-<tbody>
-<%java>
-final String ZEROKB = "0 KB";
-final String ZEROMB = "0 MB";
-for (ServerName serverName: serverNames) {
-
- String storeUncompressedSizeMBStr = ZEROMB;
- String storeFileSizeMBStr = ZEROMB;
- String totalStaticIndexSizeKBStr = ZEROKB;
- String totalStaticBloomSizeKBStr = ZEROKB;
- ServerMetrics sl = master.getServerManager().getLoad(serverName);
- if (sl != null) {
- long storeCount = 0;
- long storeFileCount = 0;
- long storeUncompressedSizeMB = 0;
- long storeFileSizeMB = 0;
- long totalStaticIndexSizeKB = 0;
- long totalStaticBloomSizeKB = 0;
- for (RegionMetrics rl : sl.getRegionMetrics().values()) {
- storeCount += rl.getStoreCount();
- storeFileCount += rl.getStoreFileCount();
- storeUncompressedSizeMB += rl.getUncompressedStoreFileSize().get(Size.Unit.MEGABYTE);
- storeFileSizeMB += rl.getStoreFileSize().get(Size.Unit.MEGABYTE);
- totalStaticIndexSizeKB += rl.getStoreFileUncompressedDataIndexSize().get(Size.Unit.KILOBYTE);
- totalStaticBloomSizeKB += rl.getBloomFilterSize().get(Size.Unit.KILOBYTE);
- }
- if (storeUncompressedSizeMB > 0) {
- storeUncompressedSizeMBStr = TraditionalBinaryPrefix.
- long2String(storeUncompressedSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (storeFileSizeMB > 0) {
- storeFileSizeMBStr = TraditionalBinaryPrefix.
- long2String(storeFileSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- if (totalStaticIndexSizeKB > 0) {
- totalStaticIndexSizeKBStr = TraditionalBinaryPrefix.
- long2String(totalStaticIndexSizeKB * TraditionalBinaryPrefix.KILO.value, "B", 1);
- }
- if (totalStaticBloomSizeKB > 0) {
- totalStaticBloomSizeKBStr = TraditionalBinaryPrefix.
- long2String(totalStaticBloomSizeKB * TraditionalBinaryPrefix.KILO.value, "B", 1);
- }
-</%java>
-<tr>
-<td><& serverNameLink; serverName=serverName; &></td>
-<td><% String.format("%,d", storeCount) %></td>
-<td><% String.format("%,d", storeFileCount) %></td>
-<td><% storeUncompressedSizeMBStr %></td>
-<td><% storeFileSizeMBStr %></td>
-<td><% totalStaticIndexSizeKBStr %></td>
-<td><% totalStaticBloomSizeKBStr %></td>
-</tr>
-<%java>
- } else {
-</%java>
-<& emptyStat; serverName=serverName; &>
-<%java>
- }
-}
-</%java>
-</tbody>
-</table>
-</%def>
-
-<%def compactionStats>
-<%args>
- ServerName [] serverNames;
- </%args>
-<table id="compactionStatsTable" class="tablesorter table table-striped">
-<thead>
-<tr>
- <th>ServerName</th>
- <th class="cls_separator">Num. Compacting Cells</th>
- <th class="cls_separator">Num. Compacted Cells</th>
- <th class="cls_separator">Remaining Cells</th>
- <th>Compaction Progress</th>
-</tr>
-</thead>
-<tbody>
-<%java>
-for (ServerName serverName: serverNames) {
-
-ServerMetrics sl = master.getServerManager().getLoad(serverName);
-if (sl != null) {
-long totalCompactingCells = 0;
-long totalCompactedCells = 0;
-for (RegionMetrics rl : sl.getRegionMetrics().values()) {
- totalCompactingCells += rl.getCompactingCellCount();
- totalCompactedCells += rl.getCompactedCellCount();
-}
-String percentDone = "";
-if (totalCompactingCells > 0) {
- percentDone = String.format("%.2f", 100 *
- ((float) totalCompactedCells / totalCompactingCells)) + "%";
-}
-</%java>
-<tr>
-<td><& serverNameLink; serverName=serverName; &></td>
-<td><% String.format("%,d", totalCompactingCells) %></td>
-<td><% String.format("%,d", totalCompactedCells) %></td>
-<td><% String.format("%,d", totalCompactingCells - totalCompactedCells) %></td>
-<td><% percentDone %></td>
-</tr>
-<%java>
- } else {
- </%java>
-<& emptyStat; serverName=serverName; &>
-<%java>
- }
-}
-</%java>
-</tbody>
-</table>
-</%def>
-
-<%def replicationStats>
-<%args>
- ServerName [] serverNames;
-</%args>
-<%java>
- HashMap<String, List<Pair<ServerName, ReplicationLoadSource>>> replicationLoadSourceMap
- = master.getReplicationLoad(serverNames);
- List<String> peers = null;
- if (replicationLoadSourceMap != null && replicationLoadSourceMap.size() > 0){
- peers = new ArrayList<>(replicationLoadSourceMap.keySet());
- Collections.sort(peers);
- }
-</%java>
-
-<%if (replicationLoadSourceMap != null && replicationLoadSourceMap.size() > 0) %>
-
-<div class="tabbable">
- <ul class="nav nav-tabs">
- <%java>
- String active = "active";
- for (String peer : peers){
- </%java>
- <li class=<% active %>><a href="#tab_<% peer %>" data-bs-toggle="tab">Peer <% peer %></a> </li>
- <%java>
- active = "";
- }
- </%java>
- </ul>
- <div class="tab-content">
- <%java>
- active = "active";
- for (String peer : peers){
- </%java>
- <div class="tab-pane <% active %>" id="tab_<% peer %>">
- <table class="table table-striped">
- <tr>
- <th>Server</th>
- <th>AgeOfLastShippedOp</th>
- <th>SizeOfLogQueue</th>
- <th>ReplicationLag</th>
- </tr>
-
- <%for Pair<ServerName, ReplicationLoadSource> pair: replicationLoadSourceMap.get(peer) %>
- <tr>
- <td><& serverNameLink; serverName=pair.getFirst(); &></td>
- <td><% StringUtils.humanTimeDiff(pair.getSecond().getAgeOfLastShippedOp()) %></td>
- <td><% pair.getSecond().getSizeOfLogQueue() %></td>
- <td><% pair.getSecond().getReplicationLag() == Long.MAX_VALUE ? "UNKNOWN" : StringUtils.humanTimeDiff(pair.getSecond().getReplicationLag()) %></td>
- </tr>
- </%for>
- </table>
- </div>
- <%java>
- active = "";
- }
- </%java>
- </div>
- <p>If the replication delay is UNKNOWN, that means this walGroup doesn't start replicate yet and it may get disabled.</p>
-</div>
-<%else>
- <p>No Peers Metrics</p>
-</%if>
-</%def>
-
-
-
-<%def serverNameLink>
- <%args>
- ServerName serverName;
- </%args>
- <%java>
- int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
- </%java>
-
- <%if infoPort > 0%>
- <a href="<% url %>"><% serverName.getServerName() %></a>
- <%else>
- <% serverName.getServerName() %>
- </%if>
-</%def>
-
-<%def emptyStat>
- <%args>
- ServerName serverName;
- </%args>
- <tr>
- <td><& serverNameLink; serverName=serverName; &></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- <td></td>
- </tr>
-</%def>
-
-
-
-
-
-
-
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionVisualizerTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionVisualizerTmpl.jamon
deleted file mode 100644
index 9a98cfefed7..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionVisualizerTmpl.jamon
+++ /dev/null
@@ -1,119 +0,0 @@
-<%doc>
-
-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.
-</%doc>
-
- <script type="text/javascript" src="/static/js/vega.min.js"></script>
- <script type="text/javascript" src="/static/js/vega-lite.min.js"></script>
- <script type="text/javascript" src="/static/js/vega-embed.min.js"></script>
-
- <div id="vis" style="width:80%;"></div>
- <script type="text/javascript">
- vega.expressionFunction('values', function(obj) { return Object.values(obj); });
- var vlSpec = {
- $schema: 'https://vega.github.io/schema/vega-lite/v5.json',
- description: 'Total `storefileSize` per Region Server',
- data: {
- name: 'region_info',
- url: '/api/v1/admin/cluster_metrics/live_servers',
- format: { type: 'json', property: 'data' }
- },
- transform: [
- { calculate: "split(datum.server_name.server_name, ',', 1)[0]", as: 'server_name' },
- { calculate: 'values(datum.region_status)', as: 'region_status' },
- { flatten: ['region_status'] },
- { calculate: "split(datum.region_status.name, ',', 1)[0]", as: 'table_name' },
- { calculate: "split(datum.region_status.name, ',', 3)[2]", as: 'region_id' },
- ],
- vconcat: [{
- title: {
- text: 'Total `storefileSize` per Region Server',
- align: 'center'
- },
- height: 250,
- width: 'container',
- mark: { type: 'bar', tooltip: true },
- params: [{
- name: 'legend_selection',
- select: { type: 'point', fields: ['table_name'] },
- bind: 'legend'
- }],
- encoding: {
- x: {
- title:'Region Server',
- field: 'server_name',
- type: 'nominal',
- axis: {
- labelAngle: 90,
- labelOverlap: 'greedy'
- },
- scale: { domain: { param: 'brush' } },
- sort: '-y'
- },
- y: {
- title: 'Total StoreFileSize',
- field: 'region_status.store_file_size',
- type: 'quantitative',
- aggregate: 'sum',
- format: '.4s',
- axis: { format: '.2s' },
- scale: { domainMin: 0 }
- },
- color: {
- field: 'table_name',
- type: 'nominal',
- title: 'Table'
- },
- opacity: {
- condition: { param: 'legend_selection', value: 0.9 },
- value: 0.2
- }
- }
- }, {
- mark: 'bar',
- height: 50,
- width: 'container',
- params: [{
- name: 'brush',
- select: { type: 'interval', encodings: ['x'] }
- }],
- encoding: {
- x: {
- field: 'server_name',
- type: 'nominal',
- axis: null,
- sort: '-y'
- },
- y: {
- field: 'region_status.store_file_size',
- aggregate: 'sum',
- axis: null
- },
- color: {
- field: 'table_name',
- title: 'Table'
- }
- }
- }]
- };
- vegaEmbed('#vis', vlSpec)
- .then(function(result) {
- //result.view.logger(vega.Debug);
- //console.log(result.view.data('region_info'));
- })
- .catch(console.Error);
- </script>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon
index 4b8047b9e44..15426675dec 100644
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon
+++ b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon
@@ -243,7 +243,7 @@ org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
<%else>
<%java>
String host = masterServerName.getHostname() + ":" + infoPort;
- String url = "//" + host + "/master-status";
+ String url = "//" + host + "/master.jsp";
</%java>
<a href="<% url %>"><% host %></a>
</%if>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/index.html b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusConstants.java
similarity index 52%
copy from hbase-server/src/main/resources/hbase-webapps/master/index.html
copy to hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusConstants.java
index 0f05414a219..7432e529dfc 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/index.html
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusConstants.java
@@ -1,5 +1,4 @@
-<!--
-/**
+/*
* 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
@@ -16,5 +15,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
--->
-<meta HTTP-EQUIV="REFRESH" content="0;url=/master-status"/>
+package org.apache.hadoop.hbase.master.http;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Constants used by the web UI JSP pages.
+ */
+@InterfaceAudience.Private
+public final class MasterStatusConstants {
+
+ public static final String FRAGS = "frags";
+ public static final String SERVER_NAMES = "serverNames";
+ public static final String SERVER_NAME = "serverName";
+ public static final String RS_GROUP_INFOS = "rsGroupInfos";
+ public static final String COLLECT_SERVERS = "collectServers";
+ public static final String FILTER = "filter";
+ public static final String FORMAT = "format";
+ public static final String PARENT = "parent";
+
+ private MasterStatusConstants() {
+ // Do not instantiate.
+ }
+}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java
index 09bb5375a5d..564e5f01124 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java
@@ -18,25 +18,13 @@
package org.apache.hadoop.hbase.master.http;
import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.ServerName;
-import org.apache.hadoop.hbase.client.RegionInfoBuilder;
-import org.apache.hadoop.hbase.master.HMaster;
-import org.apache.hadoop.hbase.master.RegionState;
-import org.apache.hadoop.hbase.master.ServerManager;
-import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
-import org.apache.hadoop.hbase.tmpl.master.MasterStatusTmpl;
-import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.yetus.audience.InterfaceAudience;
/**
- * The servlet responsible for rendering the index page of the master.
+ * Only kept for redirecting to master.jsp.
*/
@InterfaceAudience.Private
public class MasterStatusServlet extends HttpServlet {
@@ -44,52 +32,6 @@ public class MasterStatusServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
- assert master != null : "No Master in context!";
-
- response.setContentType("text/html");
-
- Configuration conf = master.getConfiguration();
-
- Map<String, Integer> frags = getFragmentationInfo(master, conf);
- ServerName metaLocation = null;
- List<ServerName> servers = null;
- Set<ServerName> deadServers = null;
-
- if (master.isActiveMaster()) {
- metaLocation = getMetaLocationOrNull(master);
- ServerManager serverManager = master.getServerManager();
- if (serverManager != null) {
- deadServers = serverManager.getDeadServers().copyServerNames();
- servers = serverManager.getOnlineServersList();
- }
- }
-
- MasterStatusTmpl tmpl =
- new MasterStatusTmpl().setFrags(frags).setMetaLocation(metaLocation).setServers(servers)
- .setDeadServers(deadServers).setCatalogJanitorEnabled(master.isCatalogJanitorEnabled());
-
- if (request.getParameter("filter") != null) tmpl.setFilter(request.getParameter("filter"));
- if (request.getParameter("format") != null) tmpl.setFormat(request.getParameter("format"));
- tmpl.render(response.getWriter(), master);
- }
-
- private ServerName getMetaLocationOrNull(HMaster master) {
- RegionStateNode rsn = master.getAssignmentManager().getRegionStates()
- .getRegionStateNode(RegionInfoBuilder.FIRST_META_REGIONINFO);
- if (rsn != null) {
- return rsn.isInState(RegionState.State.OPEN) ? rsn.getRegionLocation() : null;
- }
- return null;
- }
-
- private Map<String, Integer> getFragmentationInfo(HMaster master, Configuration conf)
- throws IOException {
- boolean showFragmentation = conf.getBoolean("hbase.master.ui.fragmentation.enabled", false);
- if (showFragmentation) {
- return FSUtils.getTableFragmentation(master);
- } else {
- return null;
- }
+ response.sendRedirect(request.getContextPath() + "/master.jsp");
}
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
similarity index 50%
copy from hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java
copy to hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
index 09bb5375a5d..221e43f8e11 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusServlet.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
@@ -20,61 +20,55 @@ package org.apache.hadoop.hbase.master.http;
import java.io.IOException;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
+import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.master.RegionState;
-import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
-import org.apache.hadoop.hbase.tmpl.master.MasterStatusTmpl;
import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.yetus.audience.InterfaceAudience;
/**
- * The servlet responsible for rendering the index page of the master.
+ * Utility used by the web UI JSP pages.
*/
@InterfaceAudience.Private
-public class MasterStatusServlet extends HttpServlet {
- private static final long serialVersionUID = 1L;
+public final class MasterStatusUtil {
- @Override
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
- HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
- assert master != null : "No Master in context!";
-
- response.setContentType("text/html");
-
- Configuration conf = master.getConfiguration();
-
- Map<String, Integer> frags = getFragmentationInfo(master, conf);
- ServerName metaLocation = null;
- List<ServerName> servers = null;
- Set<ServerName> deadServers = null;
+ private MasterStatusUtil() {
+ // Do not instantiate.
+ }
- if (master.isActiveMaster()) {
- metaLocation = getMetaLocationOrNull(master);
- ServerManager serverManager = master.getServerManager();
- if (serverManager != null) {
- deadServers = serverManager.getDeadServers().copyServerNames();
- servers = serverManager.getOnlineServersList();
+ public static String getUserTables(HMaster master, List<TableDescriptor> tables) {
+ if (master.isInitialized()) {
+ try {
+ Map<String, TableDescriptor> descriptorMap = master.getTableDescriptors().getAll();
+ if (descriptorMap != null) {
+ for (TableDescriptor desc : descriptorMap.values()) {
+ if (!desc.getTableName().isSystemTable()) {
+ tables.add(desc);
+ }
+ }
+ }
+ } catch (IOException e) {
+ return "Got user tables error, " + e.getMessage();
}
}
+ return null;
+ }
- MasterStatusTmpl tmpl =
- new MasterStatusTmpl().setFrags(frags).setMetaLocation(metaLocation).setServers(servers)
- .setDeadServers(deadServers).setCatalogJanitorEnabled(master.isCatalogJanitorEnabled());
-
- if (request.getParameter("filter") != null) tmpl.setFilter(request.getParameter("filter"));
- if (request.getParameter("format") != null) tmpl.setFormat(request.getParameter("format"));
- tmpl.render(response.getWriter(), master);
+ public static Map<String, Integer> getFragmentationInfo(HMaster master, Configuration conf)
+ throws IOException {
+ boolean showFragmentation = conf.getBoolean("hbase.master.ui.fragmentation.enabled", false);
+ if (showFragmentation) {
+ return FSUtils.getTableFragmentation(master);
+ } else {
+ return null;
+ }
}
- private ServerName getMetaLocationOrNull(HMaster master) {
+ public static ServerName getMetaLocationOrNull(HMaster master) {
RegionStateNode rsn = master.getAssignmentManager().getRegionStates()
.getRegionStateNode(RegionInfoBuilder.FIRST_META_REGIONINFO);
if (rsn != null) {
@@ -83,13 +77,13 @@ public class MasterStatusServlet extends HttpServlet {
return null;
}
- private Map<String, Integer> getFragmentationInfo(HMaster master, Configuration conf)
- throws IOException {
- boolean showFragmentation = conf.getBoolean("hbase.master.ui.fragmentation.enabled", false);
- if (showFragmentation) {
- return FSUtils.getTableFragmentation(master);
+ public static String serverNameLink(HMaster master, ServerName serverName) {
+ int infoPort = master.getRegionServerInfoPort(serverName);
+ String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
+ if (infoPort > 0) {
+ return "<a href=\"" + url + "\">" + serverName.getServerName() + "</a>";
} else {
- return null;
+ return serverName.getServerName();
}
}
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/RegionVisualizer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/RegionVisualizer.java
index 09171c3a8c2..ceb08bcedf2 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/RegionVisualizer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/RegionVisualizer.java
@@ -58,7 +58,7 @@ import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
/**
* Support class for the "Region Visualizer" rendered out of
- * {@code src/main/jamon/org/apache/hadoop/hbase/tmpl/master/RegionVisualizerTmpl.jamon}
+ * {@code src/main/resources/hbase-webapps/master/regionVisualizer.jsp}
*/
@InterfaceAudience.Private
public class RegionVisualizer extends AbstractHBaseTool {
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/assignmentManagerStatus.jsp b/hbase-server/src/main/resources/hbase-webapps/master/assignmentManagerStatus.jsp
new file mode 100644
index 00000000000..0966d04316b
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/assignmentManagerStatus.jsp
@@ -0,0 +1,117 @@
+<%--
+/**
+* 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="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.quotas.QuotaUtil"
+ import="org.apache.hadoop.hbase.HBaseConfiguration"
+ import="org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer"
+ import="org.apache.hadoop.hbase.master.assignment.AssignmentManager"
+ import="org.apache.hadoop.hbase.master.RegionState"
+ import="java.util.SortedSet"
+ import="org.apache.hadoop.hbase.master.assignment.RegionStates"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay" %>
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+ AssignmentManager assignmentManager = master.getAssignmentManager();
+ int limit = 100;
+
+ SortedSet<RegionState> rit = assignmentManager.getRegionStates().getRegionsInTransitionOrderedByTimestamp();
+
+if (!rit.isEmpty()) {
+ long currentTime = System.currentTimeMillis();
+ AssignmentManager.RegionInTransitionStat ritStat = assignmentManager.computeRegionInTransitionStat();
+
+ int numOfRITs = rit.size();
+ int ritsPerPage = Math.min(5, numOfRITs);
+ int numOfPages = (int) Math.ceil(numOfRITs * 1.0 / ritsPerPage);
+%>
+ <section>
+ <h2><a name="rit">Regions in Transition</a></h2>
+ <p><a href="/rits.jsp"><%= numOfRITs %> region(s) in transition.</a>
+ <% if(ritStat.hasRegionsTwiceOverThreshold()) { %>
+ <span class="label label-danger" style="font-size:100%;font-weight:normal">
+ <% } else if ( ritStat.hasRegionsOverThreshold()) { %>
+ <span class="label label-warning" style="font-size:100%;font-weight:normal">
+ <% } else { %>
+ <span>
+ <% } %>
+ <%= ritStat.getTotalRITsOverThreshold() %> region(s) in transition for
+ more than <%= ritStat.getRITThreshold() %> milliseconds.
+ </span>
+ </p>
+ <div class="tabbable">
+ <div class="tab-content">
+ <% int recordItr = 0; %>
+ <% for (RegionState rs : rit) { %>
+ <% if((recordItr % ritsPerPage) == 0 ) { %>
+ <% if(recordItr == 0) { %>
+ <div class="tab-pane active" id="tab_rits<%= (recordItr / ritsPerPage) + 1 %>">
+ <% } else { %>
+ <div class="tab-pane" id="tab_rits<%= (recordItr / ritsPerPage) + 1 %>">
+ <% } %>
+ <table class="table table-striped" style="margin-bottom:0px;"><tr><th>Region</th>
+ <th>State</th><th>RIT time (ms)</th> <th>Retries </th></tr>
+ <% } %>
+
+ <% if(ritStat.isRegionTwiceOverThreshold(rs.getRegion())) { %>
+ <tr class="alert alert-danger" role="alert">
+ <% } else if ( ritStat.isRegionOverThreshold(rs.getRegion())) { %>
+ <tr class="alert alert-warning" role="alert">
+ <% } else { %>
+ <tr>
+ <% } %>
+ <%
+ String retryStatus = "0";
+ RegionStates.RegionFailedOpen regionFailedOpen = assignmentManager
+ .getRegionStates().getFailedOpen(rs.getRegion());
+ if (regionFailedOpen != null) {
+ retryStatus = Integer.toString(regionFailedOpen.getRetries());
+ } else if (rs.getState() == RegionState.State.FAILED_OPEN) {
+ retryStatus = "Failed";
+ }
+ %>
+ <td><%= rs.getRegion().getEncodedName() %></td><td>
+ <%= RegionInfoDisplay.getDescriptiveNameFromRegionStateForDisplay(rs,
+ assignmentManager.getConfiguration()) %></td>
+ <td><%= (currentTime - rs.getStamp()) %> </td>
+ <td> <%= retryStatus %> </td>
+ </tr>
+ <% recordItr++; %>
+ <% if((recordItr % ritsPerPage) == 0) { %>
+ </table>
+ </div>
+ <% } %>
+ <% } %>
+
+ <% if((recordItr % ritsPerPage) != 0) { %>
+ <% for (; (recordItr % ritsPerPage) != 0 ; recordItr++) { %>
+ <tr><td colspan="3" style="height:61px"></td></tr>
+ <% } %>
+ </table>
+ </div>
+ <% } %>
+ </div>
+ <input type="hidden" id ="rit_page_num" value="<%= numOfRITs %>" />
+ <input type="hidden" id ="rit_per_page" value="<%= ritsPerPage %>" />
+ <nav id="rit_pagination"></nav>
+ </div>
+ </section>
+<% } %>
+
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/backupMasterStatus.jsp b/hbase-server/src/main/resources/hbase-webapps/master/backupMasterStatus.jsp
new file mode 100644
index 00000000000..cada34472c9
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/backupMasterStatus.jsp
@@ -0,0 +1,66 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hbase.thirdparty.com.google.common.base.Preconditions" %>
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+ if (!master.isActiveMaster()) {
+
+ ServerName active_master = master.getActiveMaster().orElse(null);
+ Preconditions.checkState(active_master != null, "Failed to retrieve active master's ServerName!");
+ int activeInfoPort = master.getActiveMasterInfoPort();
+%>
+ <div class="row inner_header">
+ <div class="page-header">
+ <h1>Backup Master <small><%= master.getServerName().getHostname() %></small></h1>
+ </div>
+ </div>
+ <h4>Current Active Master: <a href="//<%= active_master.getHostname() %>:<%= activeInfoPort %>/master.jsp"
+ target="_blank"><%= active_master.getHostname() %></a></h4>
+ <% } else { %>
+ <h2>Backup Masters</h2>
+
+ <table class="table table-striped">
+ <tr>
+ <th>ServerName</th>
+ <th>Port</th>
+ <th>Start Time</th>
+ </tr>
+ <%
+ Collection<ServerName> backup_masters = master.getBackupMasters();
+ ServerName [] backupServerNames = backup_masters.toArray(new ServerName[backup_masters.size()]);
+ Arrays.sort(backupServerNames);
+ for (ServerName serverName : backupServerNames) {
+ int infoPort = master.getBackupMasterInfoPort(serverName);
+ %>
+ <tr>
+ <td><a href="//<%= serverName.getHostname() %>:<%= infoPort %>/master.jsp"
+ target="_blank"><%= serverName.getHostname() %></a>
+ </td>
+ <td><%= serverName.getPort() %></td>
+ <td><%= new Date(serverName.getStartCode()) %></td>
+ </tr>
+ <% } %>
+ <tr><td>Total:<%= backupServerNames.length %></td>
+ </table>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/catalogTables.jsp b/hbase-server/src/main/resources/hbase-webapps/master/catalogTables.jsp
new file mode 100644
index 00000000000..5bc67e0b79e
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/catalogTables.jsp
@@ -0,0 +1,84 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.NamespaceDescriptor"
+ import="org.apache.hadoop.hbase.TableName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.quotas.QuotaUtil"
+ import="org.apache.hadoop.hbase.security.access.PermissionStorage"
+ import="org.apache.hadoop.hbase.security.visibility.VisibilityConstants"
+ import="org.apache.hadoop.hbase.tool.CanaryTool"
+ import="org.apache.hadoop.hbase.client.*"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ Map<String, Integer> frags = (Map<String, Integer>) request.getAttribute(MasterStatusConstants.FRAGS);
+
+ List<TableDescriptor> sysTables = master.isInitialized() ?
+ master.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR) : null;
+%>
+
+<%if (sysTables != null && sysTables.size() > 0) { %>
+<table class="table table-striped">
+ <tr>
+ <th>Table Name</th>
+ <% if (frags != null) { %>
+ <th title="Fragmentation - Will be 0% after a major compaction and fluctuate during normal usage.">Frag.</th>
+ <% } %>
+ <th>Description</th>
+ </tr>
+ <% for (TableDescriptor systemTable : sysTables) { %>
+ <tr>
+ <% TableName tableName = systemTable.getTableName();%>
+ <td><a href="table.jsp?name=<%= tableName %>"><%= tableName %></a></td>
+ <% if (frags != null) { %>
+ <td align="center"><%= frags.get(tableName.getNameAsString()) != null ? frags.get(tableName.getNameAsString()) + "%" : "n/a" %></td>
+ <% } %>
+ <% String description = null;
+ if (tableName.equals(TableName.META_TABLE_NAME)){
+ description = "The hbase:meta table holds references to all User Table regions.";
+ } else if (tableName.equals(CanaryTool.DEFAULT_WRITE_TABLE_NAME)){
+ description = "The hbase:canary table is used to sniff the write availability of"
+ + " each regionserver.";
+ } else if (tableName.equals(PermissionStorage.ACL_TABLE_NAME)){
+ description = "The hbase:acl table holds information about acl.";
+ } else if (tableName.equals(VisibilityConstants.LABELS_TABLE_NAME)){
+ description = "The hbase:labels table holds information about visibility labels.";
+ } else if (tableName.equals(TableName.NAMESPACE_TABLE_NAME)){
+ description = "The hbase:namespace table holds information about namespaces.";
+ } else if (tableName.equals(QuotaUtil.QUOTA_TABLE_NAME)){
+ description = "The hbase:quota table holds quota information about number" +
+ " or size of requests in a given time frame.";
+ } else if (tableName.equals(TableName.valueOf("hbase:rsgroup"))){
+ description = "The hbase:rsgroup table holds information about regionserver groups.";
+ } else if (tableName.equals(TableName.valueOf("hbase:replication"))) {
+ description = "The hbase:replication table tracks cross cluster replication through " +
+ "WAL file offsets.";
+ }
+ %>
+ <td><%= description %></td>
+ </tr>
+ <% } %>
+</table>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/deadRegionServers.jsp b/hbase-server/src/main/resources/hbase-webapps/master/deadRegionServers.jsp
new file mode 100644
index 00000000000..daef9a58eca
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/deadRegionServers.jsp
@@ -0,0 +1,96 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="java.util.*"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.master.DeadServer"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.hbase.master.ServerManager"
+ import="org.apache.hadoop.hbase.RSGroupTableAccessor" %>
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ ServerManager serverManager = master.getServerManager();
+
+ Set<ServerName> deadServers = null;
+
+ if (master.isActiveMaster()) {
+ if (serverManager != null) {
+ deadServers = serverManager.getDeadServers().copyServerNames();
+ }
+ }
+%>
+
+<% if (deadServers != null && deadServers.size() > 0) { %>
+<h2>Dead Region Servers</h2>
+<table class="table table-striped">
+ <tr>
+ <th></th>
+ <th>ServerName</th>
+ <th>Stop time</th>
+ <% if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
+ && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
+ && master.getServerManager().getOnlineServersList().size() > 0) { %>
+ <th>RSGroup</th>
+ <% } %>
+</tr>
+<%
+ List<RSGroupInfo> groups = null;
+ DeadServer deadServerUtil = master.getServerManager().getDeadServers();
+ if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
+ && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
+ && master.getServerManager().getOnlineServersList().size() > 0) {
+ groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
+ }
+ ServerName [] deadServerNames = deadServers.toArray(new ServerName[deadServers.size()]);
+ Arrays.sort(deadServerNames);
+ for (ServerName deadServerName: deadServerNames) {
+ String rsGroupName = null;
+ if (groups != null){
+ for (RSGroupInfo rsGroupInfo : groups) {
+ if (rsGroupInfo.containsServer(deadServerName.getAddress())) {
+ rsGroupName = rsGroupInfo.getName();
+ break;
+ }
+ }
+ if (rsGroupName == null) {
+ rsGroupName = RSGroupInfo.DEFAULT_GROUP;
+ }
+ }
+ %>
+ <tr>
+ <th></th>
+ <td><%= deadServerName %></td>
+ <td><%= deadServerUtil.getTimeOfDeath(deadServerName) %></td>
+ <% if (rsGroupName != null) { %>
+ <td><%= rsGroupName %></td>
+ <% } %>
+ </tr>
+ <%
+ }
+ %>
+ <tr>
+ <th>Total: </th>
+ <td>servers: <%= deadServers.size() %></td>
+ <th></th>
+ </tr>
+</table>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/header.jsp b/hbase-server/src/main/resources/hbase-webapps/master/header.jsp
index 267658d1ca0..0c03b36e6f2 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/header.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/header.jsp
@@ -42,13 +42,13 @@
<body>
<nav class="navbar navbar-expand-md navbar-light fixed-top bg-light">
<div class="container-fluid">
- <a class="navbar-brand" href="/master-status"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a>
+ <a class="navbar-brand" href="/master.jsp"><img src="/static/hbase_logo_small.png" alt="HBase Logo"/></a>
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
- <li class="nav-item"><a class="nav-link" href="/master-status">Home</a></li>
+ <li class="nav-item"><a class="nav-link" href="/master.jsp">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/tablesDetailed.jsp">Table Details</a></li>
<% if (master.isActiveMaster()){ %>
<li class="nav-item"><a class="nav-link" href="/procedures.jsp">Procedures & Locks</a></li>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/index.html b/hbase-server/src/main/resources/hbase-webapps/master/index.html
index 0f05414a219..74c14cb3e64 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/index.html
+++ b/hbase-server/src/main/resources/hbase-webapps/master/index.html
@@ -17,4 +17,4 @@
* limitations under the License.
*/
-->
-<meta HTTP-EQUIV="REFRESH" content="0;url=/master-status"/>
+<meta HTTP-EQUIV="REFRESH" content="0;url=/master.jsp"/>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/master.jsp b/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
index 6651c9336b1..7e537123851 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
@@ -17,4 +17,146 @@
* limitations under the License.
*/
--%>
-<meta HTTP-EQUIV="REFRESH" content="0;url=/master-status"/>
+<%@ page contentType="text/html;charset=UTF-8"
+ import="java.util.*"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.conf.Configuration"
+ import="org.apache.hadoop.hbase.util.*"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ String filter = request.getParameter(MasterStatusConstants.FILTER);
+ String format = request.getParameter(MasterStatusConstants.FORMAT);
+ if (format != null && format.equals("json")) {
+ request.setAttribute(MasterStatusConstants.FILTER, filter);
+ request.setAttribute(MasterStatusConstants.FORMAT, "json");
+ %>
+ <jsp:include page="taskMonitor.jsp"/>
+<%
+ return;
+ }
+%>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ Configuration conf = master.getConfiguration();
+ Map<String, Integer> frags = MasterStatusUtil.getFragmentationInfo(master, conf);
+
+ String title;
+ if(master.isActiveMaster()) {
+ title = "Master: ";
+ } else {
+ title = "Backup Master: ";
+ }
+ title += master.getServerName().getHostname();
+ pageContext.setAttribute("pageTitle", title);
+
+ ServerName metaLocation = null;
+
+ if (master.isActiveMaster()) {
+ metaLocation = MasterStatusUtil.getMetaLocationOrNull(master);
+ }
+%>
+
+<jsp:include page="header.jsp">
+ <jsp:param name="pageTitle" value="${pageTitle}"/>
+</jsp:include>
+
+<div class="container-fluid content">
+ <% if(master.isActiveMaster()) { %>
+ <div class="row inner_header top_header">
+ <div class="page-header">
+ <h1>Master <small><%= master.getServerName().getHostname() %></small></h1>
+ </div>
+ </div>
+
+ <div class="row">
+ <jsp:include page="warnings.jsp"/>
+ </div>
+ <div class="row">
+ <section>
+ <h2><a name="regionservers">Region Servers</a></h2>
+ <jsp:include page="regionServerList.jsp"/>
+
+ <jsp:include page="deadRegionServers.jsp"/>
+ </section>
+ </div>
+ <div class="row">
+ <section>
+ <jsp:include page="backupMasterStatus.jsp"/>
+ </section>
+ </div>
+ <div class="row">
+ <section>
+ <h2><a name="tables">Tables</a></h2>
+ <div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link active" href="#tab_userTables" data-bs-toggle="tab" role="tab">User Tables</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_catalogTables" data-bs-toggle="tab" role="tab">System Tables</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_userSnapshots" data-bs-toggle="tab" role="tab">Snapshots</a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="tab_userTables" role="tabpanel">
+ <%if (metaLocation != null) { %>
+ <% request.setAttribute(MasterStatusConstants.FRAGS, frags); %>
+ <jsp:include page="userTables.jsp"/>
+ <% } %>
+ </div>
+ <div class="tab-pane" id="tab_catalogTables" role="tabpanel">
+ <%if (metaLocation != null) { %>
+ <% request.setAttribute(MasterStatusConstants.FRAGS, frags); %>
+ <jsp:include page="catalogTables.jsp"/>
+ <% } %>
+ </div>
+ <div class="tab-pane" id="tab_userSnapshots" role="tabpanel">
+ <%-- tab.js will load userSnapshots.jsp with an AJAX request here. --%>
+ </div>
+ </div>
+ </div>
+ </section>
+ </div>
+ <div class="row">
+ <section>
+ <h2><a name="region_visualizer"></a>Region Visualizer</h2>
+ <jsp:include page="regionVisualizer.jsp"/>
+ </section>
+ </div>
+ <div class="row">
+ <section>
+ <h2><a name="peers">Peers</a></h2>
+ <jsp:include page="peerConfigs.jsp"/>
+ </section>
+ </div>
+<% } else { %>
+ <section>
+ <jsp:include page="backupMasterStatus.jsp"/>
+ </section>
+<% } %>
+
+ <section>
+ <jsp:include page="taskMonitor.jsp"/>
+ </section>
+
+ <section>
+ <% request.setAttribute(MasterStatusConstants.FRAGS, frags); %>
+ <jsp:include page="softwareAttributes.jsp"/>
+ </section>
+
+</div> <!-- /.container-fluid content -->
+
+
+<jsp:include page="footer.jsp"/>
+
+<script src="/static/js/jquery.tablesorter.min.js" type="text/javascript"></script>
+<script src="/static/js/parser-date-iso8601.min.js" type="text/javascript"></script>
+<script src="/static/js/jqSpager.js" type="text/javascript"></script>
+<script src="/static/js/masterStatusInit.js" type="text/javascript"></script>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/peerConfigs.jsp b/hbase-server/src/main/resources/hbase-webapps/master/peerConfigs.jsp
new file mode 100644
index 00000000000..0cf22991b60
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/peerConfigs.jsp
@@ -0,0 +1,82 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.replication.ReplicationPeerDescription"
+ import="org.apache.hadoop.hbase.replication.ReplicationPeerConfig"
+ import="org.apache.hadoop.hbase.client.replication.ReplicationPeerConfigUtil"
+ import="org.apache.hadoop.hbase.util.Strings" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ List<ReplicationPeerDescription> peers = null;
+ if (master.getReplicationPeerManager() != null) {
+ peers = master.getReplicationPeerManager().listPeers(null);
+ }
+%>
+ <table class="table table-striped">
+ <tr>
+ <th>Peer Id</th>
+ <th>Cluster Key</th>
+ <th>Endpoint</th>
+ <th>State</th>
+ <th>IsSerial</th>
+ <th>Bandwidth</th>
+ <th>ReplicateAll</th>
+ <th>Namespaces</th>
+ <th>Exclude Namespaces</th>
+ <th>Table Cfs</th>
+ <th>Exclude Table Cfs</th>
+ </tr>
+<% if (peers != null && peers.size() > 0) { %>
+ <% for (ReplicationPeerDescription peer : peers) { %>
+ <%
+ String peerId = peer.getPeerId();
+ ReplicationPeerConfig peerConfig = peer.getPeerConfig();
+ %>
+ <tr>
+ <td><%= peerId %></td>
+ <td><%= peerConfig.getClusterKey() %></td>
+ <td><%= peerConfig.getReplicationEndpointImpl() %></td>
+ <td><%= peer.isEnabled() ? "ENABLED" : "DISABLED" %></td>
+ <td><%= peerConfig.isSerial() %></td>
+ <td><%= peerConfig.getBandwidth() == 0? "UNLIMITED" : Strings.humanReadableInt(peerConfig.getBandwidth()) %></td>
+ <td><%= peerConfig.replicateAllUserTables() %></td>
+ <td>
+ <%= peerConfig.getNamespaces() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getNamespaces()).replaceAll(";", "; ") %>
+ </td>
+ <td>
+ <%= peerConfig.getExcludeNamespaces() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getExcludeNamespaces()).replaceAll(";", "; ") %>
+ </td>
+ <td>
+ <%= peerConfig.getTableCFsMap() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getTableCFsMap()).replaceAll(";", "; ") %>
+ </td>
+ <td>
+ <%= peerConfig.getExcludeTableCFsMap() == null ? "" : ReplicationPeerConfigUtil.convertToString(peerConfig.getExcludeTableCFsMap()).replaceAll(";", "; ") %>
+ </td>
+ </tr>
+ <% } %>
+<% } %>
+
+<tr><td>Total: <%= (peers != null) ? peers.size() : 0 %></td></tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerList.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerList.jsp
new file mode 100644
index 00000000000..9fc0adda00c
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerList.jsp
@@ -0,0 +1,90 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.ServerManager" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+ ServerManager serverManager = master.getServerManager();
+
+ List<ServerName> servers = null;
+
+ if (master.isActiveMaster()) {
+ if (serverManager != null) {
+ servers = serverManager.getOnlineServersList();
+ }
+ }
+%>
+
+<%
+ if (servers != null && servers.size() > 0) {
+
+ ServerName [] serverNames = servers.toArray(new ServerName[servers.size()]);
+ Arrays.sort(serverNames);
+%>
+
+<div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link active" href="#tab_baseStats" data-bs-toggle="tab" role="tab">Base Stats</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_memoryStats" data-bs-toggle="tab" role="tab">Memory</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_requestStats" data-bs-toggle="tab" role="tab">Requests</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_storeStats" data-bs-toggle="tab" role="tab">Storefiles</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_compactStats" data-bs-toggle="tab" role="tab">Compactions</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_replicationStats" data-bs-toggle="tab" role="tab">Replications</a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <% request.setAttribute("serverNames", serverNames); %>
+ <div class="tab-pane active" id="tab_baseStats" role="tabpanel">
+ <jsp:include page="regionServerListBaseStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_memoryStats" role="tabpanel">
+ <jsp:include page="regionServerListMemoryStats.jsp" />
+ </div>
+ <div class="tab-pane" id="tab_requestStats" role="tabpanel">
+ <jsp:include page="regionServerListRequestStats.jsp" />
+ </div>
+ <div class="tab-pane" id="tab_storeStats" role="tabpanel">
+ <jsp:include page="regionServerListStoreStats.jsp" />
+ </div>
+ <div class="tab-pane" id="tab_compactStats" role="tabpanel">
+ <jsp:include page="regionServerListCompactionStats.jsp" />
+ </div>
+ <div class="tab-pane" id="tab_replicationStats" role="tabpanel">
+ <jsp:include page="regionServerListReplicationStats.jsp" />
+ </div>
+ </div>
+</div>
+
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListBaseStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListBaseStats.jsp
new file mode 100644
index 00000000000..c3ae071a42c
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListBaseStats.jsp
@@ -0,0 +1,134 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.util.VersionInfo"
+ import="org.apache.hadoop.hbase.RSGroupTableAccessor"
+ import="org.apache.hadoop.hbase.master.ServerManager"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="java.util.*"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.util.StringUtils"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+
+<table id="baseStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>ServerName</th>
+ <th>State</th>
+ <th class="cls_dateTime">Start time</th>
+ <th>Last contact</th>
+ <th>Version</th>
+ <th class="cls_separator">Requests Per Second</th>
+ <th class="cls_separator">Num. Regions</th>
+ <% if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
+ && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
+ && master.getServerManager().getOnlineServersList().size() > 0) { %>
+ <th>RSGroup</th>
+ <% } %>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+ int totalRegions = 0;
+ int totalRequestsPerSecond = 0;
+ int inconsistentNodeNum = 0;
+ String state = "Normal";
+ String masterVersion = VersionInfo.getVersion();
+ Set<ServerName> decommissionedServers = new HashSet<>(master.listDecommissionedRegionServers());
+
+ String rsGroupName = "default";
+ List<RSGroupInfo> groups;
+ Map<Address, RSGroupInfo> server2GroupMap = new HashMap<>();
+ if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
+ && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
+ && master.getServerManager().getOnlineServersList().size() > 0) {
+ groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
+ groups.forEach(group -> {
+ group.getServers().forEach(address -> server2GroupMap.put(address, group));
+ });
+ }
+
+ for (ServerName serverName: serverNames) {
+ if (decommissionedServers.contains(serverName)) {
+ state = "Decommissioned";
+ }
+ ServerMetrics sl = master.getServerManager().getLoad(serverName);
+ String version = master.getRegionServerVersion(serverName);
+ if (!masterVersion.equals(version)) {
+ inconsistentNodeNum ++;
+ }
+
+ double requestsPerSecond = 0.0;
+ int numRegionsOnline = 0;
+ long lastContact = 0;
+
+ if (sl != null) {
+ requestsPerSecond = sl.getRequestCountPerSecond();
+ numRegionsOnline = sl.getRegionMetrics().size();
+ totalRegions += sl.getRegionMetrics().size();
+ totalRequestsPerSecond += sl.getRequestCountPerSecond();
+ lastContact = (System.currentTimeMillis() - sl.getReportTimestamp())/1000;
+ }
+ long startcode = serverName.getStartcode();
+
+ if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null
+ && master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null
+ && master.getServerManager().getOnlineServersList().size() > 0) {
+ rsGroupName = server2GroupMap.get(serverName.getAddress()).getName();
+ }
+%>
+<tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+ <td><%= state %></td>
+ <td><%= new Date(startcode) %></td>
+ <td><%= StringUtils.TraditionalBinaryPrefix.long2String(lastContact, "s", 1) %></td>
+ <td><%= version %></td>
+ <td><%= String.format("%,.0f", requestsPerSecond) %></td>
+ <td><%= String.format("%,d", numRegionsOnline) %></td>
+ <% if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null) { %>
+ <% if (master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null &&
+ master.getServerManager().getOnlineServersList().size() > 0) { %>
+ <td><%= rsGroupName %></td>
+ <% } %>
+ <% } %>
+</tr>
+<% } %>
+ </tbody>
+ <tr><td>Total:<%= serverNames.length %></td>
+<td></td>
+<td></td>
+<td></td>
+<% if(inconsistentNodeNum > 0) {%>
+<td style="color:red;"><%= inconsistentNodeNum %> nodes with inconsistent version</td>
+<% } else { %>
+ <td></td>
+<% } %>
+ <td><%= totalRequestsPerSecond %></td>
+<td><%= totalRegions %></td>
+</tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListCompactionStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListCompactionStats.jsp
new file mode 100644
index 00000000000..f59f48522d9
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListCompactionStats.jsp
@@ -0,0 +1,78 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+
+<table id="compactionStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>ServerName</th>
+ <th class="cls_separator">Num. Compacting Cells</th>
+ <th class="cls_separator">Num. Compacted Cells</th>
+ <th class="cls_separator">Remaining Cells</th>
+ <th>Compaction Progress</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+for (ServerName serverName: serverNames) {
+
+ServerMetrics sl = master.getServerManager().getLoad(serverName);
+if (sl != null) {
+long totalCompactingCells = 0;
+long totalCompactedCells = 0;
+for (RegionMetrics rl : sl.getRegionMetrics().values()) {
+ totalCompactingCells += rl.getCompactingCellCount();
+ totalCompactedCells += rl.getCompactedCellCount();
+}
+String percentDone = "";
+if (totalCompactingCells > 0) {
+ percentDone = String.format("%.2f", 100 *
+ ((float) totalCompactedCells / totalCompactingCells)) + "%";
+}
+%>
+<tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+ <td><%= String.format("%,d", totalCompactingCells) %></td>
+ <td><%= String.format("%,d", totalCompactedCells) %></td>
+ <td><%= String.format("%,d", totalCompactingCells - totalCompactedCells) %></td>
+ <td><%= percentDone %></td>
+ </tr>
+<%
+} else {
+%>
+ <% request.setAttribute("serverName", serverName); %>
+ <jsp:include page="regionServerListEmptyStat.jsp"/>
+<%
+ }
+}
+%>
+</tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/master.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListEmptyStat.jsp
similarity index 56%
copy from hbase-server/src/main/resources/hbase-webapps/master/master.jsp
copy to hbase-server/src/main/resources/hbase-webapps/master/regionServerListEmptyStat.jsp
index 6651c9336b1..c269f7113f2 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListEmptyStat.jsp
@@ -17,4 +17,22 @@
* limitations under the License.
*/
--%>
-<meta HTTP-EQUIV="REFRESH" content="0;url=/master-status"/>
+<%@ page contentType="text/html;charset=UTF-8"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName serverName = (ServerName) request.getAttribute(MasterStatusConstants.SERVER_NAME);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+<tr>
+<td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListMemoryStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListMemoryStats.jsp
new file mode 100644
index 00000000000..f3b743e42d1
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListMemoryStats.jsp
@@ -0,0 +1,90 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.Size"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+
+<table id="memoryStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>ServerName</th>
+ <th class="cls_filesize">Used Heap</th>
+ <th class="cls_filesize">Max Heap</th>
+ <th class="cls_filesize">Memstore Size</th>
+
+ </tr>
+ </thead>
+ <tbody>
+<%
+final String ZEROMB = "0 MB";
+for (ServerName serverName: serverNames) {
+ String usedHeapStr = ZEROMB;
+ String maxHeapStr = ZEROMB;
+ String memStoreSizeMBStr = ZEROMB;
+ ServerMetrics sl = master.getServerManager().getLoad(serverName);
+ if (sl != null) {
+ long memStoreSizeMB = 0;
+ for (RegionMetrics rl : sl.getRegionMetrics().values()) {
+ memStoreSizeMB += rl.getMemStoreSize().get(Size.Unit.MEGABYTE);
+ }
+ if (memStoreSizeMB > 0) {
+ memStoreSizeMBStr = TraditionalBinaryPrefix.long2String(memStoreSizeMB
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+
+ double usedHeapSizeMB = sl.getUsedHeapSize().get(Size.Unit.MEGABYTE);
+ if (usedHeapSizeMB > 0) {
+ usedHeapStr = TraditionalBinaryPrefix.long2String((long) usedHeapSizeMB
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ double maxHeapSizeMB = sl.getMaxHeapSize().get(Size.Unit.MEGABYTE);
+ if (maxHeapSizeMB > 0) {
+ maxHeapStr = TraditionalBinaryPrefix.long2String((long) maxHeapSizeMB
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+%>
+<tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+ <td><%= usedHeapStr %></td>
+ <td><%= maxHeapStr %></td>
+ <td><%= memStoreSizeMBStr %></td>
+ </tr>
+<%
+} else {
+%>
+ <% request.setAttribute("serverName", serverName); %>
+ <jsp:include page="regionServerListEmptyStat.jsp"/>
+<%
+ }
+}
+%>
+</tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListReplicationStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListReplicationStats.jsp
new file mode 100644
index 00000000000..1a497d2fd1d
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListReplicationStats.jsp
@@ -0,0 +1,90 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.replication.ReplicationLoadSource"
+ import="org.apache.hadoop.hbase.util.Pair"
+ import="java.util.*"
+ import="org.apache.hadoop.hbase.procedure2.util.StringUtils"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ HashMap<String, List<Pair<ServerName, ReplicationLoadSource>>> replicationLoadSourceMap
+ = master.getReplicationLoad(serverNames);
+ List<String> peers = null;
+ if (replicationLoadSourceMap != null && replicationLoadSourceMap.size() > 0){
+ peers = new ArrayList<>(replicationLoadSourceMap.keySet());
+ Collections.sort(peers);
+ }
+%>
+
+<% if (replicationLoadSourceMap != null && replicationLoadSourceMap.size() > 0) { %>
+
+<div class="tabbable">
+ <ul class="nav nav-tabs">
+ <%
+ String active = "active";
+ for (String peer : peers){
+ %>
+ <li class=<%= active %>><a href="#tab_<%= peer %>" data-bs-toggle="tab">Peer <%= peer %></a> </li>
+ <%
+ active = "";
+ }
+ %>
+ </ul>
+ <div class="tab-content">
+ <%
+ active = "active";
+ for (String peer : peers){
+ %>
+ <div class="tab-pane <%= active %>" id="tab_<%= peer %>">
+ <table class="table table-striped">
+ <tr>
+ <th>Server</th>
+ <th>AgeOfLastShippedOp</th>
+ <th>SizeOfLogQueue</th>
+ <th>ReplicationLag</th>
+ </tr>
+
+ <% for (Pair<ServerName, ReplicationLoadSource> pair: replicationLoadSourceMap.get(peer)) { %>
+ <tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, pair.getFirst()) %></td>
+ <td><%= StringUtils.humanTimeDiff(pair.getSecond().getAgeOfLastShippedOp()) %></td>
+ <td><%= pair.getSecond().getSizeOfLogQueue() %></td>
+ <td><%= pair.getSecond().getReplicationLag() == Long.MAX_VALUE ? "UNKNOWN" : StringUtils.humanTimeDiff(pair.getSecond().getReplicationLag()) %></td>
+ </tr>
+ <% } %>
+ </table>
+</div>
+<%
+ active = "";
+ }
+ %>
+ </div>
+ <p>If the replication delay is UNKNOWN, that means this walGroup doesn't start replicate yet and it may get disabled.</p>
+ </div>
+<% } else { %>
+ <p>No Peers Metrics</p>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListRequestStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListRequestStats.jsp
new file mode 100644
index 00000000000..082716c69eb
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListRequestStats.jsp
@@ -0,0 +1,75 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+
+<table id="requestStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>ServerName</th>
+ <th class="cls_separator">Request Per Second</th>
+ <th class="cls_separator">Read Request Count</th>
+ <th class="cls_separator">Filtered Read Request Count</th>
+ <th class="cls_separator">Write Request Count</th>
+ </tr>
+ </thead>
+ <tbody>
+<%
+ for (ServerName serverName: serverNames) {
+
+ ServerMetrics sl = master.getServerManager().getLoad(serverName);
+ if (sl != null) {
+ long readRequestCount = 0;
+ long writeRequestCount = 0;
+ long filteredReadRequestCount = 0;
+ for (RegionMetrics rl : sl.getRegionMetrics().values()) {
+ readRequestCount += rl.getReadRequestCount();
+ writeRequestCount += rl.getWriteRequestCount();
+ filteredReadRequestCount += rl.getFilteredReadRequestCount();
+ }
+%>
+<tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+ <td><%= String.format("%,d", sl.getRequestCountPerSecond()) %></td>
+ <td><%= String.format("%,d", readRequestCount) %></td>
+ <td><%= String.format("%,d", filteredReadRequestCount) %></td>
+ <td><%= String.format("%,d", writeRequestCount) %></td>
+</tr>
+<%
+} else {
+%>
+ <% request.setAttribute(MasterStatusConstants.SERVER_NAME, serverName); %>
+ <jsp:include page="regionServerListEmptyStat.jsp"/>
+<%
+ }
+}
+%>
+</tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionServerListStoreStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListStoreStats.jsp
new file mode 100644
index 00000000000..721105c66ef
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionServerListStoreStats.jsp
@@ -0,0 +1,108 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.Size"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
+
+<%
+ ServerName[] serverNames = (ServerName[]) request.getAttribute(MasterStatusConstants.SERVER_NAMES);
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+%>
+<table id="storeStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>ServerName</th>
+ <th class="cls_separator">Num. Stores</th>
+ <th class="cls_separator">Num. Storefiles</th>
+ <th class="cls_filesize">Storefile Size Uncompressed</th>
+ <th class="cls_filesize">Storefile Size</th>
+ <th class="cls_filesize">Index Size</th>
+ <th class="cls_filesize">Bloom Size</th>
+ </tr>
+ </thead>
+ <tbody>
+ <%
+final String ZEROKB = "0 KB";
+final String ZEROMB = "0 MB";
+for (ServerName serverName: serverNames) {
+
+ String storeUncompressedSizeMBStr = ZEROMB;
+ String storeFileSizeMBStr = ZEROMB;
+ String totalStaticIndexSizeKBStr = ZEROKB;
+ String totalStaticBloomSizeKBStr = ZEROKB;
+ ServerMetrics sl = master.getServerManager().getLoad(serverName);
+ if (sl != null) {
+ long storeCount = 0;
+ long storeFileCount = 0;
+ long storeUncompressedSizeMB = 0;
+ long storeFileSizeMB = 0;
+ long totalStaticIndexSizeKB = 0;
+ long totalStaticBloomSizeKB = 0;
+ for (RegionMetrics rl : sl.getRegionMetrics().values()) {
+ storeCount += rl.getStoreCount();
+ storeFileCount += rl.getStoreFileCount();
+ storeUncompressedSizeMB += rl.getUncompressedStoreFileSize().get(Size.Unit.MEGABYTE);
+ storeFileSizeMB += rl.getStoreFileSize().get(Size.Unit.MEGABYTE);
+ totalStaticIndexSizeKB += rl.getStoreFileUncompressedDataIndexSize().get(Size.Unit.KILOBYTE);
+ totalStaticBloomSizeKB += rl.getBloomFilterSize().get(Size.Unit.KILOBYTE);
+ }
+ if (storeUncompressedSizeMB > 0) {
+ storeUncompressedSizeMBStr = TraditionalBinaryPrefix.
+ long2String(storeUncompressedSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (storeFileSizeMB > 0) {
+ storeFileSizeMBStr = TraditionalBinaryPrefix.
+ long2String(storeFileSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (totalStaticIndexSizeKB > 0) {
+ totalStaticIndexSizeKBStr = TraditionalBinaryPrefix.
+ long2String(totalStaticIndexSizeKB * TraditionalBinaryPrefix.KILO.value, "B", 1);
+ }
+ if (totalStaticBloomSizeKB > 0) {
+ totalStaticBloomSizeKBStr = TraditionalBinaryPrefix.
+ long2String(totalStaticBloomSizeKB * TraditionalBinaryPrefix.KILO.value, "B", 1);
+ }
+%>
+<tr>
+ <td><%= MasterStatusUtil.serverNameLink(master, serverName) %></td>
+ <td><%= String.format("%,d", storeCount) %></td>
+ <td><%= String.format("%,d", storeFileCount) %></td>
+ <td><%= storeUncompressedSizeMBStr %></td>
+ <td><%= storeFileSizeMBStr %></td>
+ <td><%= totalStaticIndexSizeKBStr %></td>
+ <td><%= totalStaticBloomSizeKBStr %></td>
+ </tr>
+<%
+} else {
+%>
+ <% request.setAttribute("serverName", serverName); %>
+ <jsp:include page="regionServerListEmptyStat.jsp"/>
+<%
+ }
+}
+%>
+</tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/regionVisualizer.jsp b/hbase-server/src/main/resources/hbase-webapps/master/regionVisualizer.jsp
new file mode 100644
index 00000000000..a0cf85086df
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/regionVisualizer.jsp
@@ -0,0 +1,120 @@
+<%--
+/**
+ * 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.
+ */
+--%>
+
+<script type="text/javascript" src="/static/js/vega.min.js"></script>
+<script type="text/javascript" src="/static/js/vega-lite.min.js"></script>
+<script type="text/javascript" src="/static/js/vega-embed.min.js"></script>
+
+<div id="vis" style="width:80%;"></div>
+<script type="text/javascript">
+ vega.expressionFunction('values', function(obj) { return Object.values(obj); });
+ var vlSpec = {
+ $schema: 'https://vega.github.io/schema/vega-lite/v5.json',
+ description: 'Total `storefileSize` per Region Server',
+ data: {
+ name: 'region_info',
+ url: '/api/v1/admin/cluster_metrics/live_servers',
+ format: { type: 'json', property: 'data' }
+ },
+ transform: [
+ { calculate: "split(datum.server_name.server_name, ',', 1)[0]", as: 'server_name' },
+ { calculate: 'values(datum.region_status)', as: 'region_status' },
+ { flatten: ['region_status'] },
+ { calculate: "split(datum.region_status.name, ',', 1)[0]", as: 'table_name' },
+ { calculate: "split(datum.region_status.name, ',', 3)[2]", as: 'region_id' },
+ ],
+ vconcat: [{
+ title: {
+ text: 'Total `storefileSize` per Region Server',
+ align: 'center'
+ },
+ height: 250,
+ width: 'container',
+ mark: { type: 'bar', tooltip: true },
+ params: [{
+ name: 'legend_selection',
+ select: { type: 'point', fields: ['table_name'] },
+ bind: 'legend'
+ }],
+ encoding: {
+ x: {
+ title:'Region Server',
+ field: 'server_name',
+ type: 'nominal',
+ axis: {
+ labelAngle: 90,
+ labelOverlap: 'greedy'
+ },
+ scale: { domain: { param: 'brush' } },
+ sort: '-y'
+ },
+ y: {
+ title: 'Total StoreFileSize',
+ field: 'region_status.store_file_size',
+ type: 'quantitative',
+ aggregate: 'sum',
+ format: '.4s',
+ axis: { format: '.2s' },
+ scale: { domainMin: 0 }
+ },
+ color: {
+ field: 'table_name',
+ type: 'nominal',
+ title: 'Table'
+ },
+ opacity: {
+ condition: { param: 'legend_selection', value: 0.9 },
+ value: 0.2
+ }
+ }
+ }, {
+ mark: 'bar',
+ height: 50,
+ width: 'container',
+ params: [{
+ name: 'brush',
+ select: { type: 'interval', encodings: ['x'] }
+ }],
+ encoding: {
+ x: {
+ field: 'server_name',
+ type: 'nominal',
+ axis: null,
+ sort: '-y'
+ },
+ y: {
+ field: 'region_status.store_file_size',
+ aggregate: 'sum',
+ axis: null
+ },
+ color: {
+ field: 'table_name',
+ title: 'Table'
+ }
+ }
+ }]
+ };
+ vegaEmbed('#vis', vlSpec)
+ .then(function(result) {
+ //result.view.logger(vega.Debug);
+ //console.log(result.view.data('region_info'));
+ })
+ .catch(console.Error);
+</script>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rits.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rits.jsp
index b08c4a37f87..d5f0e7f85cb 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/rits.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rits.jsp
@@ -32,7 +32,7 @@
import="org.apache.hadoop.hbase.master.assignment.TransitRegionStateProcedure"
import="org.apache.hadoop.hbase.util.GsonUtil"
import="org.apache.hbase.thirdparty.com.google.gson.Gson"
-%>
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
<%
HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
List<RegionStateNode> rit = master.getAssignmentManager().getRegionsInTransition();
@@ -44,11 +44,11 @@
.collect(Collectors.toList());
}
- String format = request.getParameter("format");
+ String format = request.getParameter(MasterStatusConstants.FORMAT);
if(format == null || format.isEmpty()){
format = "html";
}
- String filter = request.getParameter("filter");
+ String filter = request.getParameter(MasterStatusConstants.FILTER);
Collections.sort(rit, new Comparator<RegionStateNode>() {
@Override
public int compare(RegionStateNode o1, RegionStateNode o2) {
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupList.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupList.jsp
new file mode 100644
index 00000000000..9c03de19ca2
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupList.jsp
@@ -0,0 +1,79 @@
+<%--
+/**
+* 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="org.apache.hadoop.hbase.master.HMaster"
+ import="java.util.Collections"
+ import="java.util.List"
+ import="java.util.Map"
+ import="java.util.stream.Collectors"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.RSGroupTableAccessor" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+ List<RSGroupInfo> groups = RSGroupTableAccessor.getAllRSGroupInfo(master.getConnection());
+%>
+
+<%if (groups != null && groups.size() > 0)%>
+
+<%
+ RSGroupInfo [] rsGroupInfos = groups.toArray(new RSGroupInfo[groups.size()]);
+ Map<Address, ServerMetrics> collectServers = Collections.emptyMap();
+ if (master.getServerManager() != null) {
+ collectServers =
+ master.getServerManager().getOnlineServers().entrySet().stream()
+ .collect(Collectors.toMap(p -> p.getKey().getAddress(), Map.Entry::getValue));
+ }
+%>
+
+<div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item"><a class="nav-link active" href="#tab_rsgroup_baseStats" data-bs-toggle="tab" role="tab">Base Stats</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_memoryStats" data-bs-toggle="tab" role="tab">Memory</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_requestStats" data-bs-toggle="tab" role="tab">Requests</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_storeStats" data-bs-toggle="tab" role="tab">Storefiles</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_rsgroup_compactStats" data-bs-toggle="tab" role="tab">Compactions</a></li>
+ </ul>
+ <div class="tab-content">
+
+ <% request.setAttribute(MasterStatusConstants.RS_GROUP_INFOS, rsGroupInfos); %>
+ <% request.setAttribute(MasterStatusConstants.COLLECT_SERVERS, collectServers); %>
+
+ <div class="tab-pane active" id="tab_rsgroup_baseStats" role="tabpanel">
+ <jsp:include page="rsGroupListBaseStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_rsgroup_memoryStats" role="tabpanel">
+ <jsp:include page="rsGroupListMemoryStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_rsgroup_requestStats" role="tabpanel">
+ <jsp:include page="rsGroupListRequestStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_rsgroup_storeStats" role="tabpanel">
+ <jsp:include page="rsGroupListStoreStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_rsgroup_compactStats" role="tabpanel">
+ <jsp:include page="rsGroupListCompactStats.jsp"/>
+ </div>
+ </div>
+</div>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListBaseStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListBaseStats.jsp
new file mode 100644
index 00000000000..60b56867f26
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListBaseStats.jsp
@@ -0,0 +1,101 @@
+<%--
+/**
+* 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="org.apache.hadoop.hbase.master.HMaster"
+ import="java.util.Map"
+ import="java.util.Set"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.util.StringUtils"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+ RSGroupInfo [] rsGroupInfos = (RSGroupInfo[]) request.getAttribute(MasterStatusConstants.RS_GROUP_INFOS);
+ Map<Address, ServerMetrics> collectServers = (Map<Address, ServerMetrics>) request.getAttribute(MasterStatusConstants.COLLECT_SERVERS);
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>RSGroup Name</th>
+ <th>Num. Online Servers</th>
+ <th>Num. Dead Servers</th>
+ <th>Num. Tables</th>
+ <th>Requests Per Second</th>
+ <th>Num. Regions</th>
+ <th>Average Load</th>
+ </tr>
+ <%
+ int totalOnlineServers = 0;
+ int totalDeadServers = 0;
+ int totalTables = 0;
+ int totalRequests = 0;
+ int totalRegions = 0;
+ for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
+ String rsGroupName = rsGroupInfo.getName();
+ int onlineServers = 0;
+ int deadServers = 0;
+ int tables = 0;
+ long requestsPerSecond = 0;
+ int numRegionsOnline = 0;
+ Set<Address> servers = rsGroupInfo.getServers();
+ for (Address server : servers) {
+ ServerMetrics sl = collectServers.get(server);
+ if (sl != null) {
+ requestsPerSecond += sl.getRequestCountPerSecond();
+ numRegionsOnline += sl.getRegionMetrics().size();
+ //rsgroup total
+ totalRegions += sl.getRegionMetrics().size();
+ totalRequests += sl.getRequestCountPerSecond();
+ totalOnlineServers++;
+ onlineServers++;
+ } else {
+ totalDeadServers++;
+ deadServers++;
+ }
+ }
+ tables = rsGroupInfo.getTables().size();
+ totalTables += tables;
+ double avgLoad = onlineServers == 0 ? 0 :
+ (double)numRegionsOnline / (double)onlineServers;
+%>
+<tr>
+ <td><a href="rsgroup.jsp?name=<%= rsGroupName %>"><%= rsGroupName %></a></td>
+ <td><%= onlineServers %></td>
+ <td><%= deadServers %></td>
+ <td><%= tables %></td>
+ <td><%= requestsPerSecond %></td>
+ <td><%= numRegionsOnline %></td>
+ <td><%= StringUtils.limitDecimalTo2(avgLoad) %></td>
+</tr>
+<%
+ }
+%>
+ <tr>
+ <td>Total:<%= rsGroupInfos.length %></td>
+ <td><%= totalOnlineServers %></td>
+ <td><%= totalDeadServers %></td>
+ <td><%= totalTables %></td>
+ <td><%= totalRequests %></td>
+ <td><%= totalRegions %></td>
+ <td><%= StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListCompactStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListCompactStats.jsp
new file mode 100644
index 00000000000..62ffe9e46ac
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListCompactStats.jsp
@@ -0,0 +1,73 @@
+<%--
+/**
+* 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.util.Map"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ RSGroupInfo [] rsGroupInfos = (RSGroupInfo[]) request.getAttribute(MasterStatusConstants.RS_GROUP_INFOS);
+ Map<Address, ServerMetrics> collectServers = (Map<Address, ServerMetrics>) request.getAttribute(MasterStatusConstants.COLLECT_SERVERS);
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>RSGroup Name</th>
+ <th>Num. Compacting Cells</th>
+ <th>Num. Compacted Cells</th>
+ <th>Remaining Cells</th>
+ <th>Compaction Progress</th>
+ </tr>
+ <%
+ for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
+ String rsGroupName = rsGroupInfo.getName();
+ long totalCompactingCells = 0;
+ long totalCompactedCells = 0;
+ long remainingCells = 0;
+ for (Address server : rsGroupInfo.getServers()) {
+ ServerMetrics sl = collectServers.get(server);
+ if (sl != null) {
+ for (RegionMetrics rl : sl.getRegionMetrics().values()) {
+ totalCompactingCells += rl.getCompactingCellCount();
+ totalCompactedCells += rl.getCompactedCellCount();
+ }
+ }
+ }
+ remainingCells = totalCompactingCells - totalCompactedCells;
+ String percentDone = "";
+ if (totalCompactingCells > 0) {
+ percentDone = String.format("%.2f", 100 *
+ ((float) totalCompactedCells / totalCompactingCells)) + "%";
+ }
+%>
+<tr>
+ <td><a href="rsgroup.jsp?name=<%= rsGroupName %>"><%= rsGroupName %></a></td>
+ <td><%= totalCompactingCells %></td>
+ <td><%= totalCompactedCells %></td>
+ <td><%= remainingCells %></td>
+ <td><%= percentDone %></td>
+ </tr>
+<%
+}
+%>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListMemoryStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListMemoryStats.jsp
new file mode 100644
index 00000000000..5e332a7fca6
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListMemoryStats.jsp
@@ -0,0 +1,85 @@
+<%--
+/**
+* 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.util.Map"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.Size"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ RSGroupInfo [] rsGroupInfos = (RSGroupInfo[]) request.getAttribute(MasterStatusConstants.RS_GROUP_INFOS);
+ Map<Address, ServerMetrics> collectServers = (Map<Address, ServerMetrics>) request.getAttribute(MasterStatusConstants.COLLECT_SERVERS);
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>RSGroup Name</th>
+ <th>Used Heap</th>
+ <th>Max Heap</th>
+ <th>Memstore Size</th>
+
+ </tr>
+ <%
+ final String ZEROMB = "0 MB";
+ for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
+ String usedHeapStr = ZEROMB;
+ String maxHeapStr = ZEROMB;
+ String memstoreSizeStr = ZEROMB;
+ String rsGroupName = rsGroupInfo.getName();
+ long usedHeap = 0;
+ long maxHeap = 0;
+ long memstoreSize = 0;
+ for (Address server : rsGroupInfo.getServers()) {
+ ServerMetrics sl = collectServers.get(server);
+ if (sl != null) {
+ usedHeap += (long) sl.getUsedHeapSize().get(Size.Unit.MEGABYTE);
+ maxHeap += (long) sl.getMaxHeapSize().get(Size.Unit.MEGABYTE);
+ memstoreSize += (long) sl.getRegionMetrics().values().stream().mapToDouble(
+ rm -> rm.getMemStoreSize().get(Size.Unit.MEGABYTE)).sum();
+ }
+ }
+
+ if (usedHeap > 0) {
+ usedHeapStr = TraditionalBinaryPrefix.long2String(usedHeap
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (maxHeap > 0) {
+ maxHeapStr = TraditionalBinaryPrefix.long2String(maxHeap
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (memstoreSize > 0) {
+ memstoreSizeStr = TraditionalBinaryPrefix.long2String(memstoreSize
+ * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+%>
+<tr>
+ <td><a href="rsgroup.jsp?name=<%= rsGroupName %>"><%= rsGroupName %></a></td>
+ <td><%= usedHeapStr %></td>
+ <td><%= maxHeapStr %></td>
+ <td><%= memstoreSizeStr %></td>
+
+ </tr>
+<%
+}
+%>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListRequestStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListRequestStats.jsp
new file mode 100644
index 00000000000..f490efff7e1
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListRequestStats.jsp
@@ -0,0 +1,66 @@
+<%--
+/**
+* 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.util.Map"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ RSGroupInfo [] rsGroupInfos = (RSGroupInfo[]) request.getAttribute(MasterStatusConstants.RS_GROUP_INFOS);
+ Map<Address, ServerMetrics> collectServers = (Map<Address, ServerMetrics>) request.getAttribute(MasterStatusConstants.COLLECT_SERVERS);
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>RSGroup Name</th>
+ <th>Request Per Second</th>
+ <th>Read Request Count</th>
+ <th>Write Request Count</th>
+ </tr>
+ <%
+ for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
+ String rsGroupName = rsGroupInfo.getName();
+ long requestsPerSecond = 0;
+ long readRequests = 0;
+ long writeRequests = 0;
+ for (Address server : rsGroupInfo.getServers()) {
+ ServerMetrics sl = collectServers.get(server);
+ if (sl != null) {
+ for (RegionMetrics rm : sl.getRegionMetrics().values()) {
+ readRequests += rm.getReadRequestCount();
+ writeRequests += rm.getWriteRequestCount();
+ }
+ requestsPerSecond += sl.getRequestCountPerSecond();
+ }
+ }
+ %>
+ <tr>
+ <td><a href="rsgroup.jsp?name=<%= rsGroupName %>"><%= rsGroupName %></a></td>
+ <td><%= requestsPerSecond %></td>
+ <td><%= readRequests %></td>
+ <td><%= writeRequests %></td>
+ </tr>
+ <%
+ }
+ %>
+ </table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListStoreStats.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListStoreStats.jsp
new file mode 100644
index 00000000000..05e378e7a16
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsGroupListStoreStats.jsp
@@ -0,0 +1,102 @@
+<%--
+/**
+* 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.util.Map"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.net.Address"
+ import="org.apache.hadoop.hbase.rsgroup.RSGroupInfo"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="org.apache.hadoop.hbase.Size"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ RSGroupInfo [] rsGroupInfos = (RSGroupInfo[]) request.getAttribute(MasterStatusConstants.RS_GROUP_INFOS);
+ Map<Address, ServerMetrics> collectServers = (Map<Address, ServerMetrics>) request.getAttribute(MasterStatusConstants.COLLECT_SERVERS);
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>RSGroup Name</th>
+ <th>Num. Stores</th>
+ <th>Num. Storefiles</th>
+ <th>Storefile Size Uncompressed</th>
+ <th>Storefile Size</th>
+ <th>Index Size</th>
+ <th>Bloom Size</th>
+ </tr>
+ <%
+ final String ZEROKB = "0 KB";
+ final String ZEROMB = "0 MB";
+ for (RSGroupInfo rsGroupInfo: rsGroupInfos) {
+ String uncompressedStorefileSizeStr = ZEROMB;
+ String storefileSizeStr = ZEROMB;
+ String indexSizeStr = ZEROKB;
+ String bloomSizeStr = ZEROKB;
+ String rsGroupName = rsGroupInfo.getName();
+ int numStores = 0;
+ long numStorefiles = 0;
+ long uncompressedStorefileSize = 0;
+ long storefileSize = 0;
+ long indexSize = 0;
+ long bloomSize = 0;
+ for (Address server : rsGroupInfo.getServers()) {
+ ServerMetrics sl = collectServers.get(server);
+ if (sl != null) {
+ for (RegionMetrics rm : sl.getRegionMetrics().values()) {
+ numStores += rm.getStoreCount();
+ numStorefiles += rm.getStoreFileCount();
+ uncompressedStorefileSize += rm.getUncompressedStoreFileSize().get(Size.Unit.MEGABYTE);
+ storefileSize += rm.getStoreFileSize().get(Size.Unit.MEGABYTE);
+ indexSize += rm.getStoreFileUncompressedDataIndexSize().get(Size.Unit.KILOBYTE);
+ bloomSize += rm.getBloomFilterSize().get(Size.Unit.KILOBYTE);
+ }
+ }
+ }
+ if (uncompressedStorefileSize > 0) {
+ uncompressedStorefileSizeStr = TraditionalBinaryPrefix.
+ long2String(uncompressedStorefileSize * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (storefileSize > 0) {
+ storefileSizeStr = TraditionalBinaryPrefix.
+ long2String(storefileSize * TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ if (indexSize > 0) {
+ indexSizeStr = TraditionalBinaryPrefix.
+ long2String(indexSize * TraditionalBinaryPrefix.KILO.value, "B", 1);
+ }
+ if (bloomSize > 0) {
+ bloomSizeStr = TraditionalBinaryPrefix.
+ long2String(bloomSize * TraditionalBinaryPrefix.KILO.value, "B", 1);
+ }
+%>
+<tr>
+ <td><a href="rsgroup.jsp?name=<%= rsGroupName %>"><%= rsGroupName %></a></td>
+ <td><%= numStores %></td>
+ <td><%= numStorefiles %></td>
+ <td><%= uncompressedStorefileSizeStr %></td>
+ <td><%= storefileSizeStr %></td>
+ <td><%= indexSizeStr %></td>
+ <td><%= bloomSizeStr %></td>
+ </tr>
+<%
+}
+%>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp b/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp
new file mode 100644
index 00000000000..725a116790c
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp
@@ -0,0 +1,173 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.util.JvmVersion"
+ import="org.apache.hadoop.hbase.util.CommonFSUtils"
+ import="org.apache.hadoop.util.StringUtils"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%!
+ public static String formatZKString(HMaster master) {
+ StringBuilder quorums = new StringBuilder();
+ String zkQuorum = master.getZooKeeper().getQuorum();
+
+ if (null == zkQuorum) {
+ return quorums.toString();
+ }
+
+ String[] zks = zkQuorum.split(",");
+
+ if (zks.length == 0) {
+ return quorums.toString();
+ }
+
+ for(int i = 0; i < zks.length; ++i) {
+ quorums.append(zks[i].trim());
+
+ if (i != (zks.length - 1)) {
+ quorums.append("<br/>");
+ }
+ }
+
+ return quorums.toString();
+ }
+%>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ Map<String, Integer> frags = (Map<String, Integer>) request.getAttribute(MasterStatusConstants.FRAGS);
+%>
+
+<h2><a name="attributes">Software Attributes</a></h2>
+<table id="attributes_table" class="table table-striped">
+ <tr>
+ <th>Attribute Name</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>JVM Version</td>
+ <td><%= JvmVersion.getVersion() %></td>
+ <td>JVM vendor and version</td>
+ </tr>
+ <tr>
+ <td>HBase Version</td>
+ <td><%= org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, revision=<%= org.apache.hadoop.hbase.util.VersionInfo.getRevision() %></td><td>HBase version and revision</td>
+ </tr>
+ <tr>
+ <td>HBase Compiled</td>
+ <td><%= org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <%= org.apache.hadoop.hbase.util.VersionInfo.getUser() %></td>
+ <td>When HBase version was compiled and by whom</td>
+ </tr>
+ <tr>
+ <td>HBase Source Checksum</td>
+ <td><%= org.apache.hadoop.hbase.util.VersionInfo.getSrcChecksum() %></td>
+ <td>HBase source SHA512 checksum</td>
+ </tr>
+ <tr>
+ <td>Hadoop Version</td>
+ <td><%= org.apache.hadoop.util.VersionInfo.getVersion() %>, revision=<%= org.apache.hadoop.util.VersionInfo.getRevision() %></td>
+ <td>Hadoop version and revision</td>
+ </tr>
+ <tr>
+ <td>Hadoop Compiled</td>
+ <td><%= org.apache.hadoop.util.VersionInfo.getDate() %>, <%= org.apache.hadoop.util.VersionInfo.getUser() %></td>
+ <td>When Hadoop version was compiled and by whom</td>
+ </tr>
+ <tr>
+ <td>Hadoop Source Checksum</td>
+ <td><%= org.apache.hadoop.util.VersionInfo.getSrcChecksum() %></td>
+ <td>Hadoop source MD5 checksum</td>
+ </tr>
+ <tr>
+ <td>ZooKeeper Client Version</td>
+ <td><%= org.apache.zookeeper.Version.getVersion() %>, revision=<%= org.apache.zookeeper.Version.getRevisionHash() %></td>
+ <td>ZooKeeper client version and revision hash</td>
+ </tr>
+ <tr>
+ <td>ZooKeeper Client Compiled</td>
+ <td><%= org.apache.zookeeper.Version.getBuildDate() %></td>
+ <td>When ZooKeeper client version was compiled</td>
+ </tr>
+ <tr>
+ <td>ZooKeeper Quorum</td>
+ <td> <%= formatZKString(master) %> </td>
+ <td>Addresses of all registered ZK servers. For more, see <a href="/zk.jsp">zk dump</a>.</td>
+ </tr>
+ <tr>
+ <td>ZooKeeper Base Path</td>
+ <td> <%= master.getZooKeeper().getZNodePaths().baseZNode %></td>
+ <td>Root node of this cluster in ZK.</td>
+ </tr>
+ <tr>
+ <td>Cluster Key</td>
+ <td> <%= formatZKString(master) %>:<%= master.getZooKeeper().getZNodePaths().baseZNode %></td>
+ <td>Key to add this cluster as a peer for replication. Use 'help "add_peer"' in the shell for details.</td>
+ </tr>
+ <tr>
+ <td>HBase Root Directory</td>
+ <td><%= CommonFSUtils.getRootDir(master.getConfiguration()).toString() %></td>
+ <td>Location of HBase home directory</td>
+ </tr>
+ <tr>
+ <td>HMaster Start Time</td>
+ <td><%= new Date(master.getMasterStartTime()) %></td>
+ <td>Date stamp of when this HMaster was started</td>
+ </tr>
+ <% if (master.isActiveMaster()) { %>
+ <tr>
+ <td>HMaster Active Time</td>
+ <td><%= new Date(master.getMasterActiveTime()) %></td>
+ <td>Date stamp of when this HMaster became active</td>
+ </tr>
+ <tr>
+ <td>HBase Cluster ID</td>
+ <td><%= master.getClusterId() != null ? master.getClusterId() : "Not set" %></td>
+ <td>Unique identifier generated for each HBase cluster</td>
+ </tr>
+ <tr>
+ <td>Load average</td>
+ <td><%= master.getServerManager() == null ? "0.00" :
+ StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %></td>
+ <td>Average number of regions per regionserver. Naive computation.</td>
+ </tr>
+ <% if (frags != null) { %>
+ <tr>
+ <td>Fragmentation</td>
+ <td><%= frags.get("-TOTAL-") != null ? frags.get("-TOTAL-") + "%" : "n/a" %></td>
+ <td>Overall fragmentation of all tables, including hbase:meta</td>
+ </tr>
+ <% } %>
+ <tr>
+ <td>Coprocessors</td>
+ <td><%= master.getMasterCoprocessorHost() == null ? "[]" :
+ java.util.Arrays.toString(master.getMasterCoprocessors()) %></td>
+ <td>Coprocessors currently loaded by the master</td>
+ </tr>
+ <tr>
+ <td>LoadBalancer</td>
+ <td><%= master.getLoadBalancerClassName() %></td>
+ <td>LoadBalancer to be used in the Master</td>
+ </tr>
+ <% } %>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp b/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp
index b2f3938f56f..52775bd08a6 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/tablesDetailed.jsp
@@ -21,10 +21,9 @@
import="static org.apache.commons.lang3.StringEscapeUtils.escapeXml"
import="java.util.ArrayList"
import="java.util.List"
-%>
-<%@ page import="org.apache.hadoop.hbase.client.TableDescriptor" %>
-<%@ page import="org.apache.hadoop.hbase.master.HMaster" %>
-<%@ page import="org.apache.hadoop.hbase.tmpl.master.MasterStatusTmplImpl" %>
+ import="org.apache.hadoop.hbase.client.TableDescriptor"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil" %>
<%
HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
pageContext.setAttribute("pageTitle", "HBase Master: " + master.getServerName());
@@ -41,7 +40,7 @@
</div>
<% List<TableDescriptor> tables = new ArrayList<TableDescriptor>();
- String errorMessage = MasterStatusTmplImpl.getUserTables(master, tables);
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
if (tables.size() == 0 && errorMessage != null) { %>
<p> <%= errorMessage %> </p>
<% }
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/taskMonitor.jsp b/hbase-server/src/main/resources/hbase-webapps/master/taskMonitor.jsp
new file mode 100644
index 00000000000..3a84615e3c9
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/taskMonitor.jsp
@@ -0,0 +1,90 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%
+ String filter = (String) request.getAttribute(MasterStatusConstants.FILTER);
+ if (filter == null) {
+ filter = "general";
+ }
+ String format = (String) request.getAttribute(MasterStatusConstants.FORMAT);
+ if (format == null) {
+ format = "html";
+ }
+ String parent = (String) request.getAttribute(MasterStatusConstants.PARENT);
+ if (parent == null) {
+ parent = "";
+ }
+%>
+
+<% if (format.equals("json")) { %>
+ <% request.setAttribute(MasterStatusConstants.FILTER, filter); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+<% } else { %>
+ <h2><a name="tasks">Tasks</a></h2>
+
+ <div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_alltasks" data-bs-toggle="tab" role="tab">Show All Monitored Tasks</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link active" href="#tab_generaltasks" data-bs-toggle="tab" role="tab">Show non-RPC Tasks</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_handlertasks" data-bs-toggle="tab" role="tab">Show All RPC Handler Tasks</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_rpctasks" data-bs-toggle="tab" role="tab">Show Active RPC Calls</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#tab_operationtasks" data-bs-toggle="tab" role="tab">Show Client Operations</a>
+ </li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane" id="tab_alltasks" role="tabpanel">
+ <a href="<%= parent %>?format=json&filter=all">View as JSON</a>
+ <% request.setAttribute(MasterStatusConstants.FILTER, "all"); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+ </div>
+ <div class="tab-pane active" id="tab_generaltasks" role="tabpanel">
+ <a href="<%= parent %>?format=json&filter=general">View as JSON</a>
+ <% request.setAttribute(MasterStatusConstants.FILTER, "general"); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_handlertasks" role="tabpanel">
+ <a href="<%= parent %>?format=json&filter=handler">View as JSON</a>
+ <% request.setAttribute(MasterStatusConstants.FILTER, "handler"); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_rpctasks" role="tabpanel">
+ <a href="<%= parent %>?format=json&filter=rpc">View as JSON</a>
+ <% request.setAttribute(MasterStatusConstants.FILTER, "rpc"); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_operationtasks" role="tabpanel">
+ <a href="<%= parent %>?format=json&filter=operation">View as JSON</a>
+ <% request.setAttribute(MasterStatusConstants.FILTER, "operation"); %>
+ <jsp:include page="taskMonitorRenderTasks.jsp"/>
+ </div>
+ </div>
+ </div>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/taskMonitorRenderTasks.jsp b/hbase-server/src/main/resources/hbase-webapps/master/taskMonitorRenderTasks.jsp
new file mode 100644
index 00000000000..ad606d8e332
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/taskMonitorRenderTasks.jsp
@@ -0,0 +1,87 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.monitoring.*"
+ import="org.apache.hadoop.util.StringUtils"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+
+<%!
+ public static String stateCss(MonitoredTask.State state) {
+ if (state == MonitoredTask.State.COMPLETE) {
+ return "alert alert-success";
+ } else if (state == MonitoredTask.State.ABORTED) {
+ return "alert alert-danger";
+ } else {
+ return "";
+ }
+ }
+%>
+
+<%
+ TaskMonitor taskMonitor = TaskMonitor.get();
+ String filter = (String) request.getAttribute(MasterStatusConstants.FILTER);
+ String format = (String) request.getAttribute(MasterStatusConstants.FORMAT);
+ if (format == null) {
+ format = "html";
+ }
+
+ List<? extends MonitoredTask> tasks = taskMonitor.getTasks(filter);
+ long now = System.currentTimeMillis();
+ Collections.sort(tasks, (t1, t2) -> Long.compare(t1.getStateTime(), t2.getStateTime()));
+ boolean first = true;
+ %>
+
+<% if (format.equals("json")) { %>
+[<% for (MonitoredTask task : tasks) { %><% if (first) { %><% first = false;%><% } else { %>,<% } %><%= task.toJSON() %><% } %>]
+<% } else { %>
+ <% if (tasks.isEmpty()) { %>
+ <p>No tasks currently running on this node.</p>
+ <% } else { %>
+ <table class="table table-striped">
+ <tr>
+ <th>Start Time</th>
+ <th>Description</th>
+ <th>State</th>
+ <th>Status</th>
+ <th>Completion Time</th>
+ </tr>
+ <% for (MonitoredTask task : tasks) { %>
+ <tr class="<%= stateCss(task.getState()) %>">
+ <td><%= new Date(task.getStartTime()) %></td>
+ <td><%= task.getDescription() %></td>
+ <td><%= task.getState() %>
+ (since <%= StringUtils.formatTimeDiff(now, task.getStateTime()) %> ago)
+ </td>
+ <td><%= task.getStatus() %>
+ (since <%= StringUtils.formatTimeDiff(now, task.getStatusTime()) %>
+ ago)</td>
+ <td>
+ <% if (task.getCompletionTimestamp() < 0) { %>
+ <%= task.getState() %>
+ <% } else { %>
+ <%= new Date(task.getCompletionTimestamp()) %> (since <%= StringUtils.formatTimeDiff(now, task.getCompletionTimestamp()) %> ago)
+ <% } %>
+ </td>
+ </tr>
+ <% } %>
+ </table>
+ <% } %>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/userTables.jsp b/hbase-server/src/main/resources/hbase-webapps/master/userTables.jsp
new file mode 100644
index 00000000000..cc1b1da2afc
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/userTables.jsp
@@ -0,0 +1,117 @@
+<%--
+/**
+ * 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.util.*"
+ import="java.net.URLEncoder"
+ import="org.apache.hadoop.hbase.TableName"
+ import="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.master.RegionState"
+ import="org.apache.hadoop.hbase.client.*"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusUtil"
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants" %>
+<%@ page import="org.apache.hadoop.hbase.HTableDescriptor" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ Map<String, Integer> frags = (Map<String, Integer>) request.getAttribute(MasterStatusConstants.FRAGS);
+
+ List<TableDescriptor> tables = new ArrayList<>();
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+%>
+
+<% if (tables.size() == 0 && errorMessage != null) { %>
+<p> <%= errorMessage %> </p>
+<% } %>
+
+<% if (tables != null && tables.size() > 0) { %>
+<table id="userTables" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th style="vertical-align: middle;" rowspan="2">Namespace</th>
+ <th style="vertical-align: middle;" rowspan="2">Name</th>
+ <% if (frags != null) { %>
+ <th title="Fragmentation - Will be 0% after a major compaction and fluctuate during normal usage.">Frag.</th>
+ <% } %>
+ <th style="vertical-align:middle;" rowspan="2">State</th>
+ <th style="text-align: center" colspan="7">Regions</th>
+ <th style="vertical-align:middle;" rowspan="2">Description</th>
+ </tr>
+ <tr>
+ <th>OPEN</th>
+ <th>OPENING</th>
+ <th>CLOSED</th>
+ <th>CLOSING</th>
+ <th>OFFLINE</th>
+ <th>SPLIT</th>
+ <th>Other</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% for (TableDescriptor desc : tables) { %>
+ <%
+ HTableDescriptor htDesc = new HTableDescriptor(desc);
+ TableName tableName = htDesc.getTableName();
+ TableState tableState = master.getTableStateManager().getTableState(tableName);
+ Map<RegionState.State, List<RegionInfo>> tableRegions =
+ master.getAssignmentManager().getRegionStates()
+ .getRegionByStateOfTable(tableName);
+ int openRegionsCount = tableRegions.get(RegionState.State.OPEN).size();
+ int openingRegionsCount = tableRegions.get(RegionState.State.OPENING).size();
+ int closedRegionsCount = tableRegions.get(RegionState.State.CLOSED).size();
+ int closingRegionsCount = tableRegions.get(RegionState.State.CLOSING).size();
+ int offlineRegionsCount = tableRegions.get(RegionState.State.OFFLINE).size();
+ int splitRegionsCount = tableRegions.get(RegionState.State.SPLIT).size();
+ int otherRegionsCount = 0;
+ for (List<RegionInfo> list: tableRegions.values()) {
+ otherRegionsCount += list.size();
+ }
+ // now subtract known states
+ otherRegionsCount = otherRegionsCount - openRegionsCount
+ - offlineRegionsCount - splitRegionsCount
+ - openingRegionsCount - closedRegionsCount
+ - closingRegionsCount;
+ String encodedTableName = URLEncoder.encode(tableName.getNameAsString());
+ %>
+ <tr>
+ <td><%= tableName.getNamespaceAsString() %></td>
+ <% if (tableState.isDisabledOrDisabling()) { %> <td><a style="color:red;" href=table.jsp?name=<%= encodedTableName %>><%= URLEncoder.encode(tableName.getQualifierAsString()) %></a></td> <% } else { %><td><a href=table.jsp?name=<%= encodedTableName %>><%= URLEncoder.encode(tableName.getQualifierAsString()) %></a></td> <% } %>
+ <% if (frags != null) { %>
+ <td align="center"><%= frags.get(tableName.getNameAsString()) != null ? frags.get(tableName.getNameAsString()).intValue() + "%" : "n/a" %></td>
+ <% } %>
+ <% if (tableState.isDisabledOrDisabling()) { %> <td style="color:red;"><%= tableState.getState().name() %></td> <% } else { %><td><%= tableState.getState() %></td> <% } %>
+ <td><%= openRegionsCount %></td>
+ <% if (openingRegionsCount > 0) { %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<%= encodedTableName %>&scan_region_state=OPENING"><%= openingRegionsCount %></a></td> <% } else { %><td><%= openingRegionsCount %></td> <% } %>
+ <% if (closedRegionsCount > 0) { %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<%= encodedTableName %>&scan_region_state=CLOSED"><%= closedRegionsCount %></a></td> <% } else { %><td><%= closedRegionsCount %></td> <% } %>
+ <% if (closingRegionsCount > 0) { %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<%= encodedTableName %>&scan_region_state=CLOSING"><%= closingRegionsCount %></a></td> <% } else { %><td><%= closingRegionsCount %></td> <% } %>
+ <% if (offlineRegionsCount > 0) { %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<%= encodedTableName %>&scan_region_state=OFFLINE"><%= offlineRegionsCount %></a></td> <% } else { %><td><%= offlineRegionsCount %></td> <% } %>
+ <% if (splitRegionsCount > 0) { %> <td><a href="/table.jsp?name=hbase%3Ameta&scan_table=<%= encodedTableName %>&scan_region_state=SPLIT"><%= splitRegionsCount %></a></td> <% } else { %><td><%= splitRegionsCount %></td> <% } %>
+ <td><%= otherRegionsCount %></td>
+ <td><%= htDesc.toStringCustomizedValues() %></td>
+ </tr>
+<% } %>
+<p><%= tables.size() %> table(s) in set. [<a href=tablesDetailed.jsp>Details</a>]. Click count below to
+ see list of regions currently in 'state' designated by the column title. For 'Other' Region state,
+ browse to <a href="/table.jsp?name=hbase%3Ameta">hbase:meta</a> and adjust filter on 'Meta Entries' to
+ query on states other than those listed here. Queries may take a while if the <i>hbase:meta</i> table
+ is large.</p>
+</tbody>
+</table>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/warnings.jsp b/hbase-server/src/main/resources/hbase-webapps/master/warnings.jsp
new file mode 100644
index 00000000000..6457e6a2712
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/master/warnings.jsp
@@ -0,0 +1,86 @@
+<%--
+/**
+ * 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="org.apache.hadoop.hbase.master.HMaster"
+ import="org.apache.hadoop.hbase.master.ServerManager"
+ import="org.apache.hadoop.hbase.util.JvmVersion"
+ import="org.apache.hadoop.hbase.client.MasterSwitchType" %>
+
+<%
+ HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
+
+ boolean catalogJanitorEnabled = master.isCatalogJanitorEnabled();
+ ServerManager serverManager = master.getServerManager();
+%>
+
+<!-- Various warnings that cluster admins should be aware of -->
+<% if(JvmVersion.isBadJvmVersion()) { %>
+<div class="alert alert-danger" role="alert">
+ Your current JVM version <%= System.getProperty("java.version") %> is known to be
+ unstable with HBase. Please see the
+ <a href="http://hbase.apache.org/book.html#trouble.log.gc">HBase Reference Guide</a>
+ for details.
+</div>
+<% } %>
+<% if(master.isInitialized() && !catalogJanitorEnabled) { %>
+<div class="alert alert-danger" role="alert">
+ Please note that your cluster is running with the CatalogJanitor disabled. It can be
+ re-enabled from the hbase shell by running the command 'catalogjanitor_switch true'
+</div>
+<% } %>
+<% if(master.isInMaintenanceMode()) { %>
+<div class="alert alert-warning" role="alert">
+ Your Master is in maintenance mode. This is because hbase.master.maintenance_mode is
+ set to true. Under the maintenance mode, no quota or no Master coprocessor is loaded.
+</div>
+<% } %>
+<% if(!master.isBalancerOn()) { %>
+<div class="alert alert-warning" role="alert">
+ The Load Balancer is not enabled which will eventually cause performance degradation
+ in HBase as Regions will not be distributed across all RegionServers. The balancer
+ is only expected to be disabled during rolling upgrade scenarios.
+</div>
+<% } %>
+<% if(!master.isSplitOrMergeEnabled(MasterSwitchType.SPLIT)) { %>
+<div class="alert alert-warning" role="alert">
+ Region splits are disabled. This may be the result of HBCK aborting while
+ running in repair mode. Manually enable splits from the HBase shell,
+ or re-run HBCK in repair mode.
+</div>
+<% } %>
+<% if(!master.isSplitOrMergeEnabled(MasterSwitchType.MERGE)) { %>
+<div class="alert alert-warning" role="alert">
+ Region merges are disabled. This may be the result of HBCK aborting while
+ running in repair mode. Manually enable merges from the HBase shell,
+ or re-run HBCK in repair mode.
+</div>
+<% } %>
+<% if(master.getAssignmentManager() != null) { %>
+ <jsp:include page="assignmentManagerStatus.jsp"/>
+<% } %>
+<% if (!master.isInMaintenanceMode() && master.getMasterCoprocessorHost() != null) { %>
+ <% if (master.getMasterCoprocessorHost().findCoprocessor("RSGroupAdminEndpoint") != null &&
+ serverManager.getOnlineServersList().size() > 0) { %>
+ <section>
+ <h2><a name="rsgroup">RSGroup</a></h2>
+ <jsp:include page="rsGroupList.jsp"/>
+ </section>
+ <% } %>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/static/js/masterStatusInit.js b/hbase-server/src/main/resources/hbase-webapps/static/js/masterStatusInit.js
new file mode 100644
index 00000000000..0b09b6ee06b
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/static/js/masterStatusInit.js
@@ -0,0 +1,126 @@
+/*
+ * Copyright The Apache Software Foundation
+ *
+ * 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.
+ */
+
+$(document).ready(function()
+ {
+ $.tablesorter.addParser(
+ {
+ id: 'filesize',
+ is: function(s) {
+ return s.match(new RegExp( /([\.0-9]+)\ (B|KB|MB|GB|TB)/ ));
+ },
+ format: function(s) {
+ var suf = s.match(new RegExp( /(KB|B|GB|MB|TB)$/ ))[1];
+ var num = parseFloat(s.match( new RegExp( /([\.0-9]+)\ (B|KB|MB|GB|TB)/ ))[0]);
+ switch(suf) {
+ case 'B':
+ return num;
+ case 'KB':
+ return num * 1024;
+ case 'MB':
+ return num * 1024 * 1024;
+ case 'GB':
+ return num * 1024 * 1024 * 1024;
+ case 'TB':
+ return num * 1024 * 1024 * 1024 * 1024;
+ }
+ },
+ type: 'numeric'
+ });
+ $.tablesorter.addParser(
+ {
+ id: "separator",
+ is: function (s) {
+ return /^[0-9]?[0-9,]*$/.test(s);
+ }, format: function (s) {
+ return $.tablesorter.formatFloat( s.replace(/,/g,'') );
+ }, type: "numeric"
+ });
+ $.tablesorter.addParser(
+ {
+ id: "dateTime",
+ is: function (s) {
+ return /^([a-zA-Z]{3}\s){2}\d{2}\s\d{2}:\d{2}:\d{2}\s[a-zA-Z]{3}\s\d{4}$/.test(s);
+ }, format: function (s) {
+ var split = s.split(" ");
+ var time = Date.parse(split[1] + " " + split[2] + " " + split[3] + " " + split[5]);
+ return $.tablesorter.formatFloat(time);
+ }, type: "numeric"
+ });
+ $("#baseStatsTable").tablesorter({
+ headers: {
+ '.cls_dateTime': {sorter: 'dateTime'},
+ '.cls_separator': {sorter: 'separator'}
+ }
+ });
+ $("#memoryStatsTable").tablesorter({
+ headers: {
+ '.cls_filesize': {sorter: 'filesize'}
+ }
+ });
+ $("#requestStatsTable").tablesorter({
+ headers: {
+ '.cls_separator': {sorter: 'separator'}
+ }
+ });
+ $("#storeStatsTable").tablesorter({
+ headers: {
+ '.cls_separator': {sorter: 'separator'},
+ '.cls_filesize': {sorter: 'filesize'}
+ }
+ });
+ $("#compactionStatsTable").tablesorter({
+ headers: {
+ '.cls_separator': {sorter: 'separator'}
+ }
+ });
+
+ $("#userTables").tablesorter();
+
+ function showRitPages() {
+ if (!$("#rit_page_num")) {
+ return;
+ }
+ var ritTotalNum = parseInt($("#rit_page_num").val());
+ if (!ritTotalNum || ritTotalNum < 1) {
+ return;
+ }
+ var ritPerPage = parseInt($("#rit_per_page").val());
+
+ $("#rit_pagination").sPage({
+ page:1,
+ total:ritTotalNum,
+ pageSize:ritPerPage,
+ noData: false,
+ showPN:true,
+ prevPage:"prev",
+ nextPage:"next",
+ fastForward: 5,
+ backFun:function(page){
+ $("div[id^='tab_rits']").removeClass('active');
+ $("#tab_rits"+page).addClass('active');
+ }
+ });
+
+ }
+ showRitPages();
+
+ }
+);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestInfoServers.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestInfoServers.java
index 94c2bebda28..75bfab8a2bd 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestInfoServers.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestInfoServers.java
@@ -93,7 +93,8 @@ public class TestInfoServers {
// give the cluster time to start up
UTIL.getConnection().getTable(TableName.META_TABLE_NAME).close();
int port = UTIL.getHBaseCluster().getMaster().getInfoServer().getPort();
- assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "master-status");
+ assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "master.jsp");
+ assertContainsContent(new URL("http://localhost:" + port + "/master-status"), "master.jsp");
port = UTIL.getHBaseCluster().getRegionServerThreads().get(0).getRegionServer().getInfoServer()
.getPort();
assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "rs-status");
@@ -107,7 +108,7 @@ public class TestInfoServers {
@Test
public void testInfoServersStatusPages() throws Exception {
int port = UTIL.getHBaseCluster().getMaster().getInfoServer().getPort();
- assertContainsContent(new URL("http://localhost:" + port + "/master-status"), "meta");
+ assertContainsContent(new URL("http://localhost:" + port + "/master.jsp"), "meta");
port = UTIL.getHBaseCluster().getRegionServerThreads().get(0).getRegionServer().getInfoServer()
.getPort();
assertContainsContent(new URL("http://localhost:" + port + "/rs-status"), "meta");
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusPage.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusPage.java
new file mode 100644
index 00000000000..a23182f8cb7
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusPage.java
@@ -0,0 +1,186 @@
+/*
+ * 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.master.http;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.LocalHBaseCluster;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.master.HMaster;
+import org.apache.hadoop.hbase.master.ServerManager;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.util.CommonFSUtils;
+import org.apache.hadoop.hbase.util.VersionInfo;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+@Category({ MasterTests.class, MediumTests.class })
+public class TestMasterStatusPage {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestMasterStatusPage.class);
+
+ private final static HBaseTestingUtility UTIL = new HBaseTestingUtility();
+ public static final String TEST_TABLE_NAME_1 = "TEST_TABLE_1";
+ public static final String TEST_TABLE_NAME_2 = "TEST_TABLE_2";
+
+ private static LocalHBaseCluster CLUSTER;
+
+ @Rule
+ public TestName name = new TestName();
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ Configuration conf = UTIL.getConfiguration();
+ UTIL.startMiniZKCluster();
+
+ UTIL.startMiniDFSCluster(1);
+ Path rootdir = UTIL.getDataTestDirOnTestFS("TestMasterStatusPage");
+ CommonFSUtils.setRootDir(conf, rootdir);
+
+ // The info servers do not run in tests by default.
+ // Set them to ephemeral ports so they will start
+ // setup configuration
+ conf.setInt(HConstants.MASTER_INFO_PORT, 0);
+ conf.setInt(HConstants.REGIONSERVER_INFO_PORT, 0);
+
+ CLUSTER = new LocalHBaseCluster(conf, 1);
+ CLUSTER.startup();
+ CLUSTER.getActiveMaster().waitForMetaOnline();
+ }
+
+ /**
+ * Helper method to shut down the cluster (if running)
+ */
+ @AfterClass
+ public static void shutDownMiniCluster() throws Exception {
+ if (CLUSTER != null) {
+ CLUSTER.shutdown();
+ CLUSTER.join();
+ }
+ UTIL.shutdownMiniCluster();
+ }
+
+ @Test
+ public void testMasterStatusPage() throws Exception {
+ HMaster master = CLUSTER.getActiveMaster();
+
+ createTestTables(master);
+
+ String page = getMasterStatusPageContent();
+
+ String hostname = master.getServerName().getHostname();
+ assertTrue(page.contains("<h1>Master <small>" + hostname + "</small></h1>"));
+ assertTrue(page.contains("<h2><a name=\"regionservers\">Region Servers</a></h2>"));
+ assertRegionServerLinks(master, page);
+
+ assertTrue(page.contains("<h2>Backup Masters</h2>"));
+ assertTrue(page.contains("<h2><a name=\"tables\">Tables</a></h2>"));
+ assertTableLinks(master, page);
+
+ assertTrue(page.contains("<h2><a name=\"region_visualizer\"></a>Region Visualizer</h2>"));
+ assertTrue(page.contains("<h2><a name=\"peers\">Peers</a></h2>"));
+ assertTrue(page.contains("<h2><a name=\"tasks\">Tasks</a></h2>"));
+ assertTrue(page.contains("<h2><a name=\"attributes\">Software Attributes</a></h2>"));
+
+ assertTrue(page.contains(VersionInfo.getVersion()));
+ }
+
+ private String getMasterStatusPageContent() throws IOException {
+ URL url = new URL(getInfoServerHostAndPort() + "/master-status");
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.connect();
+
+ assertEquals(200, conn.getResponseCode());
+ assertEquals("text/html;charset=utf-8", conn.getContentType());
+
+ return getResponseBody(conn);
+ }
+
+ private static void createTestTables(HMaster master) throws IOException {
+ ColumnFamilyDescriptor cf = ColumnFamilyDescriptorBuilder.of("CF");
+ TableDescriptor tableDescriptor1 = TableDescriptorBuilder
+ .newBuilder(TableName.valueOf(TEST_TABLE_NAME_1)).setColumnFamily(cf).build();
+ master.createTable(tableDescriptor1, null, 0, 0);
+ TableDescriptor tableDescriptor2 = TableDescriptorBuilder
+ .newBuilder(TableName.valueOf(TEST_TABLE_NAME_2)).setColumnFamily(cf).build();
+ master.createTable(tableDescriptor2, null, 0, 0);
+ master.flushMasterStore();
+ }
+
+ private String getInfoServerHostAndPort() {
+ return "http://localhost:" + CLUSTER.getActiveMaster().getInfoServer().getPort();
+ }
+
+ private static String getResponseBody(HttpURLConnection conn) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String output;
+ while ((output = br.readLine()) != null) {
+ sb.append(output);
+ }
+ return sb.toString();
+ }
+
+ private static void assertRegionServerLinks(HMaster master, String responseBody) {
+ ServerManager serverManager = master.getServerManager();
+ List<ServerName> servers = serverManager.getOnlineServersList();
+ assertEquals(1, servers.size());
+ for (ServerName serverName : servers) {
+ String expectedRsLink = MasterStatusUtil.serverNameLink(master, serverName);
+ assertTrue(responseBody.contains(expectedRsLink));
+ }
+ }
+
+ private static void assertTableLinks(HMaster master, String responseBody) {
+ List<TableDescriptor> tables = new ArrayList<>();
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+ assertNull(errorMessage);
+ assertEquals(2, tables.size());
+ for (TableDescriptor table : tables) {
+ String tableName = table.getTableName().getNameAsString();
+ String expectedTableLink = "<a href=table.jsp?name=" + tableName + ">" + tableName + "</a>";
+ assertTrue(responseBody.contains(expectedTableLink));
+ }
+ }
+}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusServlet.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusServlet.java
deleted file mode 100644
index a2c079661ea..00000000000
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusServlet.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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.master.http;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.hadoop.hbase.HRegionInfo;
-import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.ServerName;
-import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.client.Admin;
-import org.apache.hadoop.hbase.master.DeadServer;
-import org.apache.hadoop.hbase.master.HMaster;
-import org.apache.hadoop.hbase.master.RegionState;
-import org.apache.hadoop.hbase.master.ServerManager;
-import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
-import org.apache.hadoop.hbase.master.assignment.RegionStates;
-import org.apache.hadoop.hbase.regionserver.MetricsRegionServer;
-import org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapperStub;
-import org.apache.hadoop.hbase.testclassification.MasterTests;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.tmpl.master.MasterStatusTmpl;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
-import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
-import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.mockito.Mockito;
-
-import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
-
-/**
- * Tests for the master status page and its template.
- */
-@Category({ MasterTests.class, MediumTests.class })
-public class TestMasterStatusServlet {
-
- @ClassRule
- public static final HBaseClassTestRule CLASS_RULE =
- HBaseClassTestRule.forClass(TestMasterStatusServlet.class);
-
- private HMaster master;
- private Configuration conf;
- private Admin admin;
-
- static final ServerName FAKE_HOST = ServerName.valueOf("fakehost", 12345, 1234567890);
- static final HTableDescriptor FAKE_TABLE = new HTableDescriptor(TableName.valueOf("mytable"));
- static final HRegionInfo FAKE_HRI =
- new HRegionInfo(FAKE_TABLE.getTableName(), Bytes.toBytes("a"), Bytes.toBytes("b"));
-
- @Before
- public void setupBasicMocks() {
- conf = HBaseConfiguration.create();
-
- master = Mockito.mock(HMaster.class);
- Mockito.doReturn(FAKE_HOST).when(master).getServerName();
- Mockito.doReturn(conf).when(master).getConfiguration();
-
- // Fake DeadServer
- DeadServer deadServer = Mockito.mock(DeadServer.class);
- // Fake serverManager
- ServerManager serverManager = Mockito.mock(ServerManager.class);
- Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
- Mockito.doReturn(serverManager).when(master).getServerManager();
- Mockito.doReturn(deadServer).when(serverManager).getDeadServers();
-
- // Fake AssignmentManager and RIT
- AssignmentManager am = Mockito.mock(AssignmentManager.class);
- RegionStates rs = Mockito.mock(RegionStates.class);
- List<RegionState> regionsInTransition = new ArrayList<>();
- regionsInTransition
- .add(new RegionState(FAKE_HRI, RegionState.State.CLOSING, 12345L, FAKE_HOST));
- Mockito.doReturn(rs).when(am).getRegionStates();
- Mockito.doReturn(regionsInTransition).when(rs).getRegionsInTransition();
- Mockito.doReturn(am).when(master).getAssignmentManager();
- Mockito.doReturn(serverManager).when(master).getServerManager();
-
- // Fake ZKW
- ZKWatcher zkw = Mockito.mock(ZKWatcher.class);
- Mockito.doReturn(new ZNodePaths(conf)).when(zkw).getZNodePaths();
- Mockito.doReturn("fakequorum").when(zkw).getQuorum();
- Mockito.doReturn(zkw).when(master).getZooKeeper();
-
- // Fake MasterAddressTracker
- MasterAddressTracker tracker = Mockito.mock(MasterAddressTracker.class);
- Mockito.doReturn(tracker).when(master).getMasterAddressTracker();
- Mockito.doReturn(FAKE_HOST).when(tracker).getMasterAddress();
-
- // Fake ActiveMaster
- Mockito.doReturn(Optional.of(FAKE_HOST)).when(master).getActiveMaster();
-
- MetricsRegionServer rms = Mockito.mock(MetricsRegionServer.class);
- Mockito.doReturn(new MetricsRegionServerWrapperStub()).when(rms).getRegionServerWrapper();
- Mockito.doReturn(rms).when(master).getMetrics();
-
- // Mock admin
- admin = Mockito.mock(Admin.class);
- }
-
- private void setupMockTables() throws IOException {
- HTableDescriptor tables[] =
- new HTableDescriptor[] { new HTableDescriptor(TableName.valueOf("foo")),
- new HTableDescriptor(TableName.valueOf("bar")) };
- Mockito.doReturn(tables).when(admin).listTables();
- }
-
- @Test
- public void testStatusTemplateNoTables() throws IOException {
- new MasterStatusTmpl().render(new StringWriter(), master);
- }
-
- @Test
- public void testStatusTemplateMetaAvailable() throws IOException {
- setupMockTables();
-
- new MasterStatusTmpl().setMetaLocation(ServerName.valueOf("metaserver,123,12345"))
- .render(new StringWriter(), master);
- }
-
- @Test
- public void testStatusTemplateWithServers() throws IOException {
- setupMockTables();
-
- List<ServerName> servers = Lists.newArrayList(ServerName.valueOf("rootserver,123,12345"),
- ServerName.valueOf("metaserver,123,12345"));
- Set<ServerName> deadServers =
- new HashSet<>(Lists.newArrayList(ServerName.valueOf("badserver,123,12345"),
- ServerName.valueOf("uglyserver,123,12345")));
-
- new MasterStatusTmpl().setMetaLocation(ServerName.valueOf("metaserver,123,12345"))
- .setServers(servers).setDeadServers(deadServers).render(new StringWriter(), master);
- }
-}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusUtil.java
new file mode 100644
index 00000000000..b7576f24610
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/http/TestMasterStatusUtil.java
@@ -0,0 +1,255 @@
+/*
+ * 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.master.http;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableDescriptors;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.client.RegionInfoBuilder;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.master.DeadServer;
+import org.apache.hadoop.hbase.master.HMaster;
+import org.apache.hadoop.hbase.master.RegionState;
+import org.apache.hadoop.hbase.master.ServerManager;
+import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
+import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
+import org.apache.hadoop.hbase.master.assignment.RegionStates;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.Mockito;
+
+@Category({ MasterTests.class, SmallTests.class })
+public class TestMasterStatusUtil {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestMasterStatusUtil.class);
+
+ private HMaster master;
+ private Configuration conf;
+
+ static final ServerName FAKE_HOST = ServerName.valueOf("fakehost", 12345, 1234567890);
+ static final TableDescriptor FAKE_TABLE =
+ TableDescriptorBuilder.newBuilder(TableName.valueOf("mytable")).build();
+
+ static final RegionInfo FAKE_HRI = RegionInfoBuilder.newBuilder(FAKE_TABLE.getTableName())
+ .setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("b")).build();
+
+ @Before
+ public void setupBasicMocks() {
+ conf = HBaseConfiguration.create();
+
+ master = Mockito.mock(HMaster.class);
+ Mockito.doReturn(FAKE_HOST).when(master).getServerName();
+ Mockito.doReturn(conf).when(master).getConfiguration();
+ Mockito.doReturn(true).when(master).isInitialized();
+
+ // Fake DeadServer
+ DeadServer deadServer = Mockito.mock(DeadServer.class);
+ // Fake serverManager
+ ServerManager serverManager = Mockito.mock(ServerManager.class);
+ Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
+ Mockito.doReturn(serverManager).when(master).getServerManager();
+ Mockito.doReturn(deadServer).when(serverManager).getDeadServers();
+
+ // Fake AssignmentManager and RIT
+ AssignmentManager am = Mockito.mock(AssignmentManager.class);
+ RegionStates rs = Mockito.mock(RegionStates.class);
+ List<RegionState> regionsInTransition = new ArrayList<>();
+ regionsInTransition
+ .add(new RegionState(FAKE_HRI, RegionState.State.CLOSING, 12345L, FAKE_HOST));
+ Mockito.doReturn(rs).when(am).getRegionStates();
+ Mockito.doReturn(regionsInTransition).when(rs).getRegionsInTransition();
+ Mockito.doReturn(am).when(master).getAssignmentManager();
+ Mockito.doReturn(serverManager).when(master).getServerManager();
+
+ // Fake ZKW
+ ZKWatcher zkw = Mockito.mock(ZKWatcher.class);
+ Mockito.doReturn(new ZNodePaths(conf)).when(zkw).getZNodePaths();
+ Mockito.doReturn("fakequorum").when(zkw).getQuorum();
+ Mockito.doReturn(zkw).when(master).getZooKeeper();
+
+ // Fake ActiveMaster
+ Mockito.doReturn(Optional.of(FAKE_HOST)).when(master).getActiveMaster();
+ }
+
+ @Test
+ public void testGetUserTables() throws IOException {
+ Map<String, TableDescriptor> mockTables = new HashMap<>();
+ mockTables.put("foo", TableDescriptorBuilder.newBuilder(TableName.valueOf("foo")).build());
+ mockTables.put("bar", TableDescriptorBuilder.newBuilder(TableName.valueOf("bar")).build());
+
+ TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
+ Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
+
+ Mockito.doReturn(mockTables).when(tableDescriptors).getAll();
+
+ List<TableDescriptor> tables = new ArrayList<>();
+
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+
+ assertNull(errorMessage);
+ assertEquals(2, tables.size());
+ }
+
+ @Test
+ public void testGetUserTablesFilterOutSystemTables() throws IOException {
+ Map<String, TableDescriptor> mockTables = new HashMap<>();
+ mockTables.put("foo", TableDescriptorBuilder.newBuilder(TableName.valueOf("foo")).build());
+ mockTables.put("bar", TableDescriptorBuilder.newBuilder(TableName.valueOf("bar")).build());
+ mockTables.put("meta",
+ TableDescriptorBuilder.newBuilder(TableName.valueOf("hbase", "meta")).build());
+
+ TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
+ Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
+
+ Mockito.doReturn(mockTables).when(tableDescriptors).getAll();
+
+ List<TableDescriptor> tables = new ArrayList<>();
+
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+
+ assertNull(errorMessage);
+ assertEquals(2, tables.size());
+ }
+
+ @Test
+ public void testGetUserTablesNoUserTables() throws IOException {
+ Map<Object, Object> emptyMap = Collections.emptyMap();
+
+ TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
+ Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
+
+ Mockito.doReturn(emptyMap).when(tableDescriptors).getAll();
+
+ List<TableDescriptor> tables = new ArrayList<>();
+
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+
+ assertNull(errorMessage);
+ assertEquals(0, tables.size());
+ }
+
+ @Test
+ public void testGetUserTablesMasterNotInitialized() {
+ Mockito.doReturn(false).when(master).isInitialized();
+
+ List<TableDescriptor> tables = new ArrayList<>();
+
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+
+ assertNull(errorMessage);
+ assertEquals(0, tables.size());
+ }
+
+ @Test
+ public void testGetUserTablesException() throws IOException {
+ TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
+ Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
+
+ Mockito.doThrow(new IOException("some error")).when(tableDescriptors).getAll();
+
+ List<TableDescriptor> tables = new ArrayList<>();
+ String errorMessage = MasterStatusUtil.getUserTables(master, tables);
+ assertEquals("Got user tables error, some error", errorMessage);
+ }
+
+ @Test
+ public void testGetFragmentationInfoTurnedOff() throws IOException {
+ conf.setBoolean("hbase.master.ui.fragmentation.enabled", false);
+ assertNull(MasterStatusUtil.getFragmentationInfo(master, conf));
+ }
+
+ @Test
+ public void testGetFragmentationInfoTurnedOn() throws IOException {
+ conf.setBoolean("hbase.master.ui.fragmentation.enabled", true);
+ Map<String, Integer> fragmentationInfo = MasterStatusUtil.getFragmentationInfo(master, conf);
+ assertNotNull(fragmentationInfo);
+ assertEquals(1, fragmentationInfo.size());
+ }
+
+ @Test
+ public void testGetMetaLocationOrNull() {
+ mockMetaLocation(true);
+
+ ServerName location = MasterStatusUtil.getMetaLocationOrNull(master);
+ assertNotNull(location);
+ assertEquals(FAKE_HOST, location);
+ }
+
+ @Test
+ public void testGetMetaLocationOrNullNotOpen() {
+ mockMetaLocation(false);
+
+ ServerName location = MasterStatusUtil.getMetaLocationOrNull(master);
+ assertNull(location);
+ }
+
+ private void mockMetaLocation(boolean isOpen) {
+ RegionStates rs = master.getAssignmentManager().getRegionStates();
+ RegionStateNode rsn = Mockito.mock(RegionStateNode.class);
+ Mockito.doReturn(rsn).when(rs).getRegionStateNode(RegionInfoBuilder.FIRST_META_REGIONINFO);
+ Mockito.doReturn(isOpen).when(rsn).isInState(RegionState.State.OPEN);
+ if (isOpen) {
+ Mockito.doReturn(FAKE_HOST).when(rsn).getRegionLocation();
+ }
+ }
+
+ @Test
+ public void testServerNameLink() {
+ Mockito.doReturn(16030).when(master).getRegionServerInfoPort(FAKE_HOST);
+
+ String link = MasterStatusUtil.serverNameLink(master, FAKE_HOST);
+
+ assertNotNull(link);
+ assertEquals("<a href=\"//fakehost:16030/rs-status\">fakehost,12345,1234567890</a>", link);
+ }
+
+ @Test
+ public void testServerNameLinkNoInfoPort() {
+ Mockito.doReturn(-1).when(master).getRegionServerInfoPort(FAKE_HOST);
+
+ String link = MasterStatusUtil.serverNameLink(master, FAKE_HOST);
+
+ assertNotNull(link);
+ assertEquals("fakehost,12345,1234567890", link);
+ }
+}