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/12/02 08:22:57 UTC
(hbase) branch branch-3 updated: HBASE-29531 Migrate RegionServer Status Jamon page back to JSP (#7491)
This is an automated email from the ASF dual-hosted git repository.
paksyd pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-3 by this push:
new 7dd4e55c876 HBASE-29531 Migrate RegionServer Status Jamon page back to JSP (#7491)
7dd4e55c876 is described below
commit 7dd4e55c876dadc365d908d6778b1c64cf63689b
Author: Dávid Paksy <pa...@apache.org>
AuthorDate: Tue Dec 2 09:22:50 2025 +0100
HBASE-29531 Migrate RegionServer Status Jamon page back to JSP (#7491)
* HBASE-29531 Migrate RegionServer Status Jamon page back to JSP (#7371)
This is the 2/3 step of the Jamon to JSP migration: the Region Server Status page.
Did the migration the same way as for the Master Status page: https://github.com/apache/hbase/pull/6875
Migrated the Jamon code to JSP as close as possible. Extracted the duplicated `formatZKString` method to new java class: ZKStringFormatter and added unit tests.
Changed the Region Server Status page back to `/regionserver.jsp`. Made sure that `/rs-status` redirects to `/regionserver.jsp`.
Extracted the BlockCache inline CSS styles to `hbase.css` file. Also extracted the large BlockCache Hit Ratio periods paging JavaScript code to separate .js file.
Introduced a `src/main/resources/hbase-webapps/common` directory where we can place common JSP files which are used by both Master and RegionServer JSP pages. This required to adjust the JSP compiler Maven Antrun plugin a bit.
Extracted the inline tablesorter initialization JavaScript code to separate file.
Signed-off-by: Duo Zhang <zh...@apache.org>
(cherry picked from commit 78922077a69765f91071b35fe77c323e253243cb)
* [ADDENDUM] HBASE-29223 Fix TestMasterStatusUtil (#7416)
TestMasterStatusUtil.testGetFragmentationInfoTurnedOn failed in master nightly build
Signed-off-by: Nihal Jain <ni...@apache.org>
Signed-off-by: Duo Zhang <zh...@apache.org>
(cherry picked from commit 8ef271f837397688c26e215f2eee6e80408eb799)
---
hbase-server/pom.xml | 18 +-
.../hadoop/hbase/tmpl/common/TaskMonitorTmpl.jamon | 140 -----
.../hbase/tmpl/regionserver/BlockCacheTmpl.jamon | 564 ---------------------
.../tmpl/regionserver/BlockCacheViewTmpl.jamon | 80 ---
.../hbase/tmpl/regionserver/RSStatusTmpl.jamon | 330 ------------
.../hbase/tmpl/regionserver/RegionListTmpl.jamon | 338 ------------
.../tmpl/regionserver/ReplicationStatusTmpl.jamon | 105 ----
.../tmpl/regionserver/ServerMetricsTmpl.jamon | 265 ----------
.../hadoop/hbase/master/http/MasterStatusUtil.java | 2 +-
.../hbase/regionserver/http/RSStatusConstants.java | 41 ++
.../hbase/regionserver/http/RSStatusServlet.java | 33 +-
.../hadoop/hbase/util/ZKStringFormatter.java | 57 +++
.../{master => common}/taskMonitor.jsp | 0
.../{master => common}/taskMonitorRenderTasks.jsp | 0
.../main/resources/hbase-webapps/master/hbck.jsp | 2 +-
.../main/resources/hbase-webapps/master/master.jsp | 2 +
.../resources/hbase-webapps/master/rsgroup.jsp | 31 +-
.../hbase-webapps/master/softwareAttributes.jsp | 34 +-
.../main/resources/hbase-webapps/master/table.jsp | 10 +-
.../hbase-webapps/regionserver/blockCache.jsp | 72 +++
.../{regionserver.jsp => blockCacheBaseInfo.jsp} | 24 +-
.../regionserver/blockCacheConfig.jsp | 72 +++
.../regionserver/blockCacheEvictions.jsp | 45 ++
.../hbase-webapps/regionserver/blockCacheHits.jsp | 92 ++++
.../hbase-webapps/regionserver/blockCacheLevel.jsp | 159 ++++++
.../hbase-webapps/regionserver/blockCacheStats.jsp | 58 +++
.../hbase-webapps/regionserver/blockCacheView.jsp | 62 +++
.../hbase-webapps/regionserver/footer.jsp | 10 +-
.../hbase-webapps/regionserver/header.jsp | 4 +-
.../hbase-webapps/regionserver/index.html | 2 +-
.../hbase-webapps/regionserver/regionList.jsp | 75 +++
.../regionserver/regionListBaseInfo.jsp | 58 +++
.../regionserver/regionListCompactStats.jsp | 79 +++
.../regionserver/regionListMemstoreStats.jsp | 70 +++
.../regionserver/regionListRequestStats.jsp | 61 +++
.../regionserver/regionListStoreStats.jsp | 119 +++++
.../hbase-webapps/regionserver/regionserver.jsp | 124 ++++-
.../regionserver/replicationStatus.jsp | 53 ++
.../regionserver/replicationStatusCurrentLog.jsp | 47 ++
.../replicationStatusReplicationDelay.jsp | 44 ++
.../regionserver/{footer.jsp => scripts.jsp} | 2 -
.../hbase-webapps/regionserver/serverMetrics.jsp | 55 ++
.../regionserver/serverMetricsBaseStats.jsp | 49 ++
.../serverMetricsByteBuffAllocatorStats.jsp | 51 ++
.../regionserver/serverMetricsMemoryStats.jsp | 78 +++
.../regionserver/serverMetricsQueueStats.jsp | 53 ++
.../regionserver/serverMetricsRequestStats.jsp | 46 ++
.../regionserver/serverMetricsStoreStats.jsp | 49 ++
.../regionserver/serverMetricsWalStats.jsp | 50 ++
.../regionserver/softwareAttributes.jsp | 114 +++++
.../resources/hbase-webapps/static/css/hbase.css | 29 ++
.../hbase-webapps/static/js/blockCacheInit.js | 120 +++++
.../static/js/regionServerStatusInit.js | 86 ++++
.../org/apache/hadoop/hbase/TestInfoServers.java | 5 +-
.../hbase/master/http/TestMasterStatusUtil.java | 6 +-
.../hbase/regionserver/http/TestRSStatusPage.java | 178 +++++++
.../regionserver/http/TestRSStatusServlet.java | 141 ------
.../hadoop/hbase/util/TestZKStringFormatter.java | 74 +++
hbase-shell/src/main/ruby/hbase/taskmonitor.rb | 6 +-
59 files changed, 2502 insertions(+), 2072 deletions(-)
diff --git a/hbase-server/pom.xml b/hbase-server/pom.xml
index 2ddcf0415e6..e27ab227887 100644
--- a/hbase-server/pom.xml
+++ b/hbase-server/pom.xml
@@ -564,12 +564,26 @@
<exclude name="**/*~"/>
</fileset>
</copy>
+ <!-- Create a "staging" JSP directory where we copy the common JSP files into master and rs directories.
+ Compilation is done using this "staging" JSP directory. -->
+ <mkdir dir="${project.build.directory}/jsp"/>
+ <copy todir="${project.build.directory}/jsp">
+ <fileset dir="${src.webapps}">
+ <include name="**/*.jsp"/>
+ </fileset>
+ </copy>
+ <copy todir="${project.build.directory}/jsp/master">
+ <fileset dir="${project.build.directory}/jsp/common"/>
+ </copy>
+ <copy todir="${project.build.directory}/jsp/regionserver">
+ <fileset dir="${project.build.directory}/jsp/common"/>
+ </copy>
<!--The compile.classpath is passed in by maven -->
<taskdef classname="org.apache.jasper.JspC" classpathref="maven.compile.classpath" name="jspcompiler"/>
<mkdir dir="${build.webapps}/master/WEB-INF"/>
- <jspcompiler outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.master" uriroot="${src.webapps}/master" webxml="${build.webapps}/master/WEB-INF/web.xml"/>
+ <jspcompiler outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.master" uriroot="${project.build.directory}/jsp/master" webxml="${build.webapps}/master/WEB-INF/web.xml"/>
<mkdir dir="${build.webapps}/regionserver/WEB-INF"/>
- <jspcompiler outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.regionserver" uriroot="${src.webapps}/regionserver" webxml="${build.webapps}/regionserver/WEB-INF/web.xml"/>
+ <jspcompiler outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.regionserver" uriroot="${project.build.directory}/jsp/regionserver" webxml="${build.webapps}/regionserver/WEB-INF/web.xml"/>
</target>
</configuration>
</execution>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/common/TaskMonitorTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/common/TaskMonitorTmpl.jamon
deleted file mode 100644
index 8798e930c70..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/common/TaskMonitorTmpl.jamon
+++ /dev/null
@@ -1,140 +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.*;
-org.apache.hadoop.hbase.monitoring.*;
-org.apache.hadoop.util.StringUtils;
-</%import>
-<%args>
-TaskMonitor taskMonitor = TaskMonitor.get();
-String filter = "general";
-String format = "html";
-String parent = "";
-</%args>
-
-<%if format.equals("json")%>
- <& renderTasks; filter=filter &>
-<%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">
- <& jsonView; filter="all" &>
- <& renderTasks; filter="all" &>
- </div>
- <div class="tab-pane active" id="tab_generaltasks" role="tabpanel">
- <& jsonView; filter="general" &>
- <& renderTasks; filter="general" &>
- </div>
- <div class="tab-pane" id="tab_handlertasks" role="tabpanel">
- <& jsonView; filter="handler" &>
- <& renderTasks; filter="handler" &>
- </div>
- <div class="tab-pane" id="tab_rpctasks" role="tabpanel">
- <& jsonView; filter="rpc" &>
- <& renderTasks; filter="rpc" &>
- </div>
- <div class="tab-pane" id="tab_operationtasks" role="tabpanel">
- <& jsonView; filter="operation" &>
- <& renderTasks; filter="operation" &>
- </div>
- </div>
- </div>
-</%if>
-
-<%def jsonView>
- <%args>
- String filter;
- </%args>
- <a href="<% parent %>?format=json&filter=<% filter %>">View as JSON</a>
-</%def>
-
-<%def renderTasks>
- <%args>
- String filter;
- </%args>
- <%java>
- 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;
- </%java>
- <%if format.equals("json") %>
- [<%for MonitoredTask task : tasks%><%if first%><%java>first = false;</%java><%else>,</%if><% task.toJSON() %></%for>]
- <%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; state = 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)
- </%if>
- </td>
- </tr>
- </%for>
- </table>
- </%if>
- </%if>
-</%def>
-
-<%def stateCss>
- <%args>
- MonitoredTask.State state;
- </%args>
-<%java> if (state == MonitoredTask.State.COMPLETE) { </%java>alert alert-success<%java> } </%java>
-<%java> else if (state == MonitoredTask.State.ABORTED) { </%java>alert alert-danger<%java> } </%java>
-</%def>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheTmpl.jamon
deleted file mode 100644
index 82609aad719..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheTmpl.jamon
+++ /dev/null
@@ -1,564 +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.
-
-Template for rendering Block Cache tabs in RegionServer Status page.
-</%doc>
-<%args>
-CacheConfig cacheConfig;
-Configuration config;
-BlockCache bc;
-</%args>
-<%java>
- String bcUrl = bc == null ? null : "http://hbase.apache.org/devapidocs/" + bc.getClass().getName().replaceAll("\\.", "/") + ".html";
- String bcName = bc == null ? null : bc.getClass().getSimpleName();
- BlockCache [] bcs = bc == null ? null : bc.getBlockCaches();
- boolean evictions = bcs != null && bcs.length > 1;
-</%java>
-<%import>
-java.util.Map;
-org.apache.hadoop.hbase.io.hfile.BlockCacheUtil;
-org.apache.hadoop.hbase.io.hfile.BlockCacheUtil.CachedBlocksByFile;
-org.apache.hadoop.hbase.io.hfile.AgeSnapshot;
-org.apache.hadoop.hbase.io.hfile.CachedBlock;
-org.apache.hadoop.conf.Configuration;
-org.apache.hadoop.hbase.io.hfile.CacheConfig;
-org.apache.hadoop.hbase.io.hfile.BlockCache;
-org.apache.hadoop.hbase.io.hfile.LruBlockCache;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketCacheStats;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocator;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocator.Bucket;
-org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix;
-</%import>
-<div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item"><a class="nav-link active" href="#tab_bc_baseInfo" data-bs-toggle="tab" role="tab">Base Info</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_bc_config" data-bs-toggle="tab" role="tab">Config</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_bc_stats" data-bs-toggle="tab" role="tab">Stats</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_bc_l1" data-bs-toggle="tab" role="tab">L1</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_bc_l2" data-bs-toggle="tab" role="tab">L2</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_bc_baseInfo" role="tabpanel">
- <& bc_baseInfo; bc = bc; bcUrl = bcUrl; bcName = bcName; &>
- </div>
- <div class="tab-pane" id="tab_bc_config" role="tabpanel">
- <& bc_config; cacheConfig = cacheConfig &>
- </div>
- <div class="tab-pane" id="tab_bc_stats" role="tabpanel">
- <& bc_stats; bc = bc &>
- </div>
- <div class="tab-pane" id="tab_bc_l1" role="tabpanel">
- <& bc_l; bc = bcs == null? bc: bcs[0]; name = "L1"; evictions = evictions; &>
- </div>
- <div class="tab-pane" id="tab_bc_l2" role="tabpanel">
- <& bc_l; bc = bcs == null? null: bcs.length <= 1? null: bcs[1]; name = "L2"; evictions = evictions; &>
- </div>
- </div>
-</div>
-
-<%def bc_baseInfo>
-<%args>
- BlockCache bc;
- String bcUrl;
- String bcName;
-</%args>
-<%java>
- BlockCache [] bcs = bc == null? null: bc.getBlockCaches();
- String bcl1Url = null;
- String bcl1Name = null;
- String bcl2Url = null;
- String bcl2Name = null;
- if (bcs != null) {
- BlockCache bcl1 = bcs[0];
- if (bcl1 != null) {
- bcl1Url = "http://hbase.apache.org/devapidocs/" + bcl1.getClass().getName().replaceAll("\\.", "/") + ".html";
- bcl1Name = bcl1.getClass().getSimpleName();
- }
- if (bcs.length == 2) {
- BlockCache bcl2 = bcs[1];
- bcl2Url = "http://hbase.apache.org/devapidocs/" + bcl2.getClass().getName().replaceAll("\\.", "/") + ".html";
- bcl2Name = bcl2.getClass().getSimpleName();
- }
- }
-</%java>
-<table class="table table-striped">
- <tr>
- <th>Attribute</th>
- <th>Value</th>
- <th>Description</th>
- </tr>
- </tr>
- <tr>
- <td>Implementation</td>
- <td><a href="<% bcUrl %>"><% bcName %></a></td>
- <td>Block cache implementing class</td>
- </tr>
-</table>
-<p>See <a href="http://hbase.apache.org/book.html#block.cache">block cache</a> in the HBase Reference Guide for help.</p>
-</%def>
-
-<%def bc_config>
-<%args>
- CacheConfig cacheConfig;
-</%args>
-<%if cacheConfig == null %>
-<p>CacheConfig is null</p>
-<%else>
-<table class="table table-striped">
- <tr>
- <th>Attribute</th>
- <th>Value</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>Cache DATA on Read</td>
- <td><% cacheConfig.shouldCacheDataOnRead() %></td>
- <td>True if DATA blocks are cached on read
- (INDEX & BLOOM blocks are always cached)</td>
- </tr>
- <tr>
- <td>Cache DATA on Write</td>
- <td><% cacheConfig.shouldCacheDataOnWrite() %></td>
- <td>True if DATA blocks are cached on write.</td>
- </tr>
- <tr>
- <td>Cache INDEX on Write</td>
- <td><% cacheConfig.shouldCacheIndexesOnWrite() %></td>
- <td>True if INDEX blocks are cached on write</td>
- </tr>
- <tr>
- <td>Cache BLOOM on Write</td>
- <td><% cacheConfig.shouldCacheBloomsOnWrite() %></td>
- <td>True if BLOOM blocks are cached on write</td>
- </tr>
- <tr>
- <td>Evict blocks on Close</td>
- <td><% cacheConfig.shouldEvictOnClose() %></td>
- <td>True if blocks are evicted from cache when an HFile
- reader is closed</td>
- </tr>
- <tr>
- <td>Cache DATA in compressed format</td>
- <td><% cacheConfig.shouldCacheDataCompressed() %></td>
- <td>True if DATA blocks are cached in their compressed form</td>
- </tr>
- <tr>
- <td>Prefetch on Open</td>
- <td><% cacheConfig.shouldPrefetchOnOpen() %></td>
- <td>True if blocks are prefetched into cache on open</td>
- </tr>
-</table>
-</%if>
-</%def>
-
-<%def evictions_tmpl>
-<%args>
- BlockCache bc;
-</%args>
-<%java>
- AgeSnapshot ageAtEvictionSnapshot = bc.getStats().getAgeAtEvictionSnapshot();
- // Only show if non-zero mean and stddev as is the case in combinedblockcache
-</%java>
- <tr>
- <td>Evicted</td>
- <td><% String.format("%,d", bc.getStats().getEvictedCount()) %></td>
- <td>The total number of blocks evicted</td>
- </tr>
- <tr>
- <td>Evictions</td>
- <td><% String.format("%,d", bc.getStats().getEvictionCount()) %></td>
- <td>The total number of times an eviction has occurred</td>
- </tr>
- <tr>
- <td>Mean</td>
- <td><% String.format("%,d", (long)ageAtEvictionSnapshot.getMean()) %></td>
- <td>Mean age of Blocks at eviction time (seconds)</td>
- </tr>
-</%def>
-
-<%def hits_tmpl>
-<%args>
- BlockCache bc;
-</%args>
-<%java>
- int hitPeriods = 0;
- for(int i=0; i<bc.getStats().getNumPeriodsInWindow(); i++) {
- if(bc.getStats().getWindowPeriods()[i] != null) {
- hitPeriods++;
- }
- }
-</%java>
-<%if hitPeriods > 0 %>
- <script>
- // Wait for document to be fully loaded
- document.addEventListener('DOMContentLoaded', function() {
-
- // Count actual items in the DOM
- const itemRows = document.querySelectorAll('tr.item-row');
-
- // Pagination state
- let currentPage = 1;
- const pageSize = 10;
- const totalItems = itemRows.length;
- const totalPages = Math.ceil(totalItems / pageSize);
-
- // Create page buttons
- const pageButtonsContainer = document.getElementById('page-buttons');
- if (pageButtonsContainer) {
- for (let i = 1; i <= totalPages; i++) {
- const button = document.createElement('button');
- button.className = 'page-number';
- button.textContent = i;
- button.onclick = function() { goToPage(i); };
- pageButtonsContainer.appendChild(button);
- }
- }
- function displayItems() {
- // Hide all item rows
- itemRows.forEach(row => {
- row.style.display = 'none';
- });
-
- // Calculate indexes
- const startIndex = (currentPage - 1) * pageSize;
- const endIndex = Math.min(startIndex + pageSize, totalItems);
-
- // Show rows for current page
- let displayedCount = 0;
- for (let i = startIndex; i < endIndex; i++) {
- const row = document.getElementById('row-' + i);
- if (row) {
- row.style.display = 'table-row';
- displayedCount++;
- }
- }
-
- // Update pagination UI
- document.querySelectorAll('.page-number').forEach(btn => {
- if (parseInt(btn.textContent) === currentPage) {
- btn.classList.add('active');
- } else {
- btn.classList.remove('active');
- }
- });
-
- const prevBtn = document.getElementById('prev-page');
- const nextBtn = document.getElementById('next-page');
-
- if (prevBtn) prevBtn.disabled = currentPage === 1;
- if (nextBtn) nextBtn.disabled = currentPage === totalPages;
-
- // Update page info
- const pageInfo = document.getElementById('page-info');
- if (pageInfo) {
- pageInfo.textContent = `Showing ${startIndex + 1} to ${endIndex} of ${totalItems} items`;
- }
- }
-
- function goToPage(page) {
- if (page >= 1 && page <= totalPages) {
- currentPage = page;
- displayItems();
- }
- }
-
- window.nextPage = function() {
- goToPage(currentPage + 1);
- };
-
- window.prevPage = function() {
- goToPage(currentPage - 1);
- };
-
- window.goToPage = goToPage;
-
- // Check URL for initial page
- const urlParams = new URLSearchParams(window.location.search);
- const pageParam = urlParams.get('page');
- if (pageParam) {
- const parsedPage = parseInt(pageParam);
- if (!isNaN(parsedPage) && parsedPage >= 1) {
- currentPage = parsedPage;
- }
- }
-
- // Initial display
- displayItems();
- });
- </script>
-</%if>
- <tr>
- <td>Hits</td>
- <td><% String.format("%,d", bc.getStats().getHitCount()) %></td>
- <td>Number requests that were cache hits</td>
- </tr>
- <tr>
- <td>Hits Caching</td>
- <td><% String.format("%,d", bc.getStats().getHitCachingCount()) %></td>
- <td>Cache hit block requests but only requests set to cache block if a miss</td>
- </tr>
- <tr>
- <td>Misses</td>
- <td><% String.format("%,d", bc.getStats().getMissCount()) %></td>
- <td>Block requests that were cache misses but set to cache missed blocks</td>
- </tr>
- <tr>
- <td>Misses Caching</td>
- <td><% String.format("%,d", bc.getStats().getMissCachingCount()) %></td>
- <td>Block requests that were cache misses but only requests set to use block cache</td>
- </tr>
- <tr>
- <td>All Time Hit Ratio</td>
- <td><% String.format("%,.2f", bc.getStats().getHitRatio() * 100) %><% "%" %></td>
- <td>Hit Count divided by total requests count</td>
- </tr>
- <%for int i=0; i<hitPeriods; i++ %>
- <tr id="row-<% i %>" class="item-row" style="display: none;">
- <td>Hit Ratio for period starting at <% bc.getStats().getWindowPeriods()[i] %></td>
- <%if bc.getStats().getRequestCounts()[i] > 0 %>
- <td><% String.format("%,.2f", ((double)bc.getStats().getHitCounts()[i] / (double)bc.getStats().getRequestCounts()[i]) * 100.0) %><% "%" %></td>
- <%else>
- <td>No requests</td>
- </%if>
- <td>Hit Count divided by total requests count over the <% i %>th period of <% bc.getStats().getPeriodTimeInMinutes() %> minutes</td>
- </tr>
- </%for>
- <%if hitPeriods > 0 %>
- <tr class="pagination-row">
- <td colspan="3">
- <div class="pagination-container">
- <button id="prev-page" onclick="prevPage()">Previous</button>
- <span id="page-buttons" class="page-numbers">
-
- </span>
- <button id="next-page" onclick="nextPage()">Next</button>
- <span id="page-info" class="page-info"></span>
- </div>
- </td>
- </tr>
- </%if>
- <%if bc.getStats().getPeriodTimeInMinutes() > 0 %>
- <tr>
- <td>Last <% bc.getStats().getNumPeriodsInWindow()*bc.getStats().getPeriodTimeInMinutes() %> minutes Hit Ratio</td>
- <td><% String.format("%,.2f", bc.getStats().getHitRatioPastNPeriods() * 100.0) %><% "%" %></td>
- <td>Hit Count divided by total requests count for the last <% bc.getStats().getNumPeriodsInWindow()*bc.getStats().getPeriodTimeInMinutes() %> minutes</td>
- </tr>
- <style>
- .pagination-container {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 10px 0;
- }
-
- .page-numbers {
- display: flex;
- gap: 4px;
- }
-
- .page-number {
- min-width: 30px;
- text-align: center;
- }
-
- .page-number.active {
- font-weight: bold;
- background-color: #eee;
- }
-
- .page-info {
- margin-left: 15px;
- font-size: 0.9em;
- color: #666;
- }
- </style>
- </%if>
-</%def>
-
-<%def bc_stats>
-<%args>
- BlockCache bc;
-</%args>
-<%if bc == null %>
-<p>BlockCache is null</p>
-<%else>
-<table class="table table-striped">
- <tr>
- <th>Attribute</th>
- <th>Value</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>Size</td>
- <td><% TraditionalBinaryPrefix.long2String(bc.getCurrentSize(),
- "B", 1) %></td>
- <td>Current size of block cache in use</td>
- </tr>
- <tr>
- <td>Free</td>
- <td><% TraditionalBinaryPrefix.long2String(bc.getFreeSize(),
- "B", 1) %></td>
- <td>The total free memory currently available to store more cache entries</td>
- </tr>
- <tr>
- <td>Count</td>
- <td><% String.format("%,d", bc.getBlockCount()) %></td>
- <td>Number of blocks in block cache</td>
- </tr>
- <& evictions_tmpl; bc = bc; &>
- <& hits_tmpl; bc = bc; &>
-</table>
-<p>If block cache is made up of more than one cache -- i.e. a L1 and a L2 -- then the above
-are combined counts. Request count is sum of hits and misses.</p>
-</%if>
-</%def>
-
-<%def bc_l>
-<%args>
- BlockCache bc;
- String name;
- boolean evictions;
-</%args>
-<%if bc == null %>
-<p>No <% name %> deployed</p>
-<%else>
-<& block_cache; bc = bc; name = name; evictions = evictions; &>
-</%if>
-</%def>
-
-<%def block_cache>
-<%args>
- BlockCache bc;
- String name;
- boolean evictions;
-</%args>
-<%java>
- String bcUrl = "http://hbase.apache.org/devapidocs/" + bc.getClass().getName().replaceAll("\\.", "/") + ".html";
- String bcName = bc.getClass().getSimpleName();
- int maxCachedBlocksByFile = BlockCacheUtil.getMaxCachedBlocksByFile(config);
-
- boolean lru = bc instanceof LruBlockCache;
-
- boolean bucketCache = bc.getClass().getSimpleName().equals("BucketCache");
- BucketCacheStats bucketCacheStats = null;
- BucketAllocator bucketAllocator = null;
-
- if (bucketCache) {
- bucketCacheStats = (BucketCacheStats)bc.getStats();
- bucketAllocator = ((BucketCache)bc).getAllocator();
- }
-</%java>
-<table id="blocks_summary" class="table table-striped">
- <tr>
- <th>Attribute</th>
- <th>Value</th>
- <th>Description</th>
- </tr>
- <tr>
- <td>Implementation</td>
- <td><a href="<% bcUrl %>"><% bc.getClass().getSimpleName() %></a></td>
- <td>Class implementing this block cache Level</td>
- </tr>
-<%if bucketCache %>
- <tr>
- <td>Implementation</td>
- <td><% ((BucketCache)bc).getIoEngine() %></a></td>
- <td>IOEngine</td>
- </tr>
-</%if>
- <tr>
- <td>Cache Size Limit</td>
- <td><% TraditionalBinaryPrefix.long2String(bc.getMaxSize(), "B", 1) %></td>
- <td>Max size of cache</td>
- </tr>
- <tr>
- <td>Block Count</td>
- <td><% String.format("%,d", bc.getBlockCount()) %></td>
- <td>Count of Blocks</td>
- </tr>
-<%if !bucketCache %>
- <tr>
- <td>Data Block Count</td>
- <td><% String.format("%,d", bc.getDataBlockCount()) %></td>
- <td>Count of DATA Blocks</td>
- </tr>
-</%if>
-<%if lru %>
- <tr>
- <td>Index Block Count</td>
- <td><% String.format("%,d", ((LruBlockCache)bc).getIndexBlockCount()) %></td>
- <td>Count of INDEX Blocks</td>
- </tr>
- <tr>
- <td>Bloom Block Count</td>
- <td><% String.format("%,d", ((LruBlockCache)bc).getBloomBlockCount()) %></td>
- <td>Count of BLOOM Blocks</td>
- </tr>
-</%if>
- <tr>
- <td>Size of Blocks</td>
- <td><% TraditionalBinaryPrefix.long2String(bc.getCurrentSize(), "B", 1) %></td>
- <td>Size of Blocks</td>
- </tr>
-<%if !bucketCache %>
- <tr>
- <td>Size of Data Blocks</td>
- <td><% TraditionalBinaryPrefix.long2String(bc.getCurrentDataSize(), "B", 1) %></td>
- <td>Size of DATA Blocks</td>
- </tr>
-</%if>
-<%if lru %>
- <tr>
- <td>Size of Index Blocks</td>
- <td><% TraditionalBinaryPrefix.long2String(((LruBlockCache)bc).getCurrentIndexSize(), "B", 1) %></td>
- <td>Size of INDEX Blocks</td>
- </tr>
- <tr>
- <td>Size of Bloom Blocks</td>
- <td><% TraditionalBinaryPrefix.long2String(((LruBlockCache)bc).getCurrentBloomSize(), "B", 1) %></td>
- <td>Size of BLOOM Blocks</td>
- </tr>
-</%if>
- <& evictions_tmpl; bc = bc; &>
-<& hits_tmpl; bc = bc; &>
-
-<%if bucketCache %>
- <tr>
- <td>Hits per Second</td>
- <td><% bucketCacheStats.getIOHitsPerSecond() %></td>
- <td>Block gets against this cache per second</td>
- </tr>
- <tr>
- <td>Time per Hit</td>
- <td><% bucketCacheStats.getIOTimePerHit() %></td>
- <td>Time per cache hit</td>
- </tr>
-</%if>
-</table>
-
-<%doc>Call through to block cache Detail rendering template</%doc>
-<p>
-View block cache <a href="?format=json&bcn=<% name %>">as JSON</a> | Block cache <a href="?format=json&bcn=<% name %>&bcv=file">as JSON by file</a>
-<%if bc.getBlockCount() > maxCachedBlocksByFile %>
-<br>
-<b>Note</b>: JSON view of block cache will be incomplete, because block count <% bc.getBlockCount() %> is greater than <i>hbase.ui.blockcache.by.file.max</i> value of <% maxCachedBlocksByFile %>.
-Increase that value to get a complete picture.
-</%if>
-</p>
-</%def>
-
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheViewTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheViewTmpl.jamon
deleted file mode 100644
index ce55aaf1270..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/BlockCacheViewTmpl.jamon
+++ /dev/null
@@ -1,80 +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.
-
-
-This template is used to give views on an individual block cache as JSON.
-</%doc>
-<%args>
-CacheConfig cacheConfig;
-Configuration conf;
-String bcn;
-String bcv;
-BlockCache blockCache;
-</%args>
-<%import>
-java.util.*;
-org.apache.hadoop.conf.Configuration;
-org.apache.hadoop.hbase.io.hfile.BlockCacheUtil.CachedBlocksByFile;
-org.apache.hadoop.hbase.io.hfile.BlockCacheUtil;
-org.apache.hadoop.hbase.io.hfile.CachedBlock;
-org.apache.hadoop.hbase.io.hfile.CacheConfig;
-org.apache.hadoop.hbase.io.hfile.BlockCache;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketCacheStats;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocator;
-org.apache.hadoop.hbase.io.hfile.bucket.BucketAllocator.Bucket;
-org.apache.hadoop.util.StringUtils;
-</%import>
-<%java>
- BlockCache bc = blockCache;
- BlockCache [] bcs = bc == null ? null : bc.getBlockCaches();
- if (bcn.equals("L1")) {
- bc = bcs == null || bcs.length == 0? bc: bcs[0];
- } else {
- if (bcs == null || bcs.length < 2) {
- System.out.println("There is no L2 block cache");
- return;
- }
- bc = bcs[1];
- }
- if (bc == null) {
- System.out.println("There is no block cache");
- return;
- }
- CachedBlocksByFile cbsbf = BlockCacheUtil.getLoadedCachedBlocksByFile(conf, bc);
-</%java>
-<%if bcv.equals("file") %><& bc_by_file; cbsbf = cbsbf; &><%else>[ <% BlockCacheUtil.toJSON(bc) %>, <% BlockCacheUtil.toJSON(cbsbf) %> ]</%if>
-<%java>
-cbsbf = null;
-</%java>
-
-<%def bc_by_file>
-<%args>
- CachedBlocksByFile cbsbf;
-</%args>
-<%java>
- boolean firstEntry = true;
-</%java>
-[<%for Map.Entry<String, NavigableSet<CachedBlock>> e: cbsbf.getCachedBlockStatsByFile().entrySet() %>
- <%if !firstEntry %>,</%if><% BlockCacheUtil.toJSON(e.getKey(), e.getValue()) %>
- <%java>
- if (firstEntry) {
- firstEntry = false;
- }
- </%java>
-</%for>]
-</%def>
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
deleted file mode 100644
index 15426675dec..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RSStatusTmpl.jamon
+++ /dev/null
@@ -1,330 +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>
-HRegionServer regionServer;
-String filter = "general";
-String format = "html";
-String bcn = "";
-String bcv = "";
-</%args>
-<%import>
-java.util.*;
-org.apache.hadoop.hbase.regionserver.HRegionServer;
-org.apache.hadoop.hbase.client.RegionInfo;
-org.apache.hadoop.hbase.ServerName;
-org.apache.hadoop.hbase.HBaseConfiguration;
-org.apache.hadoop.hbase.io.hfile.CacheConfig;
-org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
-org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ServerInfo;
-org.apache.hadoop.hbase.util.JvmVersion;
-org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
-</%import>
-<%doc>If json AND bcn is NOT an empty string presume it a block cache view request.</%doc>
-<%if format.equals("json") && bcn != null && bcn.length() > 0 %>
- <& BlockCacheViewTmpl; conf = regionServer.getConfiguration(); cacheConfig = new CacheConfig(regionServer.getConfiguration()); bcn = bcn; bcv = bcv; blockCache = regionServer.getBlockCache().orElse(null) &>
- <%java return; %>
-<%elseif format.equals("json") %>
- <& ../common/TaskMonitorTmpl; filter = filter; format = "json" &>
- <%java return; %>
-</%if>
-<%java>
- ServerInfo serverInfo = ProtobufUtil.getServerInfo(null, regionServer.getRSRpcServices());
- ServerName serverName = ProtobufUtil.toServerName(serverInfo.getServerName());
- List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(regionServer.getRSRpcServices());
- MasterAddressTracker masterAddressTracker = regionServer.getMasterAddressTracker();
- ServerName masterServerName = masterAddressTracker == null ? null
- : masterAddressTracker.getMasterAddress();
- int infoPort = masterAddressTracker == null ? 0 : masterAddressTracker.getMasterInfoPort();
-</%java>
-
-<%class>
- public String formatZKString() {
- StringBuilder quorums = new StringBuilder();
- String zkQuorum = regionServer.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>
-
-<!DOCTYPE html>
-<?xml version="1.0" encoding="UTF-8" ?>
-<html lang="en">
- <head>
- <meta charset="utf-8">
- <title>HBase Region Server: <% serverName.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="/rs-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="/rs-status">Home</a></li>
- <li class="nav-item"><a class="nav-link" href="/processRS.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="/rsOperationDetails.jsp">Operation Details</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>
- </ul>
- </div><!--/.navbar-collapse -->
- </div><!--/.container-fluid -->
- </nav>
-
- <div class="container-fluid content">
- <div class="row inner_header">
- <div class="page-header">
- <h1>RegionServer <small><% serverName %></small></h1>
- </div>
- </div>
- <div class="row">
-
- <section>
- <h2>Server Metrics</h2>
- <& ServerMetricsTmpl; mWrap = regionServer.getMetrics().getRegionServerWrapper();
- mServerWrap = regionServer.getRpcServer().getMetrics().getHBaseServerWrapper();
- bbAllocator = regionServer.getRpcServer().getByteBuffAllocator(); &>
- </section>
-
- <section>
- <h2>Block Cache</h2>
- <& BlockCacheTmpl; cacheConfig = new CacheConfig(regionServer.getConfiguration()); config = regionServer.getConfiguration(); bc = regionServer.getBlockCache().orElse(null) &>
- </section>
-
- <section>
- <& ../common/TaskMonitorTmpl; filter = filter; parent = "/rs-status" &>
- </section>
-
- <section>
- <h2>Regions</h2>
- <& RegionListTmpl; regionServer = regionServer; onlineRegions = onlineRegions; &>
- </section>
-
- <section>
- <h2>Replication Status</h1>
- <& ReplicationStatusTmpl; regionServer = regionServer; &>
- </section>
-
- <section>
- <h2>Software Attributes</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</td>
- </tr>
- <tr>
- <td>Coprocessors</td>
- <td><% java.util.Arrays.toString(regionServer.getRegionServerCoprocessors()) %></td>
- <td>Coprocessors currently loaded by this regionserver</td>
- </tr>
- <tr>
- <td>RS Start Time</td>
- <td><% new Date(regionServer.getStartcode()) %></td>
- <td>Date stamp of when this region server was started</td>
- </tr>
- <tr>
- <td>HBase Master</td>
- <td>
- <%if masterServerName == null %>
- No master found
- <%else>
- <%java>
- String host = masterServerName.getHostname() + ":" + infoPort;
- String url = "//" + host + "/master.jsp";
- </%java>
- <a href="<% url %>"><% host %></a>
- </%if>
- </td>
- <td>Address of HBase Master</td>
- </tr>
- </table>
- </section>
- </div>
-</div>
-<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/bootstrap.bundle.min.js" type="text/javascript"></script>
-<script src="/static/js/tab.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"
- });
-
- $("#baseStatsTable").tablesorter({
- headers: {
- '.cls_emptyMin': {empty: 'emptyMin'},
- '.cls_emptyMax': {empty: 'emptyMax'}
- }
- });
- $("#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'}
- }
- });
- $("#memstoreStatsTable").tablesorter({
- headers: {
- '.cls_filesize': {sorter: 'filesize'}
- }
- });
- }
-);
-</script>
-</body>
-</html>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RegionListTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RegionListTmpl.jamon
deleted file mode 100644
index c4b947308ba..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/RegionListTmpl.jamon
+++ /dev/null
@@ -1,338 +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>
- HRegionServer regionServer;
- List<RegionInfo> onlineRegions;
-</%args>
-<%import>
- java.util.*;
- org.apache.commons.lang3.time.FastDateFormat;
- org.apache.hadoop.hbase.regionserver.HRegionServer;
- org.apache.hadoop.hbase.util.Bytes;
- org.apache.hadoop.hbase.client.RegionInfo;
- org.apache.hadoop.hbase.client.RegionInfoDisplay;
- org.apache.hadoop.hbase.regionserver.Region;
- org.apache.hadoop.hbase.regionserver.HStoreFile;
- org.apache.hadoop.hbase.regionserver.Store;
- org.apache.hadoop.hbase.regionserver.StoreFile;
- org.apache.hadoop.hbase.ServerName;
- org.apache.hadoop.hbase.HBaseConfiguration;
- org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
- org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ServerInfo;
- org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad;
- org.apache.hadoop.hbase.client.RegionReplicaUtil;
- org.apache.hadoop.hbase.regionserver.MetricsRegionWrapper;
- org.apache.hadoop.util.StringUtils;
- org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix;
-</%import>
-<%if (onlineRegions != null && onlineRegions.size() > 0) %>
-
- <%java>
- Collections.sort(onlineRegions, RegionInfo.COMPARATOR);
- </%java>
-
- <div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item"><a class="nav-link active" href="#tab_regionBaseInfo" data-bs-toggle="tab" role="tab">Base Info</a> </li>
- <li class="nav-item"><a class="nav-link" href="#tab_regionRequestStats" data-bs-toggle="tab" role="tab">Request metrics</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_regionStoreStats" data-bs-toggle="tab" role="tab">Storefile Metrics</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_regionMemstoreStats" data-bs-toggle="tab" role="tab">Memstore Metrics</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_regionCompactStats" data-bs-toggle="tab" role="tab">Compaction Metrics</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_regionBaseInfo" role="tabpanel">
- <& baseInfo; onlineRegions = onlineRegions; &>
- </div>
- <div class="tab-pane" id="tab_regionRequestStats" role="tabpanel">
- <& requestStats; onlineRegions = onlineRegions; &>
- </div>
- <div class="tab-pane" id="tab_regionStoreStats" role="tabpanel">
- <& storeStats; onlineRegions = onlineRegions; &>
- </div>
- <div class="tab-pane" id="tab_regionMemstoreStats" role="tabpanel">
- <& memstoreStats; onlineRegions = onlineRegions; &>
- </div>
- <div class="tab-pane" id="tab_regionCompactStats" role="tabpanel">
- <& compactStats; onlineRegions = onlineRegions; &>
- </div>
- </div>
- </div>
- <p>Region names are made of the containing table's name, a comma,
- the start key, a comma, and a randomly generated region id. To illustrate,
- the region named
- <em>domains,apache.org,5464829424211263407</em> is party to the table
- <em>domains</em>, has an id of <em>5464829424211263407</em> and the first key
- in the region is <em>apache.org</em>. The <em>hbase:meta</em> 'table' is an internal
- system table (or a 'catalog' table in db-speak).
- The hbase:meta table keeps a list of all regions in the system. The empty key is used to denote
- table start and table end. A region with an empty start key is the first region in a table.
- If a region has both an empty start key and an empty end key, it's the only region in the
- table. See <a href="http://hbase.apache.org">HBase Home</a> for further explication.<p>
-<%else>
- <p>Not serving regions</p>
-</%if>
-
-<%def baseInfo>
-<%args>
- List<RegionInfo> onlineRegions;
-</%args>
- <table id="baseStatsTable" class="tablesorter table table-striped">
- <thead>
- <tr>
- <th>Region Name</th>
- <th class="cls_emptyMin">Start Key</th>
- <th class="cls_emptyMax">End Key</th>
- <th>ReplicaID</th>
- </tr>
- </thead>
-
- <tbody>
- <%for RegionInfo r: onlineRegions %>
- <tr>
- <%java>
- String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
- regionServer.getConfiguration());
- </%java>
- <td><a href="region.jsp?name=<% r.getEncodedName() %>"><% displayName %></a></td>
- <td><% Bytes.toStringBinary(RegionInfoDisplay.getStartKeyForDisplay(r,
- regionServer.getConfiguration())) %></td>
- <td><% Bytes.toStringBinary(RegionInfoDisplay.getEndKeyForDisplay(r,
- regionServer.getConfiguration())) %></td>
- <td><% r.getReplicaId() %></td>
- </tr>
- </%for>
- </tbody>
- </table>
-</%def>
-
-<%def requestStats>
-<%args>
- List<RegionInfo> onlineRegions;
-</%args>
- <table id="requestStatsTable" class="tablesorter table table-striped">
- <thead>
- <tr>
- <th>Region Name</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 RegionInfo r: onlineRegions %>
-
- <tr>
- <%java>
- RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
- String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
- regionServer.getConfiguration());
- </%java>
- <td><a href="region.jsp?name=<% r.getEncodedName() %>"><% displayName %></a></td>
- <%if load != null %>
- <td><% String.format("%,1d", load.getReadRequestsCount()) %></td>
- <td><% String.format("%,1d", load.getFilteredReadRequestsCount()) %></td>
- <td><% String.format("%,1d", load.getWriteRequestsCount()) %></td>
- </%if>
- </tr>
- </%for>
- </tbody>
- </table>
-</%def>
-
-
-<%def storeStats>
-<%args>
- List<RegionInfo> onlineRegions;
-</%args>
- <table id="storeStatsTable" class="tablesorter table table-striped">
- <thead>
- <tr>
- <th>Region Name</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>
- <th>Data Locality</th>
- <th>Len Of Biggest Cell</th>
- <th>% Cached</th>
- </tr>
- </thead>
-
- <tbody>
- <%for RegionInfo r: onlineRegions %>
-
- <tr>
- <%java>
- final String ZEROMB = "0 MB";
- final String ZEROKB = "0 KB";
- String uncompressedStorefileSizeStr = ZEROMB;
- String storefileSizeStr = ZEROMB;
- String indexSizeStr = ZEROKB;
- String bloomSizeStr = ZEROKB;
- RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
- String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
- regionServer.getConfiguration());
- if (load != null) {
- long uncompressedStorefileSize = load.getStoreUncompressedSizeMB();
- long storefileSize = load.getStorefileSizeMB();
- long indexSize = load.getTotalStaticIndexSizeKB();
- long bloomSize = load.getTotalStaticBloomSizeKB();
- 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);
- }
- }
- long lenOfBiggestCellInRegion = -1L;
- Region region = regionServer.getRegion(r.getEncodedName());
- if (region != null) {
- List<? extends Store> stores = region.getStores();
- for (Store store : stores) {
- Collection<? extends StoreFile> storeFiles = store.getStorefiles();
- for (StoreFile sf : storeFiles) {
- long lenOfBiggestCell = ((HStoreFile)sf).getFileInfo().getHFileInfo().getLenOfBiggestCell();
- if (lenOfBiggestCellInRegion < lenOfBiggestCell) {
- lenOfBiggestCellInRegion = lenOfBiggestCell;
- }
- }
- }
- }
-
- </%java>
- <td><a href="region.jsp?name=<% r.getEncodedName() %>"><% displayName %></a></td>
- <%if load != null %>
- <td><% String.format("%,1d", load.getStores()) %></td>
- <td><% String.format("%,1d", load.getStorefiles()) %></td>
- <td><% uncompressedStorefileSizeStr %></td>
- <td><% storefileSizeStr %></td>
- <td><% indexSizeStr %></td>
- <td><% bloomSizeStr %></td>
- <td><% load.getDataLocality() %></td>
- <td><% String.format("%,1d", lenOfBiggestCellInRegion) %></td>
- <td><% StringUtils.formatPercent(load.getCurrentRegionCachedRatio(), 2) %></td>
- </%if>
- </tr>
- </%for>
- </tbody>
- </table>
-</%def>
-
-
-<%def compactStats>
-<%args>
- List<RegionInfo> onlineRegions;
-</%args>
- <table id="compactionStatsTable" class="tablesorter table table-striped">
- <thead>
- <tr>
- <th>Region Name</th>
- <th class="cls_separator">Num. Compacting Cells</th>
- <th class="cls_separator">Num. Compacted Cells</th>
- <th>Compaction Progress</th>
- <th data-date-format="yyyymmdd hhmm zz">Last Major Compaction</th>
- </tr>
- </thead>
-
- <tbody>
- <%for RegionInfo r: onlineRegions %>
-
- <tr>
- <%java>
- RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
- String percentDone = "";
- String compactTime = "";
- if (load != null) {
- if (load.getTotalCompactingKVs() > 0) {
- percentDone = String.format("%.2f", 100 *
- ((float) load.getCurrentCompactedKVs() / load.getTotalCompactingKVs())) + "%";
- }
- if (load.getLastMajorCompactionTs() > 0) {
- FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm (ZZ)");
- compactTime = fdf.format(load.getLastMajorCompactionTs());
- }
- }
- String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
- regionServer.getConfiguration());
- </%java>
- <td><a href="region.jsp?name=<% r.getEncodedName() %>"><% displayName %></a></td>
- <%if load != null %>
- <td><% String.format("%,1d", load.getTotalCompactingKVs()) %></td>
- <td><% String.format("%,1d", load.getCurrentCompactedKVs()) %></td>
- <td><% percentDone %></td>
- <td><% compactTime %></td>
- </%if>
- </tr>
- </%for>
- </tbody>
- </table>
-</%def>
-
-<%def memstoreStats>
-<%args>
- List<RegionInfo> onlineRegions;
-</%args>
- <table id="memstoreStatsTable" class="tablesorter table table-striped">
- <thead>
- <tr>
- <th>Region Name</th>
- <th class="cls_filesize">Memstore Size</th>
- </tr>
- </thead>
-
- <tbody>
- <%for RegionInfo r: onlineRegions %>
-
- <tr>
- <%java>
- final String ZEROMB = "0 MB";
- String memStoreSizeMBStr = ZEROMB;
- RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
- String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
- regionServer.getConfiguration());
- if (load != null) {
- long memStoreSizeMB = load.getMemStoreSizeMB();
- if (memStoreSizeMB > 0) {
- memStoreSizeMBStr = TraditionalBinaryPrefix.long2String(
- memStoreSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
- }
- }
- </%java>
- <td><a href="region.jsp?name=<% r.getEncodedName() %>"><% displayName %></a></td>
- <%if load != null %>
- <td><% memStoreSizeMBStr %></td>
- </%if>
- </tr>
- </%for>
- </tbody>
- </table>
-</%def>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ReplicationStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ReplicationStatusTmpl.jamon
deleted file mode 100644
index 273b26aecd3..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ReplicationStatusTmpl.jamon
+++ /dev/null
@@ -1,105 +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>
- HRegionServer regionServer;
-</%args>
-<%import>
- java.util.*;
- java.util.Map.Entry;
- org.apache.hadoop.hbase.procedure2.util.StringUtils;
- org.apache.hadoop.hbase.regionserver.HRegionServer;
- org.apache.hadoop.hbase.replication.regionserver.ReplicationStatus;
-</%import>
-
-<%java>
- Map<String, ReplicationStatus> walGroupsReplicationStatus = regionServer.getWalGroupsReplicationStatus();
-</%java>
-
-<%if (walGroupsReplicationStatus != null && walGroupsReplicationStatus.size() > 0) %>
-
- <div class="tabbable">
- <ul class="nav nav-pills" role="tablist">
- <li class="nav-item"><a class="nav-link active" href="#tab_currentLog" data-bs-toggle="tab" role="tab">Current Log</a> </li>
- <li class="nav-item"><a class="nav-link" href="#tab_replicationDelay" data-bs-toggle="tab" role="tab">Replication Delay</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_currentLog" role="tabpanel">
- <& currentLog; metrics = walGroupsReplicationStatus; &>
- </div>
- <div class="tab-pane" id="tab_replicationDelay" role="tabpanel">
- <& replicationDelay; metrics = walGroupsReplicationStatus; &>
- </div>
- </div>
- </div>
- <p> If the replication delay is UNKNOWN, that means this walGroup doesn't start replicate yet and it may get disabled.
- If the size of log is 0, it means we are replicating current HLog, thus we can't get accurate size since it's not closed yet.</p>
-
-<%else>
- <p>No Replication Metrics for Peers</p>
-</%if>
-
-<%def currentLog>
-<%args>
- Map<String, ReplicationStatus> metrics;
-</%args>
- <table class="table table-striped">
- <tr>
- <th>PeerId</th>
- <th>WalGroup</th>
- <th>Current Log</th>
- <th>Size</th>
- <th>Queue Size</th>
- <th>Offset</th>
- </tr>
- <%for Map.Entry<String, ReplicationStatus> entry: metrics.entrySet() %>
- <tr>
- <td><% entry.getValue().getPeerId() %></td>
- <td><% entry.getValue().getWalGroup() %></td>
- <td><% entry.getValue().getCurrentPath() %> </td>
- <td><% StringUtils.humanSize(entry.getValue().getFileSize()) %></td>
- <td><% entry.getValue().getQueueSize() %></td>
- <td><% StringUtils.humanSize(entry.getValue().getCurrentPosition()) %></td>
- </tr>
- </%for>
- </table>
-</%def>
-
-<%def replicationDelay>
-<%args>
- Map<String, ReplicationStatus> metrics;
-</%args>
- <table class="table table-striped">
- <tr>
- <th>PeerId</th>
- <th>WalGroup</th>
- <th>Current Log</th>
- <th>Last Shipped Age</th>
- <th>Replication Delay</th>
- </tr>
- <%for Map.Entry<String, ReplicationStatus> entry: metrics.entrySet() %>
- <tr>
- <td><% entry.getValue().getPeerId() %></td>
- <td><% entry.getValue().getWalGroup() %></td>
- <td><% entry.getValue().getCurrentPath() %> </td>
- <td><% StringUtils.humanTimeDiff(entry.getValue().getAgeOfLastShippedOp()) %></td>
- <td><% entry.getValue().getReplicationDelay() == Long.MAX_VALUE ? "UNKNOWN" : StringUtils.humanTimeDiff(entry.getValue().getReplicationDelay()) %></td>
- </tr>
- </%for>
- </table>
-</%def>
diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ServerMetricsTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ServerMetricsTmpl.jamon
deleted file mode 100644
index 7805a8b0908..00000000000
--- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ServerMetricsTmpl.jamon
+++ /dev/null
@@ -1,265 +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>
-MetricsRegionServerWrapper mWrap;
-MetricsHBaseServerWrapper mServerWrap;
-ByteBuffAllocator bbAllocator;
-</%args>
-<%import>
-java.util.*;
-org.apache.hadoop.hbase.regionserver.HRegionServer;
-org.apache.hadoop.hbase.io.ByteBuffAllocator;
-org.apache.hadoop.hbase.ipc.MetricsHBaseServerWrapper;
-org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper;
-org.apache.hadoop.hbase.util.Bytes;
-org.apache.hadoop.hbase.ServerName;
-org.apache.hadoop.hbase.HBaseConfiguration;
-org.apache.hadoop.hbase.util.DirectMemoryUtils;
-org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix;
-java.lang.management.MemoryUsage;
-org.apache.hadoop.hbase.io.util.MemorySizeUtil;
-</%import>
-<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_walStats" data-bs-toggle="tab" role="tab">WALs</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_queueStats" data-bs-toggle="tab" role="tab">Queues</a></li>
- <li class="nav-item"><a class="nav-link" href="#tab_byteBuffAllocatorStats" data-bs-toggle="tab" role="tab">ByteBuffAllocator Stats</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="tab_baseStats" role="tabpanel">
- <& baseStats; mWrap = mWrap &>
- </div>
- <div class="tab-pane" id="tab_memoryStats" role="tabpanel">
- <& memoryStats; mWrap = mWrap &>
- </div>
- <div class="tab-pane" id="tab_requestStats" role="tabpanel">
- <& requestStats; mWrap = mWrap &>
- </div>
- <div class="tab-pane" id="tab_walStats" role="tabpanel">
- <& walStats; mWrap = mWrap &>
- </div>
- <div class="tab-pane" id="tab_storeStats" role="tabpanel">
- <& storeStats; mWrap = mWrap &>
- </div>
- <div class="tab-pane" id="tab_queueStats" role="tabpanel">
- <& queueStats; mWrap = mWrap; mServerWrap = mServerWrap; &>
- </div>
- <div class="tab-pane" id="tab_byteBuffAllocatorStats" role="tabpanel">
- <& byteBuffAllocatorStats; bbAllocator = bbAllocator; &>
- </div>
- </div>
-</div>
-
-<%def baseStats>
-<%args>
- MetricsRegionServerWrapper mWrap;
-</%args>
-<table class="table table-striped">
- <tr>
-
- <th>Requests Per Second</th>
- <th>Num. Regions</th>
- <th>Block locality</th>
- <th>Block locality (Secondary replicas)</th>
- <th>Slow WAL Append Count</th>
- </tr>
- <tr>
- <td><% String.format("%.0f", mWrap.getRequestsPerSecond()) %></td>
- <td><% mWrap.getNumOnlineRegions() %></td>
- <td><% String.format("%.3f",mWrap.getPercentFileLocal()) %><% "%" %></td>
- <td><% String.format("%.3f",mWrap.getPercentFileLocalSecondaryRegions()) %><% "%" %></td>
- <td><% mWrap.getNumWALSlowAppend() %></td>
- </tr>
-</table>
-</%def>
-
-<%def memoryStats>
-<%args>
-MetricsRegionServerWrapper mWrap;
-</%args>
-<%java
- long usedHeap = -1L;
- long maxHeap = -1L;
- final MemoryUsage usage = MemorySizeUtil.safeGetHeapMemoryUsage();
- if (usage != null) {
- maxHeap = usage.getMax();
- usedHeap = usage.getUsed();
- }
-%>
-<table class="table table-striped">
-<tr>
- <tr>
- <th>Used Heap</th>
- <th>Max Heap</th>
- <th>Direct Memory Used</th>
- <th>Direct Memory Configured</th>
- <th>Memstore On-Heap Size / Limit</th>
- <th>Memstore Off-Heap Size / Limit</th>
- <th>Memstore Data Size (On&&Off Heap)</th>
- </tr>
-</tr>
-<tr>
- <td>
- <% TraditionalBinaryPrefix.long2String(usedHeap, "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(maxHeap, "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(DirectMemoryUtils.getDirectMemoryUsage(), "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(DirectMemoryUtils.getDirectMemorySize(), "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(mWrap.getOnHeapMemStoreSize(), "B", 1) + " / "
- + TraditionalBinaryPrefix.long2String(mWrap.getOnHeapMemStoreLimit(), "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(mWrap.getOffHeapMemStoreSize(), "B", 1) + " / "
- + TraditionalBinaryPrefix.long2String(mWrap.getOffHeapMemStoreLimit(), "B", 1) %>
- </td>
- <td>
- <% TraditionalBinaryPrefix.long2String(mWrap.getMemStoreSize(), "B", 1) %>
- </td>
-</tr>
-</table>
-</%def>
-
-<%def walStats>
-<%args>
-MetricsRegionServerWrapper mWrap;
-</%args>
-<table class="table table-striped">
-<tr>
- <tr>
- <th>Num. WAL Files</th>
- <th>Size. WAL Files</th>
- <th>WAL exclude DNs</th>
- </tr>
-</tr>
-<tr>
- <td><% mWrap.getNumWALFiles() %></td>
- <td><% TraditionalBinaryPrefix.long2String(mWrap.getWALFileSize(), "B", 1) %></td>
- <td>
- <%for String exclude: mWrap.getWALExcludeDNs() %>
- <% exclude %><br>
- </%for>
- </td>
-</tr>
-</table>
-</%def>
-
-<%def storeStats>
-<%args>
-MetricsRegionServerWrapper mWrap;
-</%args>
-<table class="table table-striped">
-<tr>
-
- <th>Num. Stores</th>
- <th>Num. Storefiles</th>
- <th>Root Index Size</th>
- <th>Index Size</th>
- <th>Bloom Size</th>
-</tr>
-<tr>
- <td><% mWrap.getNumStores() %></td>
- <td><% mWrap.getNumStoreFiles() %></td>
- <td><% TraditionalBinaryPrefix.long2String(mWrap.getStoreFileIndexSize(), "B", 1) %></td>
- <td><% TraditionalBinaryPrefix.long2String(mWrap.getTotalStaticIndexSize(), "B", 1) %></td>
- <td><% TraditionalBinaryPrefix.long2String(mWrap.getTotalStaticBloomSize(), "B", 1) %></td>
-</tr>
-</table>
-</%def>
-
-
-<%def requestStats>
-<%args>
-MetricsRegionServerWrapper mWrap;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>Request Per Second</th>
- <th>Read Request Count</th>
- <th>Filtered Read Request Count</th>
- <th>Write Request Count</th>
-</tr>
-<tr>
- <td><% String.format("%.0f", mWrap.getRequestsPerSecond()) %></td>
- <td><% mWrap.getReadRequestsCount() %></td>
- <td><% mWrap.getFilteredReadRequestsCount() %></td>
- <td><% mWrap.getWriteRequestsCount() %></td>
-</tr>
-</table>
-</%def>
-
-<%def queueStats>
-<%args>
-MetricsRegionServerWrapper mWrap;
-MetricsHBaseServerWrapper mServerWrap;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>Compaction Queue Length</th>
- <th>Flush Queue Length</th>
- <th>Priority Call Queue Length</th>
- <th>General Call Queue Length</th>
- <th>Replication Call Queue Length</th>
- <th>Total Call Queue Size</th>
-
-</tr>
-<tr>
- <td><% mWrap.getCompactionQueueSize() %></td>
- <td><% mWrap.getFlushQueueSize() %></td>
- <td><% mServerWrap.getPriorityQueueLength() %></td>
- <td><% mServerWrap.getGeneralQueueLength() %></td>
- <td><% mServerWrap.getReplicationQueueLength() %></td>
- <td><% TraditionalBinaryPrefix.long2String(mServerWrap.getTotalQueueSize(), "B", 1) %></td>
-</tr>
-</table>
-</%def>
-
-<%def byteBuffAllocatorStats>
-<%args>
-ByteBuffAllocator bbAllocator;
-</%args>
-<table class="table table-striped">
-<tr>
- <th>Total Heap Allocation</th>
- <th>Total Pool Allocation</th>
- <th>Heap Allocation Ratio</th>
- <th>Total Buffer Count</th>
- <th>Used Buffer Count</th>
- <th>Buffer Size</th>
-</tr>
-<tr>
- <td><% TraditionalBinaryPrefix.long2String(ByteBuffAllocator.getHeapAllocationBytes(bbAllocator, ByteBuffAllocator.HEAP), "B", 1) %></td>
- <td><% TraditionalBinaryPrefix.long2String(bbAllocator.getPoolAllocationBytes(), "B", 1) %></td>
- <td><% String.format("%.3f", ByteBuffAllocator.getHeapAllocationRatio(bbAllocator, ByteBuffAllocator.HEAP) * 100) %><% "%" %></td>
- <td><% bbAllocator.getTotalBufferCount() %></td>
- <td><% bbAllocator.getUsedBufferCount() %></td>
- <td><% TraditionalBinaryPrefix.long2String(bbAllocator.getBufferSize(), "B", 1) %></td>
-</tr>
-</table>
-</%def>
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
index 221e43f8e11..c860e89681c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/http/MasterStatusUtil.java
@@ -79,7 +79,7 @@ public final class MasterStatusUtil {
public static String serverNameLink(HMaster master, ServerName serverName) {
int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
+ String url = "//" + serverName.getHostname() + ":" + infoPort + "/regionserver.jsp";
if (infoPort > 0) {
return "<a href=\"" + url + "\">" + serverName.getServerName() + "</a>";
} else {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusConstants.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusConstants.java
new file mode 100644
index 00000000000..09b7c34e331
--- /dev/null
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusConstants.java
@@ -0,0 +1,41 @@
+/*
+ * 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.regionserver.http;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Constants used by the web UI JSP pages.
+ */
+@InterfaceAudience.Private
+public final class RSStatusConstants {
+ public static final String FILTER = "filter";
+ public static final String FILTER_GENERAL = "general";
+ public static final String FORMAT = "format";
+ public static final String FORMAT_JSON = "json";
+ public static final String FORMAT_HTML = "html";
+ public static final String PARENT = "parent";
+ public static final String BLOCK_CACHE_NAME = "bcn";
+ public static final String BLOCK_CACHE_NAME_L1 = "L1";
+ public static final String BLOCK_CACHE_V = "bcv";
+ public static final String BLOCK_CACHE_V_FILE = "file";
+
+ private RSStatusConstants() {
+ // Do not instantiate.
+ }
+}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusServlet.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusServlet.java
index 43bac8791b4..9b8f9833f0b 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusServlet.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/http/RSStatusServlet.java
@@ -18,43 +18,20 @@
package org.apache.hadoop.hbase.regionserver.http;
import java.io.IOException;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.tmpl.regionserver.RSStatusTmpl;
import org.apache.yetus.audience.InterfaceAudience;
+/**
+ * Only kept for redirecting to regionserver.jsp.
+ */
@InterfaceAudience.Private
public class RSStatusServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- HRegionServer hrs =
- (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
- assert hrs != null : "No RS in context!";
-
- String format = req.getParameter("format");
- if ("json".equals(format)) {
- resp.setContentType("application/json");
- } else {
- resp.setContentType("text/html");
- }
-
- if (!hrs.isOnline()) {
- resp.getWriter().write("The RegionServer is initializing!");
- resp.getWriter().close();
- return;
- }
-
- RSStatusTmpl tmpl = new RSStatusTmpl();
- if (format != null) tmpl.setFormat(format);
- if (req.getParameter("filter") != null) tmpl.setFilter(req.getParameter("filter"));
- if (req.getParameter("bcn") != null) tmpl.setBcn(req.getParameter("bcn"));
- if (req.getParameter("bcv") != null) tmpl.setBcv(req.getParameter("bcv"));
- tmpl.render(resp.getWriter(), hrs);
+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ response.sendRedirect(request.getContextPath() + "/regionserver.jsp");
}
}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ZKStringFormatter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ZKStringFormatter.java
new file mode 100644
index 00000000000..a83f07014b0
--- /dev/null
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/ZKStringFormatter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Utility used by both Master and Region Server web UI JSP pages.
+ */
+@InterfaceAudience.Private
+public final class ZKStringFormatter {
+
+ private ZKStringFormatter() {
+ // Do not instantiate.
+ }
+
+ public static String formatZKString(ZKWatcher zookeeper) {
+ StringBuilder quorums = new StringBuilder();
+ String zkQuorum = zookeeper.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();
+ }
+}
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/taskMonitor.jsp b/hbase-server/src/main/resources/hbase-webapps/common/taskMonitor.jsp
similarity index 100%
rename from hbase-server/src/main/resources/hbase-webapps/master/taskMonitor.jsp
rename to hbase-server/src/main/resources/hbase-webapps/common/taskMonitor.jsp
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/taskMonitorRenderTasks.jsp b/hbase-server/src/main/resources/hbase-webapps/common/taskMonitorRenderTasks.jsp
similarity index 100%
rename from hbase-server/src/main/resources/hbase-webapps/master/taskMonitorRenderTasks.jsp
rename to hbase-server/src/main/resources/hbase-webapps/common/taskMonitorRenderTasks.jsp
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/hbck.jsp b/hbase-server/src/main/resources/hbase-webapps/master/hbck.jsp
index a6c6c2d17e6..210438ba7fe 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/hbck.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/hbck.jsp
@@ -383,7 +383,7 @@ private static String formatServerName(HMaster master,
int infoPort = master.getRegionServerInfoPort(serverName);
if (infoPort > 0) {
return "<a href=" + "//" + serverName.getHostname() + ":" +
- infoPort + "/rs-status>" + sn + "</a>";
+ infoPort + "/regionserver.jsp>" + sn + "</a>";
} else {
return "<b>" + sn + "</b>";
}
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 7e537123851..76dbd656e9d 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/master.jsp
@@ -32,6 +32,7 @@
if (format != null && format.equals("json")) {
request.setAttribute(MasterStatusConstants.FILTER, filter);
request.setAttribute(MasterStatusConstants.FORMAT, "json");
+ response.setContentType("application/json");
%>
<jsp:include page="taskMonitor.jsp"/>
<%
@@ -143,6 +144,7 @@
<% } %>
<section>
+ <% request.setAttribute(MasterStatusConstants.PARENT, "/master.jsp"); %>
<jsp:include page="taskMonitor.jsp"/>
</section>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/rsgroup.jsp b/hbase-server/src/main/resources/hbase-webapps/master/rsgroup.jsp
index c86c9902ea1..91734e8d0a3 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/rsgroup.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/rsgroup.jsp
@@ -38,10 +38,11 @@
import="org.apache.hadoop.hbase.rsgroup.RSGroupUtil"
import="org.apache.hadoop.hbase.util.Bytes"
import="org.apache.hadoop.hbase.util.VersionInfo"
- import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"%>
-<%@ page import="org.apache.hadoop.hbase.ServerMetrics" %>
-<%@ page import="org.apache.hadoop.hbase.Size" %>
-<%@ page import="org.apache.hadoop.hbase.RegionMetrics" %>
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.ServerMetrics"
+ import="org.apache.hadoop.hbase.Size"
+ import="org.apache.hadoop.hbase.RegionMetrics"
+ import="static org.apache.hadoop.hbase.master.http.MasterStatusUtil.serverNameLink" %>
<%
String rsGroupName = request.getParameter("name");
pageContext.setAttribute("pageTitle", "RSGroup: " + rsGroupName);
@@ -167,11 +168,9 @@
totalRequestsPerSecond += sl.getRequestCountPerSecond();
lastContact = (System.currentTimeMillis() - sl.getReportTimestamp())/1000;
}
- long startcode = serverName.getStartCode();
- int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";%>
+ long startcode = serverName.getStartCode(); %>
<tr>
- <td><a href="<%= url %>"><%= serverName.getServerName() %></a></td>
+ <td><%= serverNameLink(master, serverName) %></td>
<td><%= new Date(startcode) %></td>
<td><%= lastContact %></td>
<td><%= version %></td>
@@ -223,8 +222,6 @@
double memStoreSizeMB = sl.getRegionMetrics().values()
.stream().mapToDouble(rm -> rm.getMemStoreSize().get(Size.Unit.MEGABYTE))
.sum();
- int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
if (memStoreSizeMB > 0) {
memStoreSizeMBStr = TraditionalBinaryPrefix.long2String(
@@ -240,7 +237,7 @@
}
%>
<tr>
- <td><a href="<%= url %>"><%= serverName.getServerName() %></a></td>
+ <td><%= serverNameLink(master, serverName) %></td>
<td><%= usedHeapSizeMBStr %></td>
<td><%= maxHeapSizeMBStr %></td>
<td><%= memStoreSizeMBStr %></td>
@@ -268,17 +265,15 @@
ServerName serverName = serverMaping.get(server);
ServerMetrics sl = onlineServers.get(server);
if (sl != null && serverName != null) {
- int infoPort = master.getRegionServerInfoPort(serverName);
long readRequestCount = 0;
long writeRequestCount = 0;
for (RegionMetrics rm : sl.getRegionMetrics().values()) {
readRequestCount += rm.getReadRequestCount();
writeRequestCount += rm.getWriteRequestCount();
}
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
%>
<tr>
- <td><a href="<%= url %>"><%= serverName.getServerName() %></a></td>
+ <td><%= serverNameLink(master, serverName) %></td>
<td><%= sl.getRequestCountPerSecond() %></td>
<td><%= readRequestCount %></td>
<td><%= writeRequestCount %></td>
@@ -328,8 +323,6 @@
totalStaticIndexSizeKB += rm.getStoreFileUncompressedDataIndexSize().get(Size.Unit.KILOBYTE);
totalStaticBloomSizeKB += rm.getBloomFilterSize().get(Size.Unit.KILOBYTE);
}
- int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
if (storeUncompressedSizeMB > 0) {
storeUncompressedSizeMBStr = TraditionalBinaryPrefix.long2String(
(long) storeUncompressedSizeMB * TraditionalBinaryPrefix.MEGA.value, "B", 1);
@@ -348,7 +341,7 @@
}
%>
<tr>
- <td><a href="<%= url %>"><%= serverName.getServerName() %></a></td>
+ <td><%= serverNameLink(master, serverName) %></td>
<td><%= storeCount %></td>
<td><%= storeFileCount %></td>
<td><%= storeUncompressedSizeMBStr %></td>
@@ -394,11 +387,9 @@
percentDone = String.format("%.2f", 100 *
((float) currentCompactedCells / totalCompactingCells)) + "%";
}
- int infoPort = master.getRegionServerInfoPort(serverName);
- String url = "//" + serverName.getHostname() + ":" + infoPort + "/rs-status";
%>
<tr>
- <td><a href="<%= url %>"><%= serverName.getServerName() %></a></td>
+ <td><%= serverNameLink(master, serverName) %></td>
<td><%= totalCompactingCells %></td>
<td><%= currentCompactedCells %></td>
<td><%= totalCompactingCells - currentCompactedCells %></td>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp b/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp
index 725a116790c..3feb1e1323f 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/softwareAttributes.jsp
@@ -23,34 +23,8 @@
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();
- }
-%>
+ import="org.apache.hadoop.hbase.master.http.MasterStatusConstants"
+ import="org.apache.hadoop.hbase.util.ZKStringFormatter" %>
<%
HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER);
@@ -111,7 +85,7 @@
</tr>
<tr>
<td>ZooKeeper Quorum</td>
- <td> <%= formatZKString(master) %> </td>
+ <td> <%= ZKStringFormatter.formatZKString(master.getZooKeeper()) %> </td>
<td>Addresses of all registered ZK servers. For more, see <a href="/zk.jsp">zk dump</a>.</td>
</tr>
<tr>
@@ -121,7 +95,7 @@
</tr>
<tr>
<td>Cluster Key</td>
- <td> <%= formatZKString(master) %>:<%= master.getZooKeeper().getZNodePaths().baseZNode %></td>
+ <td> <%= ZKStringFormatter.formatZKString(master.getZooKeeper()) %>:<%= 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>
diff --git a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp
index 9a6aec049a7..d88d968e199 100644
--- a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp
@@ -124,7 +124,7 @@
String hostNameEncoded = URLEncoder.encode(hostName, StandardCharsets.UTF_8);
// This port might be wrong if RS actually ended up using something else.
int serverInfoPort = master.getRegionServerInfoPort(serverName);
- String urlRegionServer = "//" + hostNameEncoded + ":" + serverInfoPort + "/rs-status";
+ String urlRegionServer = "//" + hostNameEncoded + ":" + serverInfoPort + "/regionserver.jsp";
return "<td><a href=\"" + urlRegionServer + "\">" + StringEscapeUtils.escapeHtml4(hostName)
+ ":" + serverInfoPort + "</a></td>";
@@ -398,7 +398,7 @@
%>
<tr>
<td><%= escapeXml(meta.getRegionNameAsString()) %></td>
- <td><a href="http://<%= hostAndPort %>/rs-status"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
+ <td><a href="http://<%= hostAndPort %>/regionserver.jsp"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
<td><%= readReq%></td>
<td><%= writeReq%></td>
<td><%= fileSizeUncompressed%></td>
@@ -455,7 +455,7 @@
%>
<tr>
<td><%= escapeXml(meta.getRegionNameAsString()) %></td>
- <td><a href="http://<%= hostAndPort %>/rs-status"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
+ <td><a href="http://<%= hostAndPort %>/regionserver.jsp"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
<td><%= locality%></td>
<td><%= localityForSsd%></td>
</tr>
@@ -512,7 +512,7 @@
%>
<tr>
<td><%= escapeXml(meta.getRegionNameAsString()) %></td>
- <td><a href="http://<%= hostAndPort %>/rs-status"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
+ <td><a href="http://<%= hostAndPort %>/regionserver.jsp"><%= StringEscapeUtils.escapeHtml4(hostAndPort) %></a></td>
<td><%= String.format("%,1d", compactingCells)%></td>
<td><%= String.format("%,1d", compactedCells)%></td>
<td><%= String.format("%,1d", compactingCells - compactedCells)%></td>
@@ -1174,7 +1174,7 @@
for (Map.Entry<ServerName, Integer> rdEntry : regDistribution.entrySet()) {
ServerName addr = rdEntry.getKey();
String url = "//" + URLEncoder.encode(addr.getHostname(), StandardCharsets.UTF_8) + ":"
- + master.getRegionServerInfoPort(addr) + "/rs-status";
+ + master.getRegionServerInfoPort(addr) + "/regionserver.jsp";
%>
<tr>
<td><a href="<%= url %>"><%= StringEscapeUtils.escapeHtml4(addr.getHostname())
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCache.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCache.jsp
new file mode 100644
index 00000000000..7bba000a271
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCache.jsp
@@ -0,0 +1,72 @@
+<%--
+/**
+ * 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.io.hfile.BlockCache"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer" %>
+<%@ page import="org.apache.hadoop.hbase.io.hfile.CacheConfig" %>
+
+<%-- Template for rendering Block Cache tabs in RegionServer Status page. --%>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ CacheConfig cacheConfig = new CacheConfig(regionServer.getConfiguration());
+
+ BlockCache bc = regionServer.getBlockCache().orElse(null);
+
+ BlockCache[] bcs = bc == null ? null : bc.getBlockCaches();
+ BlockCache l1 = bcs == null ? bc : bcs[0];
+ BlockCache l2 = bcs == null ? null : bcs.length <= 1 ? null : bcs[1];
+%>
+
+<div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item"><a class="nav-link active" href="#tab_bc_baseInfo" data-bs-toggle="tab" role="tab">Base Info</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_bc_config" data-bs-toggle="tab" role="tab">Config</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_bc_stats" data-bs-toggle="tab" role="tab">Stats</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_bc_l1" data-bs-toggle="tab" role="tab">L1</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_bc_l2" data-bs-toggle="tab" role="tab">L2</a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="tab_bc_baseInfo" role="tabpanel">
+ <% request.setAttribute("bc", bc); %>
+ <jsp:include page="blockCacheBaseInfo.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_bc_config" role="tabpanel">
+ <% request.setAttribute("cacheConfig", cacheConfig); %>
+ <jsp:include page="blockCacheConfig.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_bc_stats" role="tabpanel">
+ <% request.setAttribute("bc", bc); %>
+ <jsp:include page="blockCacheStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_bc_l1" role="tabpanel">
+ <% request.setAttribute("bc", l1); %>
+ <% request.setAttribute("name", "L1"); %>
+ <jsp:include page="blockCacheLevel.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_bc_l2" role="tabpanel">
+ <% request.setAttribute("bc", l2); %>
+ <% request.setAttribute("name", "L2"); %>
+ <jsp:include page="blockCacheLevel.jsp"/>
+ </div>
+ </div>
+</div>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheBaseInfo.jsp
similarity index 51%
copy from hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp
copy to hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheBaseInfo.jsp
index ee63075d5d6..d7d322d4754 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheBaseInfo.jsp
@@ -17,4 +17,26 @@
* limitations under the License.
*/
--%>
-<meta HTTP-EQUIV="REFRESH" content="0;url=/rs-status"/>
+<%@ page contentType="text/html;charset=UTF-8"
+ import="org.apache.hadoop.hbase.io.hfile.BlockCache" %>
+
+<%
+ BlockCache bc = (BlockCache) request.getAttribute("bc");
+
+ String bcUrl = bc == null ? null : "http://hbase.apache.org/devapidocs/" + bc.getClass().getName().replaceAll("\\.", "/") + ".html";
+ String bcName = bc == null ? null : bc.getClass().getSimpleName();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Implementation</td>
+ <td><a href="<%= bcUrl %>"><%= bcName %></a></td>
+ <td>Block cache implementing class</td>
+ </tr>
+</table>
+<p>See <a href="http://hbase.apache.org/book.html#block.cache">block cache</a> in the HBase Reference Guide for help.</p>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheConfig.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheConfig.jsp
new file mode 100644
index 00000000000..d73652de4cb
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheConfig.jsp
@@ -0,0 +1,72 @@
+<%--
+/**
+ * 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.io.hfile.CacheConfig" %>
+
+<%
+ CacheConfig cacheConfig = (CacheConfig) request.getAttribute("cacheConfig");
+if (cacheConfig == null) { %>
+ <p>CacheConfig is null</p>
+<% } else { %>
+<table class="table table-striped">
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Cache DATA on Read</td>
+ <td><%= cacheConfig.shouldCacheDataOnRead() %></td>
+ <td>True if DATA blocks are cached on read
+ (INDEX & BLOOM blocks are always cached)</td>
+ </tr>
+ <tr>
+ <td>Cache DATA on Write</td>
+ <td><%= cacheConfig.shouldCacheDataOnWrite() %></td>
+ <td>True if DATA blocks are cached on write.</td>
+ </tr>
+ <tr>
+ <td>Cache INDEX on Write</td>
+ <td><%= cacheConfig.shouldCacheIndexesOnWrite() %></td>
+ <td>True if INDEX blocks are cached on write</td>
+ </tr>
+ <tr>
+ <td>Cache BLOOM on Write</td>
+ <td><%= cacheConfig.shouldCacheBloomsOnWrite() %></td>
+ <td>True if BLOOM blocks are cached on write</td>
+ </tr>
+ <tr>
+ <td>Evict blocks on Close</td>
+ <td><%= cacheConfig.shouldEvictOnClose() %></td>
+ <td>True if blocks are evicted from cache when an HFile
+ reader is closed</td>
+ </tr>
+ <tr>
+ <td>Cache DATA in compressed format</td>
+ <td><%= cacheConfig.shouldCacheDataCompressed() %></td>
+ <td>True if DATA blocks are cached in their compressed form</td>
+ </tr>
+ <tr>
+ <td>Prefetch on Open</td>
+ <td><%= cacheConfig.shouldPrefetchOnOpen() %></td>
+ <td>True if blocks are prefetched into cache on open</td>
+ </tr>
+</table>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheEvictions.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheEvictions.jsp
new file mode 100644
index 00000000000..58870ca0072
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheEvictions.jsp
@@ -0,0 +1,45 @@
+<%--
+/**
+ * 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.io.hfile.BlockCache"
+ import="org.apache.hadoop.hbase.io.hfile.AgeSnapshot" %>
+
+<%
+ BlockCache bc = (BlockCache) request.getAttribute("bc");
+
+ AgeSnapshot ageAtEvictionSnapshot = bc.getStats().getAgeAtEvictionSnapshot();
+ // Only show if non-zero mean and stddev as is the case in combinedblockcache
+%>
+
+<tr>
+ <td>Evicted</td>
+ <td><%= String.format("%,d", bc.getStats().getEvictedCount()) %></td>
+ <td>The total number of blocks evicted</td>
+</tr>
+<tr>
+ <td>Evictions</td>
+ <td><%= String.format("%,d", bc.getStats().getEvictionCount()) %></td>
+ <td>The total number of times an eviction has occurred</td>
+</tr>
+<tr>
+ <td>Mean</td>
+ <td><%= String.format("%,d", (long)ageAtEvictionSnapshot.getMean()) %></td>
+ <td>Mean age of Blocks at eviction time (seconds)</td>
+</tr>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheHits.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheHits.jsp
new file mode 100644
index 00000000000..df9da58592c
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheHits.jsp
@@ -0,0 +1,92 @@
+<%--
+/**
+ * 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.io.hfile.BlockCache" %>
+
+<%
+ BlockCache bc = (BlockCache) request.getAttribute("bc");
+
+ int hitPeriods = 0;
+ for (int i = 0; i < bc.getStats().getNumPeriodsInWindow(); i++) {
+ if (bc.getStats().getWindowPeriods()[i] != null) {
+ hitPeriods++;
+ }
+ }
+%>
+
+<% if (hitPeriods > 0) { %>
+<script src="/static/js/blockCacheInit.js" type="text/javascript"></script>
+<% } %>
+<tr>
+ <td>Hits</td>
+ <td><%= String.format("%,d", bc.getStats().getHitCount()) %></td>
+ <td>Number requests that were cache hits</td>
+</tr>
+<tr>
+ <td>Hits Caching</td>
+ <td><%= String.format("%,d", bc.getStats().getHitCachingCount()) %></td>
+ <td>Cache hit block requests but only requests set to cache block if a miss</td>
+</tr>
+<tr>
+ <td>Misses</td>
+ <td><%= String.format("%,d", bc.getStats().getMissCount()) %></td>
+ <td>Block requests that were cache misses but set to cache missed blocks</td>
+</tr>
+<tr>
+ <td>Misses Caching</td>
+ <td><%= String.format("%,d", bc.getStats().getMissCachingCount()) %></td>
+ <td>Block requests that were cache misses but only requests set to use block cache</td>
+</tr>
+<tr>
+ <td>All Time Hit Ratio</td>
+ <td><%= String.format("%,.2f", bc.getStats().getHitRatio() * 100) %><%= "%" %></td>
+ <td>Hit Count divided by total requests count</td>
+</tr>
+<% for (int i = 0; i < hitPeriods; i++) { %>
+<%-- These rows are hidden on page load, blockCacheInit.js will display these as paginated. --%>
+<tr id="row-<%= i %>" class="item-row" style="display: none;">
+ <td>Hit Ratio for period starting at <%= bc.getStats().getWindowPeriods()[i] %></td>
+ <% if (bc.getStats().getRequestCounts()[i] > 0) { %>
+ <td><%= String.format("%,.2f", ((double)bc.getStats().getHitCounts()[i] / (double)bc.getStats().getRequestCounts()[i]) * 100.0) %><%= "%" %></td>
+ <% } else { %>
+ <td>No requests</td>
+ <% } %>
+ <td>Hit Count divided by total requests count over the <%= i %>th period of <%= bc.getStats().getPeriodTimeInMinutes() %> minutes</td>
+</tr>
+<% } %>
+<% if (hitPeriods > 0) { %>
+ <tr class="pagination-row">
+ <td colspan="3">
+ <div class="pagination-container">
+ <button id="prev-page" onclick="prevPage()">Previous</button>
+ <span id="page-buttons" class="page-numbers"></span>
+ <button id="next-page" onclick="nextPage()">Next</button>
+ <span id="page-info" class="page-info"></span>
+ </div>
+ </td>
+ </tr>
+<% } %>
+<% if (bc.getStats().getPeriodTimeInMinutes() > 0) { %>
+ <tr>
+ <td>Last <%= bc.getStats().getNumPeriodsInWindow()*bc.getStats().getPeriodTimeInMinutes() %> minutes Hit Ratio</td>
+ <td><%= String.format("%,.2f", bc.getStats().getHitRatioPastNPeriods() * 100.0) %><%= "%" %></td>
+ <td>Hit Count divided by total requests count for the last <%= bc.getStats().getNumPeriodsInWindow()*bc.getStats().getPeriodTimeInMinutes() %> minutes</td>
+ </tr>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheLevel.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheLevel.jsp
new file mode 100644
index 00000000000..47cc6a5a985
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheLevel.jsp
@@ -0,0 +1,159 @@
+<%--
+/**
+ * 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.conf.Configuration"
+ import="org.apache.hadoop.hbase.io.hfile.BlockCache"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.io.hfile.BlockCacheUtil"
+ import="org.apache.hadoop.hbase.io.hfile.LruBlockCache"
+ import="org.apache.hadoop.hbase.io.hfile.bucket.BucketCacheStats"
+ import="org.apache.hadoop.hbase.io.hfile.bucket.BucketCache"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ Configuration configuration = regionServer.getConfiguration();
+
+ BlockCache bc = (BlockCache) request.getAttribute("bc");
+
+ String name = (String) request.getAttribute("name");
+%>
+
+<% if (bc == null) { %>
+ <p>No <%= name %> deployed</p>
+<% } else { %>
+
+<%
+ String bcUrl = "http://hbase.apache.org/devapidocs/" + bc.getClass().getName().replaceAll("\\.", "/") + ".html";
+ String bcName = bc.getClass().getSimpleName();
+ int maxCachedBlocksByFile = BlockCacheUtil.getMaxCachedBlocksByFile(configuration);
+
+ boolean isLru = bc instanceof LruBlockCache;
+
+ boolean isBucketCache = bc.getClass().getSimpleName().equals("BucketCache");
+ BucketCacheStats bucketCacheStats = null;
+ BucketCache bucketCache = null;
+ if (bc instanceof BucketCache) {
+ bucketCache = (BucketCache) bc;
+ bucketCacheStats = (BucketCacheStats) bc.getStats();
+ }
+%>
+
+<table id="blocks_summary" class="table table-striped">
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Implementation</td>
+ <td><a href="<%= bcUrl %>"><%= bcName %></a></td>
+ <td>Class implementing this block cache Level</td>
+ </tr>
+<% if (isBucketCache) { %>
+ <tr>
+ <td>IOEngine</td>
+ <td><%= bucketCache.getIoEngine() %></td>
+ <td>Supported IOEngine types: offheap, file, files, mmap or pmem. See <a href="https://hbase.apache.org/book.html#hbase.bucketcache.ioengine">hbase.bucketcache.ioengine</a>.</td>
+ </tr>
+<% } %>
+ <tr>
+ <td>Cache Size Limit</td>
+ <td><%= TraditionalBinaryPrefix.long2String(bc.getMaxSize(), "B", 1) %></td>
+ <td>Max size of cache</td>
+ </tr>
+ <tr>
+ <td>Block Count</td>
+ <td><%= String.format("%,d", bc.getBlockCount()) %></td>
+ <td>Count of Blocks</td>
+ </tr>
+<% if (!isBucketCache) { %>
+ <tr>
+ <td>Data Block Count</td>
+ <td><%= String.format("%,d", bc.getDataBlockCount()) %></td>
+ <td>Count of DATA Blocks</td>
+ </tr>
+<% } %>
+<% if (isLru) { %>
+ <tr>
+ <td>Index Block Count</td>
+ <td><%= String.format("%,d", ((LruBlockCache)bc).getIndexBlockCount()) %></td>
+ <td>Count of INDEX Blocks</td>
+ </tr>
+ <tr>
+ <td>Bloom Block Count</td>
+ <td><%= String.format("%,d", ((LruBlockCache)bc).getBloomBlockCount()) %></td>
+ <td>Count of BLOOM Blocks</td>
+ </tr>
+<% } %>
+ <tr>
+ <td>Size of Blocks</td>
+ <td><%= TraditionalBinaryPrefix.long2String(bc.getCurrentSize(), "B", 1) %></td>
+ <td>Size of Blocks</td>
+ </tr>
+<% if (!isBucketCache) { %>
+ <tr>
+ <td>Size of Data Blocks</td>
+ <td><%= TraditionalBinaryPrefix.long2String(bc.getCurrentDataSize(), "B", 1) %></td>
+ <td>Size of DATA Blocks</td>
+ </tr>
+<% } %>
+<% if (isLru) { %>
+ <tr>
+ <td>Size of Index Blocks</td>
+ <td><%= TraditionalBinaryPrefix.long2String(((LruBlockCache)bc).getCurrentIndexSize(), "B", 1) %></td>
+ <td>Size of INDEX Blocks</td>
+ </tr>
+ <tr>
+ <td>Size of Bloom Blocks</td>
+ <td><%= TraditionalBinaryPrefix.long2String(((LruBlockCache)bc).getCurrentBloomSize(), "B", 1) %></td>
+ <td>Size of BLOOM Blocks</td>
+ </tr>
+<% } %>
+ <% request.setAttribute("bc", bc); %>
+ <jsp:include page="blockCacheEvictions.jsp"/>
+ <jsp:include page="blockCacheHits.jsp"/>
+
+<% if (isBucketCache) { %>
+ <tr>
+ <td>Hits per Second</td>
+ <td><%= bucketCacheStats.getIOHitsPerSecond() %></td>
+ <td>Block gets against this cache per second</td>
+ </tr>
+ <tr>
+ <td>Time per Hit</td>
+ <td><%= bucketCacheStats.getIOTimePerHit() %></td>
+ <td>Time per cache hit</td>
+ </tr>
+<% } %>
+</table>
+
+<%-- Call through to block cache Detail rendering template --%>
+<p>
+ View block cache <a href="?format=json&bcn=<%= name %>">as JSON</a> | Block cache <a href="?format=json&bcn=<%= name %>&bcv=file">as JSON by file</a>
+ <% if (bc.getBlockCount() > maxCachedBlocksByFile) { %>
+ <br>
+ <b>Note</b>: JSON view of block cache will be incomplete, because block count <%= bc.getBlockCount() %> is greater than <i>hbase.ui.blockcache.by.file.max</i> value of <%= maxCachedBlocksByFile %>.
+ Increase that value to get a complete picture.
+ <% } %>
+</p>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheStats.jsp
new file mode 100644
index 00000000000..c30160b7621
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheStats.jsp
@@ -0,0 +1,58 @@
+<%--
+/**
+ * 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.io.hfile.BlockCache"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" %>
+
+<%
+ BlockCache bc = (BlockCache) request.getAttribute("bc");
+if (bc == null) { %>
+ <p>BlockCache is null</p>
+<% } else { %>
+<table class="table table-striped">
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>Size</td>
+ <td><%= TraditionalBinaryPrefix.long2String(bc.getCurrentSize(),
+ "B", 1) %></td>
+ <td>Current size of block cache in use</td>
+ </tr>
+ <tr>
+ <td>Free</td>
+ <td><%= TraditionalBinaryPrefix.long2String(bc.getFreeSize(),
+ "B", 1) %></td>
+ <td>The total free memory currently available to store more cache entries</td>
+ </tr>
+ <tr>
+ <td>Count</td>
+ <td><%= String.format("%,d", bc.getBlockCount()) %></td>
+ <td>Number of blocks in block cache</td>
+ </tr>
+ <% request.setAttribute("bc", bc); %>
+ <jsp:include page="blockCacheEvictions.jsp"/>
+ <jsp:include page="blockCacheHits.jsp"/>
+</table>
+<p>If block cache is made up of more than one cache -- i.e. a L1 and a L2 -- then the above
+ are combined counts. Request count is sum of hits and misses.</p>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheView.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheView.jsp
new file mode 100644
index 00000000000..be6061bc652
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/blockCacheView.jsp
@@ -0,0 +1,62 @@
+<%--
+/**
+ * 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.io.hfile.BlockCache"
+ import="org.apache.hadoop.conf.Configuration"
+ import="org.apache.hadoop.hbase.io.hfile.BlockCacheUtil"
+ import="org.apache.hadoop.hbase.io.hfile.CachedBlock"
+ import="org.apache.hadoop.hbase.regionserver.http.RSStatusConstants" %><%
+ // This template is used to give views on an individual block cache as JSON.
+
+ Configuration conf = (Configuration) request.getAttribute("conf");
+ String bcn = (String) request.getAttribute(RSStatusConstants.BLOCK_CACHE_NAME);
+ String bcv = (String) request.getAttribute(RSStatusConstants.BLOCK_CACHE_V);
+ BlockCache bc = (BlockCache) request.getAttribute("blockCache");
+
+ BlockCache [] bcs = bc == null ? null : bc.getBlockCaches();
+ if (bcn.equals(RSStatusConstants.BLOCK_CACHE_NAME_L1)) {
+ bc = bcs == null || bcs.length == 0? bc: bcs[0];
+ } else {
+ if (bcs == null || bcs.length < 2) {
+ System.out.println("There is no L2 block cache");
+ return;
+ }
+ bc = bcs[1];
+ }
+ if (bc == null) {
+ System.out.println("There is no block cache");
+ return;
+ }
+ BlockCacheUtil.CachedBlocksByFile cbsbf = BlockCacheUtil.getLoadedCachedBlocksByFile(conf, bc);
+ if (bcv.equals(RSStatusConstants.BLOCK_CACHE_V_FILE)) {
+ boolean firstEntry = true; %>
+ [<% for (Map.Entry<String, NavigableSet<CachedBlock>> e: cbsbf.getCachedBlockStatsByFile().entrySet()) { %>
+ <% if (!firstEntry) { %>,<% } %><%= BlockCacheUtil.toJSON(e.getKey(), e.getValue()) %>
+ <%
+ if (firstEntry) {
+ firstEntry = false;
+ }
+ %>
+ <% } %>]
+
+<% } else { %>
+[ <%= BlockCacheUtil.toJSON(bc) %>, <%= BlockCacheUtil.toJSON(cbsbf) %> ]
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp
index 02a36e9c23f..4b2d6cb2f5e 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp
@@ -17,14 +17,6 @@
* limitations under the License.
*/
--%>
- <script src="/static/js/jquery.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 type="text/javascript">
- $(document).ready(function() {
- $('nav.navbar li.active').removeClass('active');
- $('a[href="' + location.pathname + '"]').addClass('active');
- });
- </script>
+ <jsp:include page="scripts.jsp"/>
</body>
</html>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/header.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/header.jsp
index 14d22363c51..47e46017b74 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/header.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/header.jsp
@@ -37,7 +37,7 @@
<body>
<nav class="navbar navbar-expand-md navbar-light fixed-top bg-light">
<div class="container-fluid">
- <a class="navbar-brand" href="/rs-status">
+ <a class="navbar-brand" href="/regionserver.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">
@@ -45,7 +45,7 @@
</button>
<div class="collapse navbar-collapse">
<ul class="navbar-nav">
- <li class="nav-item"><a class="nav-link" href="/rs-status">Home</a></li>
+ <li class="nav-item"><a class="nav-link" href="/regionserver.jsp">Home</a></li>
<li class="nav-item"><a class="nav-link" href="/processRS.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="/rsOperationDetails.jsp">Operation Details</a></li>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/index.html b/hbase-server/src/main/resources/hbase-webapps/regionserver/index.html
index 47fc1b9b30b..ce57b77f1fb 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/index.html
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/index.html
@@ -17,4 +17,4 @@
* limitations under the License.
*/
-->
-<meta HTTP-EQUIV="REFRESH" content="0;url=/rs-status"/>
+<meta HTTP-EQUIV="REFRESH" content="0;url=/regionserver.jsp"/>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionList.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionList.jsp
new file mode 100644
index 00000000000..4dc03adb1d0
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionList.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="java.util.*"
+ import="org.apache.hadoop.hbase.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+
+ if (onlineRegions != null && onlineRegions.size() > 0) {
+
+ Collections.sort(onlineRegions, RegionInfo.COMPARATOR);
+%>
+<div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item"><a class="nav-link active" href="#tab_regionBaseInfo" data-bs-toggle="tab" role="tab">Base Info</a> </li>
+ <li class="nav-item"><a class="nav-link" href="#tab_regionRequestStats" data-bs-toggle="tab" role="tab">Request metrics</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_regionStoreStats" data-bs-toggle="tab" role="tab">Storefile Metrics</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_regionMemstoreStats" data-bs-toggle="tab" role="tab">Memstore Metrics</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_regionCompactStats" data-bs-toggle="tab" role="tab">Compaction Metrics</a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="tab_regionBaseInfo" role="tabpanel">
+ <jsp:include page="regionListBaseInfo.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_regionRequestStats" role="tabpanel">
+ <jsp:include page="regionListRequestStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_regionStoreStats" role="tabpanel">
+ <jsp:include page="regionListStoreStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_regionMemstoreStats" role="tabpanel">
+ <jsp:include page="regionListMemstoreStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_regionCompactStats" role="tabpanel">
+ <jsp:include page="regionListCompactStats.jsp"/>
+ </div>
+ </div>
+</div>
+<p>Region names are made of the containing table's name, a comma,
+ the start key, a comma, and a randomly generated region id. To illustrate,
+ the region named
+ <em>domains,apache.org,5464829424211263407</em> is party to the table
+ <em>domains</em>, has an id of <em>5464829424211263407</em> and the first key
+ in the region is <em>apache.org</em>. The <em>hbase:meta</em> 'table' is an internal
+ system table (or a 'catalog' table in db-speak).
+ The hbase:meta table keeps a list of all regions in the system. The empty key is used to denote
+ table start and table end. A region with an empty start key is the first region in a table.
+ If a region has both an empty start key and an empty end key, it's the only region in the
+ table. See <a href="http://hbase.apache.org">HBase Home</a> for further explication.<p>
+<% } else { %>
+ <p>Not serving regions</p>
+<% } %>
+
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListBaseInfo.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListBaseInfo.jsp
new file mode 100644
index 00000000000..a70819d8e9a
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListBaseInfo.jsp
@@ -0,0 +1,58 @@
+<%--
+/**
+ * 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.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay"
+ import="org.apache.hadoop.hbase.util.Bytes" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+%>
+<table id="baseStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>Region Name</th>
+ <th class="cls_emptyMin">Start Key</th>
+ <th class="cls_emptyMax">End Key</th>
+ <th>ReplicaID</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% for (RegionInfo r: onlineRegions) { %>
+ <tr>
+ <%
+ String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
+ regionServer.getConfiguration());
+ %>
+ <td><a href="region.jsp?name=<%= r.getEncodedName() %>"><%= displayName %></a></td>
+ <td><%= Bytes.toStringBinary(RegionInfoDisplay.getStartKeyForDisplay(r,
+ regionServer.getConfiguration())) %></td>
+ <td><%= Bytes.toStringBinary(RegionInfoDisplay.getEndKeyForDisplay(r,
+ regionServer.getConfiguration())) %></td>
+ <td><%= r.getReplicaId() %></td>
+ </tr>
+ <% } %>
+ </tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListCompactStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListCompactStats.jsp
new file mode 100644
index 00000000000..07cf41e8334
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListCompactStats.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="java.util.*"
+ import="org.apache.hadoop.hbase.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos.RegionLoad"
+ import="org.apache.commons.lang3.time.FastDateFormat"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+
+%>
+<table id="compactionStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>Region Name</th>
+ <th class="cls_separator">Num. Compacting Cells</th>
+ <th class="cls_separator">Num. Compacted Cells</th>
+ <th>Compaction Progress</th>
+ <th data-date-format="yyyymmdd hhmm zz">Last Major Compaction</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% for (RegionInfo r: onlineRegions) { %>
+ <tr>
+
+ <%
+ RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
+ String percentDone = "";
+ String compactTime = "";
+ if (load != null) {
+ if (load.getTotalCompactingKVs() > 0) {
+ percentDone = String.format("%.2f", 100 *
+ ((float) load.getCurrentCompactedKVs() / load.getTotalCompactingKVs())) + "%";
+ }
+ if (load.getLastMajorCompactionTs() > 0) {
+ FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm (ZZ)");
+ compactTime = fdf.format(load.getLastMajorCompactionTs());
+ }
+ }
+ String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
+ regionServer.getConfiguration());
+ %>
+ <td><a href="region.jsp?name=<%= r.getEncodedName() %>"><%= displayName %></a></td>
+ <% if (load != null) { %>
+ <td><%= String.format("%,1d", load.getTotalCompactingKVs()) %></td>
+ <td><%= String.format("%,1d", load.getCurrentCompactedKVs()) %></td>
+ <td><%= percentDone %></td>
+ <td><%= compactTime %></td>
+ <% } %>
+
+ </tr>
+
+ <% } %>
+ </tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListMemstoreStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListMemstoreStats.jsp
new file mode 100644
index 00000000000..b81e42ce6dd
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListMemstoreStats.jsp
@@ -0,0 +1,70 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay" %>
+<%@ page import="org.apache.hadoop.util.StringUtils" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+
+%>
+<table id="memstoreStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>Region Name</th>
+ <th class="cls_filesize">Memstore Size</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% for (RegionInfo r: onlineRegions) { %>
+ <tr>
+
+ <%
+ final String ZEROMB = "0 MB";
+ String memStoreSizeMBStr = ZEROMB;
+ ClusterStatusProtos.RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
+ String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
+ regionServer.getConfiguration());
+ if (load != null) {
+ long memStoreSizeMB = load.getMemStoreSizeMB();
+ if (memStoreSizeMB > 0) {
+ memStoreSizeMBStr = StringUtils.TraditionalBinaryPrefix.long2String(
+ memStoreSizeMB * StringUtils.TraditionalBinaryPrefix.MEGA.value, "B", 1);
+ }
+ }
+ %>
+
+ <td><a href="region.jsp?name=<%= r.getEncodedName() %>"><%= displayName %></a></td>
+ <% if (load != null) { %>
+ <td><%= memStoreSizeMBStr %></td>
+ <% } %>
+
+ </tr>
+ <% } %>
+ </tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListRequestStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListRequestStats.jsp
new file mode 100644
index 00000000000..2d0ef5cd1d2
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListRequestStats.jsp
@@ -0,0 +1,61 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+%>
+<table id="requestStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>Region Name</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 (RegionInfo r: onlineRegions) { %>
+
+ <tr>
+ <%
+ ClusterStatusProtos.RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
+ String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
+ regionServer.getConfiguration());
+ %>
+ <td><a href="region.jsp?name=<%= r.getEncodedName() %>"><%= displayName %></a></td>
+ <% if (load != null) { %>
+ <td><%= String.format("%,1d", load.getReadRequestsCount()) %></td>
+ <td><%= String.format("%,1d", load.getFilteredReadRequestsCount()) %></td>
+ <td><%= String.format("%,1d", load.getWriteRequestsCount()) %></td>
+ <% } %>
+ </tr>
+ <% } %>
+ </tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListStoreStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListStoreStats.jsp
new file mode 100644
index 00000000000..b663b74536e
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionListStoreStats.jsp
@@ -0,0 +1,119 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.shaded.protobuf.generated.ClusterStatusProtos"
+ import="org.apache.hadoop.hbase.client.RegionInfoDisplay"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.regionserver.*"
+ import="org.apache.hadoop.util.StringUtils" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ List<RegionInfo> onlineRegions = (List<RegionInfo>) request.getAttribute("onlineRegions");
+%>
+<table id="storeStatsTable" class="tablesorter table table-striped">
+ <thead>
+ <tr>
+ <th>Region Name</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>
+ <th>Data Locality</th>
+ <th>Len Of Biggest Cell</th>
+ <th>% Cached</th>
+ </tr>
+ </thead>
+
+ <tbody>
+
+ <% for (RegionInfo r: onlineRegions) { %>
+ <tr>
+ <%
+ final String ZEROMB = "0 MB";
+ final String ZEROKB = "0 KB";
+ String uncompressedStorefileSizeStr = ZEROMB;
+ String storefileSizeStr = ZEROMB;
+ String indexSizeStr = ZEROKB;
+ String bloomSizeStr = ZEROKB;
+ ClusterStatusProtos.RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
+ String displayName = RegionInfoDisplay.getRegionNameAsStringForDisplay(r,
+ regionServer.getConfiguration());
+ if (load != null) {
+ long uncompressedStorefileSize = load.getStoreUncompressedSizeMB();
+ long storefileSize = load.getStorefileSizeMB();
+ long indexSize = load.getTotalStaticIndexSizeKB();
+ long bloomSize = load.getTotalStaticBloomSizeKB();
+ 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);
+ }
+ }
+ long lenOfBiggestCellInRegion = -1L;
+ Region region = regionServer.getRegion(r.getEncodedName());
+ if (region != null) {
+ List<? extends Store> stores = region.getStores();
+ for (Store store : stores) {
+ Collection<? extends StoreFile> storeFiles = store.getStorefiles();
+ for (StoreFile sf : storeFiles) {
+ long lenOfBiggestCell = ((HStoreFile)sf).getFileInfo().getHFileInfo().getLenOfBiggestCell();
+ if (lenOfBiggestCellInRegion < lenOfBiggestCell) {
+ lenOfBiggestCellInRegion = lenOfBiggestCell;
+ }
+ }
+ }
+ }
+ %>
+
+ <td><a href="region.jsp?name=<%= r.getEncodedName() %>"><%= displayName %></a></td>
+ <% if (load != null) { %>
+ <td><%= String.format("%,1d", load.getStores()) %></td>
+ <td><%= String.format("%,1d", load.getStorefiles()) %></td>
+ <td><%= uncompressedStorefileSizeStr %></td>
+ <td><%= storefileSizeStr %></td>
+ <td><%= indexSizeStr %></td>
+ <td><%= bloomSizeStr %></td>
+ <td><%= load.getDataLocality() %></td>
+ <td><%= String.format("%,1d", lenOfBiggestCellInRegion) %></td>
+ <td><%= StringUtils.formatPercent(load.getCurrentRegionCachedRatio(), 2) %></td>
+ <% } %>
+ </tr>
+ <% } %>
+
+ </tbody>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp
index ee63075d5d6..f25377e7e4d 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/regionserver.jsp
@@ -17,4 +17,126 @@
* limitations under the License.
*/
--%>
-<meta HTTP-EQUIV="REFRESH" content="0;url=/rs-status"/>
+<%@ page contentType="text/html;charset=UTF-8"
+ import="java.util.*"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.client.RegionInfo"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil"
+ import="org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.ServerInfo"
+ import="org.apache.hadoop.hbase.zookeeper.MasterAddressTracker"
+ import="org.apache.hadoop.hbase.regionserver.http.RSStatusConstants" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ String format = request.getParameter(RSStatusConstants.FORMAT);
+ if (format == null) {
+ format = RSStatusConstants.FORMAT_HTML;
+ }
+ if (RSStatusConstants.FORMAT_JSON.equals(format)) {
+ response.setContentType("application/json");
+ } else {
+ response.setContentType("text/html");
+ }
+
+ if (!regionServer.isOnline()) {
+ response.getWriter().write("The RegionServer is initializing!");
+ response.getWriter().close();
+ return;
+ }
+
+ String filter = request.getParameter(RSStatusConstants.FILTER);
+ if (filter == null) {
+ filter = RSStatusConstants.FILTER_GENERAL;
+ }
+ String bcn = request.getParameter(RSStatusConstants.BLOCK_CACHE_NAME);
+ String bcv = request.getParameter(RSStatusConstants.BLOCK_CACHE_V);
+ if (bcv == null) {
+ bcv = "";
+ }
+ // If json AND bcn is NOT an empty string presume it a block cache view request.
+ if (format.equals(RSStatusConstants.FORMAT_JSON) && bcn != null && bcn.length() > 0) {
+ request.setAttribute("conf", regionServer.getConfiguration());
+ request.setAttribute(RSStatusConstants.BLOCK_CACHE_NAME, bcn);
+ request.setAttribute(RSStatusConstants.BLOCK_CACHE_V, bcv);
+ request.setAttribute("blockCache", regionServer.getBlockCache().orElse(null));
+%><jsp:include page="blockCacheView.jsp"/>
+<%
+ return;
+ }
+ else if (format.equals(RSStatusConstants.FORMAT_JSON)) {
+ request.setAttribute(RSStatusConstants.FILTER, filter);
+ request.setAttribute(RSStatusConstants.FORMAT, RSStatusConstants.FORMAT_JSON); %>
+ <jsp:include page="taskMonitor.jsp"/>
+<%
+ return;
+ }
+
+ ServerInfo serverInfo = ProtobufUtil.getServerInfo(null, regionServer.getRSRpcServices());
+ ServerName serverName = ProtobufUtil.toServerName(serverInfo.getServerName());
+ List<RegionInfo> onlineRegions = ProtobufUtil.getOnlineRegions(regionServer.getRSRpcServices());
+ MasterAddressTracker masterAddressTracker = regionServer.getMasterAddressTracker();
+ ServerName masterServerName = masterAddressTracker == null ? null
+ : masterAddressTracker.getMasterAddress();
+ int infoPort = masterAddressTracker == null ? 0 : masterAddressTracker.getMasterInfoPort();
+
+ String title = "HBase Region Server: " + serverName.getHostname();
+ pageContext.setAttribute("pageTitle", title);
+%>
+
+<jsp:include page="header.jsp">
+ <jsp:param name="pageTitle" value="${pageTitle}"/>
+</jsp:include>
+
+<div class="container-fluid content">
+ <div class="row inner_header">
+ <div class="page-header">
+ <h1>RegionServer <small><%= serverName %></small></h1>
+ </div>
+ </div>
+ <div class="row">
+
+ <section>
+ <h2>Server Metrics</h2>
+ <jsp:include page="serverMetrics.jsp"/>
+ </section>
+
+ <section>
+ <h2>Block Cache</h2>
+ <jsp:include page="blockCache.jsp"/>
+ </section>
+
+ <section>
+ <% request.setAttribute(RSStatusConstants.PARENT, "/regionserver.jsp"); %>
+ <jsp:include page="taskMonitor.jsp"/>
+ </section>
+
+ <section>
+ <h2>Regions</h2>
+ <% request.setAttribute("onlineRegions", onlineRegions); %>
+ <jsp:include page="regionList.jsp"/>
+ </section>
+
+ <section>
+ <h2>Replication Status</h2>
+ <jsp:include page="replicationStatus.jsp"/>
+ </section>
+
+ <section>
+ <h2>Software Attributes</h2>
+ <% request.setAttribute("masterServerName", masterServerName); %>
+ <% request.setAttribute("infoPort", infoPort); %>
+ <jsp:include page="softwareAttributes.jsp"/>
+ </section>
+
+ </div> <!--/.row -->
+</div> <!-- /.container-fluid content -->
+
+ <jsp:include page="scripts.jsp" />
+ <script src="/static/js/jquery.tablesorter.min.js" type="text/javascript"></script>
+ <script src ="/static/js/regionServerStatusInit.js" type="text/javascript"></script>
+</body>
+</html>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatus.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatus.jsp
new file mode 100644
index 00000000000..9825669b0a1
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatus.jsp
@@ -0,0 +1,53 @@
+<%--
+/**
+ * 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.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import ="org.apache.hadoop.hbase.replication.regionserver.ReplicationStatus" %>
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+ Map<String, ReplicationStatus> walGroupsReplicationStatus = regionServer.getWalGroupsReplicationStatus();
+
+ if (walGroupsReplicationStatus != null && walGroupsReplicationStatus.size() > 0) {
+%>
+
+<div class="tabbable">
+ <ul class="nav nav-pills" role="tablist">
+ <li class="nav-item"><a class="nav-link active" href="#tab_currentLog" data-bs-toggle="tab" role="tab">Current Log</a> </li>
+ <li class="nav-item"><a class="nav-link" href="#tab_replicationDelay" data-bs-toggle="tab" role="tab">Replication Delay</a></li>
+ </ul>
+ <div class="tab-content">
+ <% request.setAttribute("metrics", walGroupsReplicationStatus); %>
+ <div class="tab-pane active" id="tab_currentLog" role="tabpanel">
+ <jsp:include page="replicationStatusCurrentLog.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_replicationDelay" role="tabpanel">
+ <jsp:include page="replicationStatusReplicationDelay.jsp"/>
+ </div>
+ </div>
+</div>
+<p> If the replication delay is UNKNOWN, that means this walGroup doesn't start replicate yet and it may get disabled.
+ If the size of log is 0, it means we are replicating current HLog, thus we can't get accurate size since it's not closed yet.</p>
+
+<% } else { %>
+ <p>No Replication Metrics for Peers</p>
+<% } %>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusCurrentLog.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusCurrentLog.jsp
new file mode 100644
index 00000000000..254620139de
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusCurrentLog.jsp
@@ -0,0 +1,47 @@
+<%--
+/**
+ * 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.procedure2.util.StringUtils"
+ import ="org.apache.hadoop.hbase.replication.regionserver.ReplicationStatus" %>
+<%
+ Map<String, ReplicationStatus> metrics = (Map<String, ReplicationStatus>) request.getAttribute("metrics");
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>PeerId</th>
+ <th>WalGroup</th>
+ <th>Current Log</th>
+ <th>Size</th>
+ <th>Queue Size</th>
+ <th>Offset</th>
+ </tr>
+ <% for (Map.Entry<String, ReplicationStatus> entry: metrics.entrySet()) { %>
+ <tr>
+ <td><%= entry.getValue().getPeerId() %></td>
+ <td><%= entry.getValue().getWalGroup() %></td>
+ <td><%= entry.getValue().getCurrentPath() %> </td>
+ <td><%= StringUtils.humanSize(entry.getValue().getFileSize()) %></td>
+ <td><%= entry.getValue().getQueueSize() %></td>
+ <td><%= StringUtils.humanSize(entry.getValue().getCurrentPosition()) %></td>
+ </tr>
+ <% } %>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusReplicationDelay.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusReplicationDelay.jsp
new file mode 100644
index 00000000000..19ea1f28b5d
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/replicationStatusReplicationDelay.jsp
@@ -0,0 +1,44 @@
+<%--
+/**
+ * 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.procedure2.util.StringUtils"
+ import ="org.apache.hadoop.hbase.replication.regionserver.ReplicationStatus" %>
+<%
+ Map<String, ReplicationStatus> metrics = (Map<String, ReplicationStatus>) request.getAttribute("metrics");
+%>
+<table class="table table-striped">
+ <tr>
+ <th>PeerId</th>
+ <th>WalGroup</th>
+ <th>Current Log</th>
+ <th>Last Shipped Age</th>
+ <th>Replication Delay</th>
+ </tr>
+ <% for (Map.Entry<String, ReplicationStatus> entry: metrics.entrySet()) { %>
+ <tr>
+ <td><%= entry.getValue().getPeerId() %></td>
+ <td><%= entry.getValue().getWalGroup() %></td>
+ <td><%= entry.getValue().getCurrentPath() %> </td>
+ <td><%= StringUtils.humanTimeDiff(entry.getValue().getAgeOfLastShippedOp()) %></td>
+ <td><%= entry.getValue().getReplicationDelay() == Long.MAX_VALUE ? "UNKNOWN" : StringUtils.humanTimeDiff(entry.getValue().getReplicationDelay()) %></td>
+ </tr>
+ <% } %>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/scripts.jsp
similarity index 98%
copy from hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp
copy to hbase-server/src/main/resources/hbase-webapps/regionserver/scripts.jsp
index 02a36e9c23f..d987621a119 100644
--- a/hbase-server/src/main/resources/hbase-webapps/regionserver/footer.jsp
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/scripts.jsp
@@ -26,5 +26,3 @@
$('a[href="' + location.pathname + '"]').addClass('active');
});
</script>
- </body>
-</html>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetrics.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetrics.jsp
new file mode 100644
index 00000000000..08af35feb66
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetrics.jsp
@@ -0,0 +1,55 @@
+<%--
+/**
+ * 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" %>
+
+<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_walStats" data-bs-toggle="tab" role="tab">WALs</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_queueStats" data-bs-toggle="tab" role="tab">Queues</a></li>
+ <li class="nav-item"><a class="nav-link" href="#tab_byteBuffAllocatorStats" data-bs-toggle="tab" role="tab">ByteBuffAllocator Stats</a></li>
+ </ul>
+ <div class="tab-content">
+ <div class="tab-pane active" id="tab_baseStats" role="tabpanel">
+ <jsp:include page="serverMetricsBaseStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_memoryStats" role="tabpanel">
+ <jsp:include page="serverMetricsMemoryStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_requestStats" role="tabpanel">
+ <jsp:include page="serverMetricsRequestStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_walStats" role="tabpanel">
+ <jsp:include page="serverMetricsWalStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_storeStats" role="tabpanel">
+ <jsp:include page="serverMetricsStoreStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_queueStats" role="tabpanel">
+ <jsp:include page="serverMetricsQueueStats.jsp"/>
+ </div>
+ <div class="tab-pane" id="tab_byteBuffAllocatorStats" role="tabpanel">
+ <jsp:include page="serverMetricsByteBuffAllocatorStats.jsp"/>
+ </div>
+ </div>
+</div>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsBaseStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsBaseStats.jsp
new file mode 100644
index 00000000000..59c2c46fe5c
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsBaseStats.jsp
@@ -0,0 +1,49 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper" %>
+
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Requests Per Second</th>
+ <th>Num. Regions</th>
+ <th>Block locality</th>
+ <th>Block locality (Secondary replicas)</th>
+ <th>Slow WAL Append Count</th>
+ </tr>
+ <tr>
+ <td><%= String.format("%.0f", mWrap.getRequestsPerSecond()) %></td>
+ <td><%= mWrap.getNumOnlineRegions() %></td>
+ <td><%= String.format("%.3f",mWrap.getPercentFileLocal()) %><%= "%" %></td>
+ <td><%= String.format("%.3f",mWrap.getPercentFileLocalSecondaryRegions()) %><%= "%" %></td>
+ <td><%= mWrap.getNumWALSlowAppend() %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsByteBuffAllocatorStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsByteBuffAllocatorStats.jsp
new file mode 100644
index 00000000000..65334a20c23
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsByteBuffAllocatorStats.jsp
@@ -0,0 +1,51 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.io.ByteBuffAllocator" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ ByteBuffAllocator bbAllocator = regionServer.getRpcServer().getByteBuffAllocator();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Total Heap Allocation</th>
+ <th>Total Pool Allocation</th>
+ <th>Heap Allocation Ratio</th>
+ <th>Total Buffer Count</th>
+ <th>Used Buffer Count</th>
+ <th>Buffer Size</th>
+ </tr>
+ <tr>
+ <td><%= TraditionalBinaryPrefix.long2String(ByteBuffAllocator.getHeapAllocationBytes(bbAllocator, ByteBuffAllocator.HEAP), "B", 1) %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(bbAllocator.getPoolAllocationBytes(), "B", 1) %></td>
+ <td><%= String.format("%.3f", ByteBuffAllocator.getHeapAllocationRatio(bbAllocator, ByteBuffAllocator.HEAP) * 100) %><%= "%" %></td>
+ <td><%= bbAllocator.getTotalBufferCount() %></td>
+ <td><%= bbAllocator.getUsedBufferCount() %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(bbAllocator.getBufferSize(), "B", 1) %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsMemoryStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsMemoryStats.jsp
new file mode 100644
index 00000000000..b3a0443add6
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsMemoryStats.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="java.util.*"
+ import="org.apache.hadoop.hbase.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper"
+ import="java.lang.management.MemoryUsage"
+ import="org.apache.hadoop.hbase.io.util.MemorySizeUtil"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+
+ long usedHeap = -1L;
+ long maxHeap = -1L;
+ final MemoryUsage usage = MemorySizeUtil.safeGetHeapMemoryUsage();
+ if (usage != null) {
+ maxHeap = usage.getMax();
+ usedHeap = usage.getUsed();
+ }
+%>
+<table class="table table-striped">
+ <tr>
+ <th>Used Heap</th>
+ <th>Max Heap</th>
+ <th>Direct Memory Used</th>
+ <th>Direct Memory Configured</th>
+ <th>Memstore On-Heap Size / Limit</th>
+ <th>Memstore Off-Heap Size / Limit</th>
+ <th>Memstore Data Size (On&&Off Heap)</th>
+ </tr>
+ <tr>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(usedHeap, "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(maxHeap, "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(DirectMemoryUtils.getDirectMemoryUsage(), "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(DirectMemoryUtils.getDirectMemorySize(), "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(mWrap.getOnHeapMemStoreSize(), "B", 1) + " / "
+ + TraditionalBinaryPrefix.long2String(mWrap.getOnHeapMemStoreLimit(), "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(mWrap.getOffHeapMemStoreSize(), "B", 1) + " / "
+ + TraditionalBinaryPrefix.long2String(mWrap.getOffHeapMemStoreLimit(), "B", 1) %>
+ </td>
+ <td>
+ <%= TraditionalBinaryPrefix.long2String(mWrap.getMemStoreSize(), "B", 1) %>
+ </td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsQueueStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsQueueStats.jsp
new file mode 100644
index 00000000000..3a6bc509fde
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsQueueStats.jsp
@@ -0,0 +1,53 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix"
+ import="org.apache.hadoop.hbase.ipc.MetricsHBaseServerWrapper" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+ MetricsHBaseServerWrapper mServerWrap = regionServer.getRpcServer().getMetrics().getHBaseServerWrapper();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Compaction Queue Length</th>
+ <th>Flush Queue Length</th>
+ <th>Priority Call Queue Length</th>
+ <th>General Call Queue Length</th>
+ <th>Replication Call Queue Length</th>
+ <th>Total Call Queue Size</th>
+ </tr>
+ <tr>
+ <td><%= mWrap.getCompactionQueueSize() %></td>
+ <td><%= mWrap.getFlushQueueSize() %></td>
+ <td><%= mServerWrap.getPriorityQueueLength() %></td>
+ <td><%= mServerWrap.getGeneralQueueLength() %></td>
+ <td><%= mServerWrap.getReplicationQueueLength() %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(mServerWrap.getTotalQueueSize(), "B", 1) %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsRequestStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsRequestStats.jsp
new file mode 100644
index 00000000000..bf435884b3d
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsRequestStats.jsp
@@ -0,0 +1,46 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Request Per Second</th>
+ <th>Read Request Count</th>
+ <th>Filtered Read Request Count</th>
+ <th>Write Request Count</th>
+ </tr>
+ <tr>
+ <td><%= String.format("%.0f", mWrap.getRequestsPerSecond()) %></td>
+ <td><%= mWrap.getReadRequestsCount() %></td>
+ <td><%= mWrap.getFilteredReadRequestsCount() %></td>
+ <td><%= mWrap.getWriteRequestsCount() %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsStoreStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsStoreStats.jsp
new file mode 100644
index 00000000000..2da3ea0bba0
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsStoreStats.jsp
@@ -0,0 +1,49 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Num. Stores</th>
+ <th>Num. Storefiles</th>
+ <th>Root Index Size</th>
+ <th>Index Size</th>
+ <th>Bloom Size</th>
+ </tr>
+ <tr>
+ <td><%= mWrap.getNumStores() %></td>
+ <td><%= mWrap.getNumStoreFiles() %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(mWrap.getStoreFileIndexSize(), "B", 1) %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(mWrap.getTotalStaticIndexSize(), "B", 1) %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(mWrap.getTotalStaticBloomSize(), "B", 1) %></td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsWalStats.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsWalStats.jsp
new file mode 100644
index 00000000000..d172a86feff
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/serverMetricsWalStats.jsp
@@ -0,0 +1,50 @@
+<%--
+/**
+ * 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.util.*"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapper"
+ import="org.apache.hadoop.util.StringUtils.TraditionalBinaryPrefix" %>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ MetricsRegionServerWrapper mWrap = regionServer.getMetrics().getRegionServerWrapper();
+%>
+
+<table class="table table-striped">
+ <tr>
+ <th>Num. WAL Files</th>
+ <th>Size. WAL Files</th>
+ <th>WAL exclude DNs</th>
+ </tr>
+ <tr>
+ <td><%= mWrap.getNumWALFiles() %></td>
+ <td><%= TraditionalBinaryPrefix.long2String(mWrap.getWALFileSize(), "B", 1) %></td>
+ <td>
+ <% for (String exclude: mWrap.getWALExcludeDNs()) { %>
+ <%= exclude %><br>
+ <% } %>
+ </%for>
+ </td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/regionserver/softwareAttributes.jsp b/hbase-server/src/main/resources/hbase-webapps/regionserver/softwareAttributes.jsp
new file mode 100644
index 00000000000..dd46f5eb444
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/regionserver/softwareAttributes.jsp
@@ -0,0 +1,114 @@
+<%--
+/**
+ * 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.util.JvmVersion"
+ import="org.apache.hadoop.hbase.regionserver.HRegionServer"
+ import="org.apache.hadoop.hbase.ServerName"
+ import="org.apache.hadoop.hbase.util.ZKStringFormatter"%>
+
+<%
+ HRegionServer regionServer =
+ (HRegionServer) getServletContext().getAttribute(HRegionServer.REGIONSERVER);
+
+ ServerName masterServerName = (ServerName) request.getAttribute("masterServerName");
+ int infoPort = (int) request.getAttribute("infoPort");
+%>
+<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><%= ZKStringFormatter.formatZKString(regionServer.getZooKeeper()) %></td>
+ <td>Addresses of all registered ZK servers</td>
+ </tr>
+ <tr>
+ <td>Coprocessors</td>
+ <td><%= Arrays.toString(regionServer.getRegionServerCoprocessors()) %></td>
+ <td>Coprocessors currently loaded by this regionserver</td>
+ </tr>
+ <tr>
+ <td>RS Start Time</td>
+ <td><%= new Date(regionServer.getStartcode()) %></td>
+ <td>Date stamp of when this region server was started</td>
+ </tr>
+ <tr>
+ <td>HBase Master</td>
+ <td>
+ <% if (masterServerName == null) { %>
+ No master found
+ <% } else {
+ String host = masterServerName.getHostname() + ":" + infoPort;
+ String url = "//" + host + "/master.jsp";
+ %>
+ <a href="<%= url %>"><%= host %></a>
+ <% } %>
+ </td>
+ <td>Address of HBase Master</td>
+ </tr>
+</table>
diff --git a/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css b/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css
index d1ae4ace7f4..46d8ca96f20 100644
--- a/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css
+++ b/hbase-server/src/main/resources/hbase-webapps/static/css/hbase.css
@@ -152,3 +152,32 @@ table.tablesorter thead tr .tablesorter-headerDesc {
table.nowrap th, table.nowrap td {
white-space: nowrap;
}
+
+/* Block Cache pagination */
+.pagination-container {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 0;
+}
+
+.page-numbers {
+ display: flex;
+ gap: 4px;
+}
+
+.page-number {
+ min-width: 30px;
+ text-align: center;
+}
+
+.page-number.active {
+ font-weight: bold;
+ background-color: #eee;
+}
+
+.page-info {
+ margin-left: 15px;
+ font-size: 0.9em;
+ color: #666;
+}
diff --git a/hbase-server/src/main/resources/hbase-webapps/static/js/blockCacheInit.js b/hbase-server/src/main/resources/hbase-webapps/static/js/blockCacheInit.js
new file mode 100644
index 00000000000..164ad9752e5
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/static/js/blockCacheInit.js
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/*
+ * This script displays and paginates the initially hidden table rows of Hit Ratios for time periods.
+ * See: HBASE-29276 Compute and display hit ratio by configurable, granular time periods
+ */
+
+// Wait for document to be fully loaded
+document.addEventListener('DOMContentLoaded', function() {
+
+ // Count actual items in the DOM
+ const itemRows = document.querySelectorAll('tr.item-row');
+
+ // Pagination state
+ let currentPage = 1;
+ const pageSize = 10;
+ const totalItems = itemRows.length;
+ const totalPages = Math.ceil(totalItems / pageSize);
+
+ // Create page buttons
+ const pageButtonsContainer = document.getElementById('page-buttons');
+ if (pageButtonsContainer) {
+ for (let i = 1; i <= totalPages; i++) {
+ const button = document.createElement('button');
+ button.className = 'page-number';
+ button.textContent = i;
+ button.onclick = function() { goToPage(i); };
+ pageButtonsContainer.appendChild(button);
+ }
+ }
+ function displayItems() {
+ // Hide all item rows
+ itemRows.forEach(row => {
+ row.style.display = 'none';
+ });
+
+ // Calculate indexes
+ const startIndex = (currentPage - 1) * pageSize;
+ const endIndex = Math.min(startIndex + pageSize, totalItems);
+
+ // Show rows for current page
+ let displayedCount = 0;
+ for (let i = startIndex; i < endIndex; i++) {
+ const row = document.getElementById('row-' + i);
+ if (row) {
+ row.style.display = 'table-row';
+ displayedCount++;
+ }
+ }
+
+ // Update pagination UI
+ document.querySelectorAll('.page-number').forEach(btn => {
+ if (parseInt(btn.textContent) === currentPage) {
+ btn.classList.add('active');
+ } else {
+ btn.classList.remove('active');
+ }
+ });
+
+ const prevBtn = document.getElementById('prev-page');
+ const nextBtn = document.getElementById('next-page');
+
+ if (prevBtn) prevBtn.disabled = currentPage === 1;
+ if (nextBtn) nextBtn.disabled = currentPage === totalPages;
+
+ // Update page info
+ const pageInfo = document.getElementById('page-info');
+ if (pageInfo) {
+ pageInfo.textContent = `Showing ${startIndex + 1} to ${endIndex} of ${totalItems} items`;
+ }
+ }
+
+ function goToPage(page) {
+ if (page >= 1 && page <= totalPages) {
+ currentPage = page;
+ displayItems();
+ }
+ }
+
+ window.nextPage = function() {
+ goToPage(currentPage + 1);
+ };
+
+ window.prevPage = function() {
+ goToPage(currentPage - 1);
+ };
+
+ window.goToPage = goToPage;
+
+ // Check URL for initial page
+ const urlParams = new URLSearchParams(window.location.search);
+ const pageParam = urlParams.get('page');
+ if (pageParam) {
+ const parsedPage = parseInt(pageParam);
+ if (!isNaN(parsedPage) && parsedPage >= 1) {
+ currentPage = parsedPage;
+ }
+ }
+
+ // Initial display
+ displayItems();
+});
diff --git a/hbase-server/src/main/resources/hbase-webapps/static/js/regionServerStatusInit.js b/hbase-server/src/main/resources/hbase-webapps/static/js/regionServerStatusInit.js
new file mode 100644
index 00000000000..f65ffdab876
--- /dev/null
+++ b/hbase-server/src/main/resources/hbase-webapps/static/js/regionServerStatusInit.js
@@ -0,0 +1,86 @@
+/*
+ * 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"
+ });
+
+ $("#baseStatsTable").tablesorter({
+ headers: {
+ '.cls_emptyMin': {empty: 'emptyMin'},
+ '.cls_emptyMax': {empty: 'emptyMax'}
+ }
+ });
+ $("#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'}
+ }
+ });
+ $("#memstoreStatsTable").tablesorter({
+ headers: {
+ '.cls_filesize': {sorter: 'filesize'}
+ }
+ });
+ }
+);
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 e0238e41e9b..a894bbcd0ae 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
@@ -97,7 +97,8 @@ public class TestInfoServers {
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");
+ assertContainsContent(new URL("http://localhost:" + port + "/index.html"), "regionserver.jsp");
+ assertContainsContent(new URL("http://localhost:" + port + "/rs-status"), "regionserver.jsp");
}
/**
@@ -111,7 +112,7 @@ public class TestInfoServers {
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");
+ assertContainsContent(new URL("http://localhost:" + port + "/regionserver.jsp"), "meta");
}
@Test
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
index d66c1b1b2e1..0ec94c91719 100644
--- 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
@@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.master.http;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -203,7 +204,7 @@ public class TestMasterStatusUtil {
conf.setBoolean("hbase.master.ui.fragmentation.enabled", true);
Map<String, Integer> fragmentationInfo = MasterStatusUtil.getFragmentationInfo(master, conf);
assertNotNull(fragmentationInfo);
- assertEquals(1, fragmentationInfo.size());
+ assertFalse(fragmentationInfo.isEmpty());
}
@Test
@@ -240,7 +241,8 @@ public class TestMasterStatusUtil {
String link = MasterStatusUtil.serverNameLink(master, FAKE_HOST);
assertNotNull(link);
- assertEquals("<a href=\"//fakehost:16030/rs-status\">fakehost,12345,1234567890</a>", link);
+ assertEquals("<a href=\"//fakehost:16030/regionserver.jsp\">fakehost,12345,1234567890</a>",
+ link);
}
@Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusPage.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusPage.java
new file mode 100644
index 00000000000..b4b7214b037
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusPage.java
@@ -0,0 +1,178 @@
+/*
+ * 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.regionserver.http;
+
+import static org.junit.Assert.assertEquals;
+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.List;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+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.MediumTests;
+import org.apache.hadoop.hbase.testclassification.RegionServerTests;
+import org.apache.hadoop.hbase.util.CommonFSUtils;
+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;
+
+/**
+ * Tests for the region server status page and its template.
+ */
+@Category({ RegionServerTests.class, MediumTests.class })
+public class TestRSStatusPage {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestRSStatusPage.class);
+
+ private static LocalHBaseCluster CLUSTER;
+
+ private final static HBaseTestingUtil UTIL = new HBaseTestingUtil();
+ public static final String TEST_TABLE_NAME_1 = "TEST_TABLE_1";
+ public static final String TEST_TABLE_NAME_2 = "TEST_TABLE_2";
+
+ @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("TestRSStatusPage");
+ 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 testStatusPage() throws Exception {
+ HMaster master = CLUSTER.getActiveMaster();
+
+ int masterPort = master.getActiveMasterManager().getActiveMasterInfoPort();
+ ServerName activeMaster =
+ master.getActiveMaster().orElseThrow(() -> new IllegalStateException("No active master"));
+ String masterHostname = activeMaster.getHostname();
+
+ createTestTables(master);
+
+ ServerManager serverManager = master.getServerManager();
+ List<ServerName> onlineServersList = serverManager.getOnlineServersList();
+
+ assertEquals(1, onlineServersList.size());
+
+ ServerName firstServerName = onlineServersList.get(0);
+ int infoPort = master.getRegionServerInfoPort(firstServerName);
+ String hostname = firstServerName.getHostname();
+ int port = firstServerName.getPort();
+
+ String page = getRegionServerStatusPageContent(hostname, infoPort);
+
+ assertTrue(page.contains("<title>HBase Region Server: " + masterHostname + "</title>"));
+
+ String expectedPageHeader = "<h1>RegionServer <small>" + hostname + "," + port + ","
+ + firstServerName.getStartCode() + "</small></h1>";
+ assertTrue(page.contains(expectedPageHeader));
+ assertTrue(page.contains("<h2>Server Metrics</h2>"));
+ assertTrue(page.contains("<th>Requests Per Second</th>"));
+ assertTrue(page.contains("<h2>Block Cache</h2>"));
+ assertTrue(page.contains("<h2>Regions</h2>"));
+ assertTrue(page.contains("<h2>Replication Status</h2>"));
+ assertTrue(page.contains("<h2>Software Attributes</h2>"));
+
+ // Should have a link to master
+ String expectedMasterLink = "<a href=\"//" + masterHostname + ":" + masterPort
+ + "/master.jsp\">" + masterHostname + ":" + masterPort + "</a>";
+ assertTrue(page.contains(expectedMasterLink));
+ }
+
+ 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 static String getRegionServerStatusPageContent(String hostname, int infoPort)
+ throws IOException {
+ URL url = new URL("http://" + hostname + ":" + infoPort + "/regionserver.jsp");
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.connect();
+
+ assertEquals(200, conn.getResponseCode());
+ assertEquals("text/html;charset=utf-8", conn.getContentType());
+
+ return getResponseBody(conn);
+ }
+
+ 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();
+ }
+}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusServlet.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusServlet.java
deleted file mode 100644
index c7e310772a9..00000000000
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/http/TestRSStatusServlet.java
+++ /dev/null
@@ -1,141 +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.regionserver.http;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.List;
-import java.util.Optional;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.ServerName;
-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.io.ByteBuffAllocator;
-import org.apache.hadoop.hbase.ipc.MetricsHBaseServer;
-import org.apache.hadoop.hbase.ipc.MetricsHBaseServerWrapperStub;
-import org.apache.hadoop.hbase.ipc.RpcServerInterface;
-import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.regionserver.MetricsRegionServer;
-import org.apache.hadoop.hbase.regionserver.MetricsRegionServerWrapperStub;
-import org.apache.hadoop.hbase.regionserver.RSRpcServices;
-import org.apache.hadoop.hbase.testclassification.RegionServerTests;
-import org.apache.hadoop.hbase.testclassification.SmallTests;
-import org.apache.hadoop.hbase.tmpl.regionserver.RSStatusTmpl;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.zookeeper.MasterAddressTracker;
-import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-import org.mockito.Mockito;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
-import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
-
-import org.apache.hadoop.hbase.shaded.protobuf.ResponseConverter;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.GetServerInfoResponse;
-
-/**
- * Tests for the region server status page and its template.
- */
-@Category({ RegionServerTests.class, SmallTests.class })
-public class TestRSStatusServlet {
-
- @ClassRule
- public static final HBaseClassTestRule CLASS_RULE =
- HBaseClassTestRule.forClass(TestRSStatusServlet.class);
-
- private static final Logger LOG = LoggerFactory.getLogger(TestRSStatusServlet.class);
- private HRegionServer rs;
- private RSRpcServices rpcServices;
- private RpcServerInterface rpcServer;
-
- static final int FAKE_IPC_PORT = 1585;
- static final int FAKE_WEB_PORT = 1586;
-
- private final ServerName fakeServerName = ServerName.valueOf("localhost", FAKE_IPC_PORT, 11111);
- private final GetServerInfoResponse fakeResponse =
- ResponseConverter.buildGetServerInfoResponse(fakeServerName, FAKE_WEB_PORT);
-
- private final ServerName fakeMasterAddress = ServerName.valueOf("localhost", 60010, 1212121212);
-
- @Rule
- public TestName name = new TestName();
-
- @Before
- public void setupBasicMocks() throws IOException, ServiceException {
- rs = Mockito.mock(HRegionServer.class);
- rpcServices = Mockito.mock(RSRpcServices.class);
- rpcServer = Mockito.mock(RpcServerInterface.class);
- Mockito.doReturn(HBaseConfiguration.create()).when(rs).getConfiguration();
- Mockito.doReturn(rpcServices).when(rs).getRSRpcServices();
- Mockito.doReturn(rpcServer).when(rs).getRpcServer();
- Mockito.doReturn(fakeResponse).when(rpcServices).getServerInfo(Mockito.any(), Mockito.any());
- // Fake ZKW
- ZKWatcher zkw = Mockito.mock(ZKWatcher.class);
- Mockito.doReturn("fakequorum").when(zkw).getQuorum();
- Mockito.doReturn(zkw).when(rs).getZooKeeper();
-
- // Fake BlockCache
- LOG.warn("The " + HConstants.HFILE_BLOCK_CACHE_SIZE_KEY + " is set to 0");
- Mockito.doReturn(Optional.empty()).when(rs).getBlockCache();
-
- // Fake MasterAddressTracker
- MasterAddressTracker mat = Mockito.mock(MasterAddressTracker.class);
- Mockito.doReturn(fakeMasterAddress).when(mat).getMasterAddress();
- Mockito.doReturn(mat).when(rs).getMasterAddressTracker();
-
- MetricsRegionServer rms = Mockito.mock(MetricsRegionServer.class);
- Mockito.doReturn(new MetricsRegionServerWrapperStub()).when(rms).getRegionServerWrapper();
- Mockito.doReturn(rms).when(rs).getMetrics();
-
- MetricsHBaseServer ms = Mockito.mock(MetricsHBaseServer.class);
- Mockito.doReturn(new MetricsHBaseServerWrapperStub()).when(ms).getHBaseServerWrapper();
- Mockito.doReturn(ms).when(rpcServer).getMetrics();
- Mockito.doReturn(ByteBuffAllocator.HEAP).when(rpcServer).getByteBuffAllocator();
- }
-
- @Test
- public void testBasic() throws IOException, ServiceException {
- new RSStatusTmpl().render(new StringWriter(), rs);
- }
-
- @Test
- public void testWithRegions() throws IOException, ServiceException {
- TableDescriptor htd =
- TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build();
- List<RegionInfo> regions = Lists.newArrayList(
- RegionInfoBuilder.newBuilder(htd.getTableName()).setStartKey(Bytes.toBytes("a"))
- .setEndKey(Bytes.toBytes("d")).build(),
- RegionInfoBuilder.newBuilder(htd.getTableName()).setStartKey(Bytes.toBytes("d"))
- .setEndKey(Bytes.toBytes("z")).build());
- Mockito.doReturn(ResponseConverter.buildGetOnlineRegionResponse(regions)).when(rpcServices)
- .getOnlineRegion(Mockito.any(), Mockito.any());
- new RSStatusTmpl().render(new StringWriter(), rs);
- }
-}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestZKStringFormatter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestZKStringFormatter.java
new file mode 100644
index 00000000000..9621344e072
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestZKStringFormatter.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category({ MiscTests.class, SmallTests.class })
+public class TestZKStringFormatter {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestZKStringFormatter.class);
+
+ private ZKWatcher zkWatcher;
+
+ @Before
+ public void setUp() throws Exception {
+ zkWatcher = mock(ZKWatcher.class);
+ }
+
+ @Test
+ public void testFormatZKStringNullQuorum() {
+ when(zkWatcher.getQuorum()).thenReturn(null);
+ String result = ZKStringFormatter.formatZKString(zkWatcher);
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testFormatZKStringEmptyQuorum() {
+ when(zkWatcher.getQuorum()).thenReturn("");
+ String result = ZKStringFormatter.formatZKString(zkWatcher);
+ assertEquals("", result);
+ }
+
+ @Test
+ public void testFormatZKStringOneServer() {
+ when(zkWatcher.getQuorum()).thenReturn("127.0.0.1:21818");
+ String result = ZKStringFormatter.formatZKString(zkWatcher);
+ assertEquals("127.0.0.1:21818", result);
+ }
+
+ @Test
+ public void testFormatZKStringMultipleServers() {
+ when(zkWatcher.getQuorum()).thenReturn("127.0.0.1:21818,127.0.0.1:21819,127.0.0.1:21820");
+ String result = ZKStringFormatter.formatZKString(zkWatcher);
+ assertEquals("127.0.0.1:21818<br/>127.0.0.1:21819<br/>127.0.0.1:21820", result);
+ }
+}
diff --git a/hbase-shell/src/main/ruby/hbase/taskmonitor.rb b/hbase-shell/src/main/ruby/hbase/taskmonitor.rb
index c9cb042d341..fb2c6874775 100644
--- a/hbase-shell/src/main/ruby/hbase/taskmonitor.rb
+++ b/hbase-shell/src/main/ruby/hbase/taskmonitor.rb
@@ -80,14 +80,16 @@ module Hbase
infoport = @admin.getClusterMetrics.getLiveServerMetrics.get(host).getInfoServerPort.to_s
+ tasks_json_path = '/regionserver.jsp?format=json&filter='
+
begin
schema = "http://"
- url = schema + host.hostname + ':' + infoport + '/rs-status?format=json&filter=' + filter
+ url = schema + host.hostname + ':' + infoport + tasks_json_path + filter
json = URL.new(url).openStream
rescue SocketException => e
# Let's try with https when SocketException occur
schema = "https://"
- url = schema + host.hostname + ':' + infoport + '/rs-status?format=json&filter=' + filter
+ url = schema + host.hostname + ':' + infoport + tasks_json_path + filter
json = URL.new(url).openStream
end