From 46d64afcd9d17c9b21559babc861da0c5149aafb Mon Sep 17 00:00:00 2001 From: Todd Lipcon Date: Tue, 3 May 2011 19:07:00 +0000 Subject: [PATCH] HBASE-3835 Switch master and region server pages to Jamon-based templates git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1099198 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 1 + pom.xml | 47 ++++ .../hbase/tmpl/master/MasterStatusTmpl.jamon | 201 ++++++++++++++++++ .../tmpl/regionserver/RSStatusTmpl.jamon | 104 +++++++++ .../apache/hadoop/hbase/master/HMaster.java | 1 + .../hbase/master/MasterStatusServlet.java | 102 +++++++++ .../hbase/regionserver/HRegionServer.java | 3 +- .../hbase/regionserver/RSStatusServlet.java | 46 ++++ .../resources/hbase-webapps/master/index.html | 2 +- .../resources/hbase-webapps/master/master.jsp | 169 +-------------- .../hbase-webapps/regionserver/index.html | 2 +- .../regionserver/regionserver.jsp | 80 +------ .../hbase/master/TestMasterStatusServlet.java | 123 +++++++++++ .../regionserver/TestRSStatusServlet.java | 94 ++++++++ 14 files changed, 725 insertions(+), 250 deletions(-) create mode 100644 src/main/jamon/org/apache/hbase/tmpl/master/MasterStatusTmpl.jamon create mode 100644 src/main/jamon/org/apache/hbase/tmpl/regionserver/RSStatusTmpl.jamon create mode 100644 src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java create mode 100644 src/main/java/org/apache/hadoop/hbase/regionserver/RSStatusServlet.java create mode 100644 src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java create mode 100644 src/test/java/org/apache/hadoop/hbase/regionserver/TestRSStatusServlet.java diff --git a/CHANGES.txt b/CHANGES.txt index 8e21b146e73..24e011768f9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -203,6 +203,7 @@ Release 0.91.0 - Unreleased HBASE-3796 Per-Store Enties in Compaction Queue HBASE-3670 Fix error handling in get(List gets) (Harsh J Chouraria) + HBASE-3835 Switch master and region server pages to Jamon-based templates TASKS HBASE-3559 Move report of split to master OFF the heartbeat channel diff --git a/pom.xml b/pom.xml index 7e6b493410b..48d5ef847ec 100644 --- a/pom.xml +++ b/pom.xml @@ -511,6 +511,47 @@ + + org.jamon + jamon-maven-plugin + 2.3.4 + + + generate-sources + + translate + + + src/main/jamon + target/generated-jamon + + + + + + org.apache.maven.plugins + maven-eclipse-plugin + + + org.jamon.project.jamonnature + + + org.jamon.project.templateBuilder + org.eclipse.jdt.core.javabuilder + org.jamon.project.markerUpdater + + + + .settings/org.jamon.prefs + # now + eclipse.preferences.version=1 + templateSourceDir=src/main/jamon + templateOutputDir=target/generated-jamon + + + + + @@ -771,6 +812,12 @@ + + org.jamon + jamon-runtime + 2.3.1 + + com.google.protobuf diff --git a/src/main/jamon/org/apache/hbase/tmpl/master/MasterStatusTmpl.jamon b/src/main/jamon/org/apache/hbase/tmpl/master/MasterStatusTmpl.jamon new file mode 100644 index 00000000000..4b1b4f44529 --- /dev/null +++ b/src/main/jamon/org/apache/hbase/tmpl/master/MasterStatusTmpl.jamon @@ -0,0 +1,201 @@ +<%doc> +Copyright 2011 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. + +<%args> +HMaster master; +HBaseAdmin admin; +Map frags = null; +ServerName rootLocation = null; +ServerName metaLocation = null; +List servers = null; +boolean showAppendWarning = false; + +<%import> +java.util.*; +org.apache.hadoop.util.StringUtils; +org.apache.hadoop.hbase.util.Bytes; +org.apache.hadoop.hbase.util.JvmVersion; +org.apache.hadoop.hbase.util.FSUtils; +org.apache.hadoop.hbase.master.HMaster; +org.apache.hadoop.hbase.HConstants; +org.apache.hadoop.hbase.HServerLoad; +org.apache.hadoop.hbase.ServerName; +org.apache.hadoop.hbase.client.HBaseAdmin; +org.apache.hadoop.hbase.client.HConnectionManager; +org.apache.hadoop.hbase.HTableDescriptor; + + + + + +HBase Master: <% master.getServerName().getHostAndPort() %> + + + + +

Master: <% master.getServerName().getHostname() %>:<% master.getServerName().getPort() %>

+ + + +<%if JvmVersion.isBadJvmVersion() %> +
+ Your current JVM version <% System.getProperty("java.version") %> is known to be + unstable with HBase. Please see the + HBase wiki + for details. +
+ +<%if showAppendWarning %> +
+ You are currently running the HMaster without HDFS append support enabled. + This may result in data loss. + Please see the HBase wiki + for details. +
+ + +
+ +

Master Attributes

+ + + + + + + + + +<%if frags != null %> + + + +
Attribute NameValueDescription
HBase Version<% org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, r<% org.apache.hadoop.hbase.util.VersionInfo.getRevision() %>HBase version and svn revision
HBase Compiled<% org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <% org.apache.hadoop.hbase.util.VersionInfo.getUser() %>When HBase version was compiled and by whom
Hadoop Version<% org.apache.hadoop.util.VersionInfo.getVersion() %>, r<% org.apache.hadoop.util.VersionInfo.getRevision() %>Hadoop version and svn revision
Hadoop Compiled<% org.apache.hadoop.util.VersionInfo.getDate() %>, <% org.apache.hadoop.util.VersionInfo.getUser() %>When Hadoop version was compiled and by whom
HBase Root Directory<% FSUtils.getRootDir(master.getConfiguration()).toString() %>Location of HBase home directory
HBase Cluster ID<% master.getClusterId() != null ? master.getClusterId() : "Not set" %>Unique identifier generated for each HBase cluster
Load average<% StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %>Average number of regions per regionserver. Naive computation.
Fragmentation<% frags.get("-TOTAL-") != null ? frags.get("-TOTAL-").intValue() + "%" : "n/a" %>Overall fragmentation of all tables, including .META. and -ROOT-.
Zookeeper Quorum<% master.getZooKeeperWatcher().getQuorum() %>Addresses of all registered ZK servers. For more, see zk dump.
+<%if (rootLocation != null) %> +<& catalogTables &> + +<%if (metaLocation != null) %> +<& userTables &> + +<%if (servers != null) %> +<& regionServers &> + + + + + +<%def catalogTables> +

Catalog Tables

+ + + + <%if (frags != null) %> + + + + + + + <%if (frags != null)%> + + + + + <%if (metaLocation != null) %> + + + <%if (frags != null)%> + + + + + + +
TableFrag.Description
<% Bytes.toString(HConstants.ROOT_TABLE_NAME) %><% frags.get("-ROOT-") != null ? frags.get("-ROOT-").intValue() + "%" : "n/a" %>The -ROOT- table holds references to all .META. regions.
<% Bytes.toString(HConstants.META_TABLE_NAME) %><% frags.get(".META.") != null ? frags.get(".META.").intValue() + "%" : "n/a" %>The .META. table holds references to all User Table regions
+ + +<%def userTables> +

User Tables

+<%java> + HTableDescriptor[] tables = admin.listTables(); + HConnectionManager.deleteConnection(admin.getConfiguration(), false); + +<%if (tables != null && tables.length > 0)%> + + + +<%if (frags != null) %> + + + + +<%for HTableDescriptor htDesc : tables%> + + + <%if (frags != null) %> + + + + + + +

<% tables.length %> table(s) in set.

+
TableFrag.Description
><% htDesc.getNameAsString() %> <% frags.get(htDesc.getNameAsString()) != null ? frags.get(htDesc.getNameAsString()).intValue() + "%" : "n/a" %><% htDesc.toString() %>
+ + + +<%def regionServers> +

Region Servers

+<%if (servers != null && servers.size() > 0)%> +<%java> + int totalRegions = 0; + int totalRequests = 0; + + + + +<%java> + ServerName [] serverNames = servers.toArray(new ServerName[servers.size()]); + Arrays.sort(serverNames); + for (ServerName serverName: serverNames) { + // TODO: this is incorrect since this conf might differ from RS to RS + // or be set to 0 to get ephemeral ports + int infoPort = conf.getInt("hbase.regionserver.info.port", 60030); + String hostname = serverName.getHostname() + ":" + infoPort; + String hostname = serverName.getHostname() + ":60030"; + String url = "http://" + hostname + "/"; + HServerLoad hsl = master.getServerManager().getLoad(serverName); + String loadStr = hsl == null? "-": hsl.toString(); + if (hsl != null) { + totalRegions += hsl.getNumberOfRegions(); + totalRequests += hsl.getNumberOfRequests(); + } + long startCode = serverName.getStartcode(); + + +<%java> + } + + +
AddressStart CodeLoad
<% hostname %><% startCode %><% serverName %><% loadStr %>
Total: servers: <% servers.size() %> requests=<% totalRequests %>, regions=<% totalRegions %>
+ +

Load is requests per second and count of regions loaded

+ + diff --git a/src/main/jamon/org/apache/hbase/tmpl/regionserver/RSStatusTmpl.jamon b/src/main/jamon/org/apache/hbase/tmpl/regionserver/RSStatusTmpl.jamon new file mode 100644 index 00000000000..617c8dc35ae --- /dev/null +++ b/src/main/jamon/org/apache/hbase/tmpl/regionserver/RSStatusTmpl.jamon @@ -0,0 +1,104 @@ +<%doc> +Copyright 2011 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. + +<%args> +HRegionServer regionServer; + +<%import> +java.util.*; +java.io.IOException; +org.apache.hadoop.io.Text; +org.apache.hadoop.hbase.regionserver.HRegionServer; +org.apache.hadoop.hbase.regionserver.HRegion; +org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics; +org.apache.hadoop.hbase.util.Bytes; +org.apache.hadoop.hbase.HConstants; +org.apache.hadoop.hbase.HServerInfo; +org.apache.hadoop.hbase.HServerLoad; +org.apache.hadoop.hbase.HRegionInfo; + +<%java> + HServerInfo serverInfo = null; + try { + serverInfo = regionServer.getHServerInfo(); + } catch (IOException e) { + e.printStackTrace(); + } + RegionServerMetrics metrics = regionServer.getMetrics(); + List onlineRegions = regionServer.getOnlineRegions(); + int interval = regionServer.getConfiguration().getInt("hbase.regionserver.msginterval", 3000)/1000; + + + + + +HBase Region Server: <% serverInfo.getServerAddress().getHostname() %>:<% serverInfo.getServerAddress().getPort() %> + + + + + +

Region Server: <% serverInfo.getServerAddress().getHostname() %>:<% serverInfo.getServerAddress().getPort() %>

+ +
+ +

Region Server Attributes

+ + + + + + +
Attribute NameValueDescription
HBase Version<% org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, r<% org.apache.hadoop.hbase.util.VersionInfo.getRevision() %>HBase version and svn revision
HBase Compiled<% org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <% org.apache.hadoop.hbase.util.VersionInfo.getUser() %>When HBase version was compiled and by whom
Metrics<% metrics.toString() %>RegionServer Metrics; file and heap sizes are in megabytes
Zookeeper Quorum<% regionServer.getZooKeeper().getQuorum() %>Addresses of all registered ZK servers
+ +

Online Regions

+<%if (onlineRegions != null && onlineRegions.size() > 0) %> + + +<%java> + Collections.sort(onlineRegions); + +<%for HRegionInfo r: onlineRegions %> +<%java> + HServerLoad.RegionLoad load = regionServer.createRegionLoad(r.getEncodedName()); + + + + + + +
Region NameStart KeyEnd KeyMetrics
<% r.getRegionNameAsString() %><% Bytes.toStringBinary(r.getStartKey()) %><% Bytes.toStringBinary(r.getEndKey()) %><% load == null? "null": load.toString() %>
+

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 +domains,apache.org,5464829424211263407 is party to the table +domains, has an id of 5464829424211263407 and the first key +in the region is apache.org. The -ROOT- +and .META. 'tables' are internal sytem tables (or 'catalog' tables in db-speak). +The -ROOT- keeps a list of all regions in the .META. table. The .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 region has both an empty start and an empty end key, its the only region in the table. See +HBase Home for further explication.

+<%else> +

Not serving regions

+ + + \ No newline at end of file diff --git a/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index bcd258da68e..68b18c2fd20 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -597,6 +597,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { if (port >= 0) { String a = this.conf.get("hbase.master.info.bindAddress", "0.0.0.0"); this.infoServer = new InfoServer(MASTER, a, port, false); + this.infoServer.addServlet("status", "/master-status", MasterStatusServlet.class); this.infoServer.setAttribute(MASTER, this); this.infoServer.start(); } diff --git a/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java b/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java new file mode 100644 index 00000000000..b63dc2abe29 --- /dev/null +++ b/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java @@ -0,0 +1,102 @@ +/** + * Copyright 2011 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. + */ +package org.apache.hadoop.hbase.master; + +import java.io.IOException; + +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.util.FSUtils; +import org.apache.hbase.tmpl.master.MasterStatusTmpl; + +/** + * The servlet responsible for rendering the index page of the + * master. + */ +public class MasterStatusServlet extends HttpServlet { + private static final Log LOG = LogFactory.getLog(MasterStatusServlet.class); + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws IOException + { + HMaster master = (HMaster) getServletContext().getAttribute(HMaster.MASTER); + assert master != null : "No Master in context!"; + + Configuration conf = master.getConfiguration(); + HBaseAdmin admin = new HBaseAdmin(conf); + + Map frags = getFragmentationInfo(master, conf); + + ServerName rootLocation = getRootLocationOrNull(master); + ServerName metaLocation = master.getCatalogTracker().getMetaLocation(); + List servers = master.getServerManager().getOnlineServersList(); + + response.setContentType("text/html"); + new MasterStatusTmpl() + .setFrags(frags) + .setShowAppendWarning(shouldShowAppendWarning(conf)) + .setRootLocation(rootLocation) + .setMetaLocation(metaLocation) + .setServers(servers) + .render(response.getWriter(), + master, admin); + } + + private ServerName getRootLocationOrNull(HMaster master) { + try { + return master.getCatalogTracker().getRootLocation(); + } catch (InterruptedException e) { + LOG.warn("Unable to get root location", e); + return null; + } + } + + private Map getFragmentationInfo( + HMaster master, Configuration conf) throws IOException { + boolean showFragmentation = conf.getBoolean( + "hbase.master.ui.fragmentation.enabled", false); + if (showFragmentation) { + return FSUtils.getTableFragmentation(master); + } else { + return null; + } + } + + static boolean shouldShowAppendWarning(Configuration conf) { + try { + return !FSUtils.isAppendSupported(conf) && FSUtils.isHDFS(conf); + } catch (IOException e) { + LOG.warn("Unable to determine if append is supported", e); + return false; + } + } +} diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 80e89ae4d4f..b910254d692 100644 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -1286,7 +1286,8 @@ public class HRegionServer implements HRegionInterface, HBaseRPCErrorHandler, while (true) { try { this.infoServer = new InfoServer("regionserver", addr, port, false); - this.infoServer.setAttribute("regionserver", this); + this.infoServer.addServlet("status", "/rs-status", RSStatusServlet.class); + this.infoServer.setAttribute(REGIONSERVER, this); this.infoServer.start(); break; } catch (BindException e) { diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/RSStatusServlet.java b/src/main/java/org/apache/hadoop/hbase/regionserver/RSStatusServlet.java new file mode 100644 index 00000000000..e8c2b95325f --- /dev/null +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/RSStatusServlet.java @@ -0,0 +1,46 @@ +/** + * Copyright 2011 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. + */ +package org.apache.hadoop.hbase.regionserver; + +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.hbase.tmpl.regionserver.RSStatusTmpl; + +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!"; + + resp.setContentType("text/html"); + new RSStatusTmpl().render(resp.getWriter(), hrs); + } + +} diff --git a/src/main/resources/hbase-webapps/master/index.html b/src/main/resources/hbase-webapps/master/index.html index 6d301abab97..2c8115b6944 100644 --- a/src/main/resources/hbase-webapps/master/index.html +++ b/src/main/resources/hbase-webapps/master/index.html @@ -1 +1 @@ - + diff --git a/src/main/resources/hbase-webapps/master/master.jsp b/src/main/resources/hbase-webapps/master/master.jsp index 8cafdeb5961..2c8115b6944 100644 --- a/src/main/resources/hbase-webapps/master/master.jsp +++ b/src/main/resources/hbase-webapps/master/master.jsp @@ -1,168 +1 @@ -<%@ page contentType="text/html;charset=UTF-8" - import="java.util.*" - import="org.apache.hadoop.conf.Configuration" - import="org.apache.hadoop.util.StringUtils" - import="org.apache.hadoop.hbase.util.Bytes" - import="org.apache.hadoop.hbase.util.JvmVersion" - import="org.apache.hadoop.hbase.util.FSUtils" - import="org.apache.hadoop.hbase.master.HMaster" - import="org.apache.hadoop.hbase.HConstants" - import="org.apache.hadoop.hbase.ServerName" - import="org.apache.hadoop.hbase.HServerLoad" - import="org.apache.hadoop.hbase.client.HBaseAdmin" - import="org.apache.hadoop.hbase.client.HConnectionManager" - import="org.apache.hadoop.hbase.HTableDescriptor" %><% - HMaster master = (HMaster)getServletContext().getAttribute(HMaster.MASTER); - Configuration conf = master.getConfiguration(); - ServerName rootLocation = master.getCatalogTracker().getRootLocation(); - boolean metaOnline = master.getCatalogTracker().getMetaLocation() != null; - List servers = master.getServerManager().getOnlineServersList(); - int interval = conf.getInt("hbase.regionserver.msginterval", 1000)/1000; - if (interval == 0) { - interval = 1; - } - boolean showFragmentation = conf.getBoolean("hbase.master.ui.fragmentation.enabled", false); - Map frags = null; - if (showFragmentation) { - frags = FSUtils.getTableFragmentation(master); - } -%> - - - -HBase Master: <%= master.getServerName().getHostAndPort() %> - - - - -

Master: <%=master.getServerName().getHostname()%>:<%=master.getServerName().getPort()%>

- - - -<% if (JvmVersion.isBadJvmVersion()) { %> -
- Your current JVM version <%= System.getProperty("java.version") %> is known to be - unstable with HBase. Please see the - HBase wiki - for details. -
-<% } %> -<% if (!FSUtils.isAppendSupported(conf) && FSUtils.isHDFS(conf)) { %> -
- You are currently running the HMaster without HDFS append support enabled. - This may result in data loss. - Please see the HBase wiki - for details. -
-<% } %> - -
- -

Master Attributes

- - - - - - - - - -<% if (showFragmentation) { %> - -<% } %> - -
Attribute NameValueDescription
HBase Version<%= org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, r<%= org.apache.hadoop.hbase.util.VersionInfo.getRevision() %>HBase version and svn revision
HBase Compiled<%= org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <%= org.apache.hadoop.hbase.util.VersionInfo.getUser() %>When HBase version was compiled and by whom
Hadoop Version<%= org.apache.hadoop.util.VersionInfo.getVersion() %>, r<%= org.apache.hadoop.util.VersionInfo.getRevision() %>Hadoop version and svn revision
Hadoop Compiled<%= org.apache.hadoop.util.VersionInfo.getDate() %>, <%= org.apache.hadoop.util.VersionInfo.getUser() %>When Hadoop version was compiled and by whom
HBase Root Directory<%= FSUtils.getRootDir(master.getConfiguration()).toString() %>Location of HBase home directory
HBase Cluster ID<%= master.getClusterId() != null ? master.getClusterId() : "Not set" %>Unique identifier generated for each HBase cluster
Load average<%= StringUtils.limitDecimalTo2(master.getServerManager().getAverageLoad()) %>Average number of regions per regionserver. Naive computation.
Fragmentation<%= frags.get("-TOTAL-") != null ? frags.get("-TOTAL-").intValue() + "%" : "n/a" %>Overall fragmentation of all tables, including .META. and -ROOT-.
Zookeeper Quorum<%= master.getZooKeeperWatcher().getQuorum() %>Addresses of all registered ZK servers. For more, see zk dump.
- -

Catalog Tables

-<% - if (rootLocation != null) { %> - - - -<% if (showFragmentation) { %> - -<% } %> - - - - -<% if (showFragmentation) { %> - -<% } %> - - -<% - if (metaOnline) { %> - - -<% if (showFragmentation) { %> - -<% } %> - - - -<% } %> -
TableFrag.Description
<%= Bytes.toString(HConstants.ROOT_TABLE_NAME) %><%= frags.get("-ROOT-") != null ? frags.get("-ROOT-").intValue() + "%" : "n/a" %>The -ROOT- table holds references to all .META. regions.
<%= Bytes.toString(HConstants.META_TABLE_NAME) %><%= frags.get(".META.") != null ? frags.get(".META.").intValue() + "%" : "n/a" %>The .META. table holds references to all User Table regions
-<%} %> - -

User Tables

-<% - HBaseAdmin hba = new HBaseAdmin(conf); - HTableDescriptor[] tables = hba.listTables(); - HConnectionManager.deleteConnection(hba.getConfiguration(), false); - if(tables != null && tables.length > 0) { %> - - - -<% if (showFragmentation) { %> - -<% } %> - - -<% for(HTableDescriptor htDesc : tables ) { %> - - -<% if (showFragmentation) { %> - -<% } %> - - -<% } %> - -

<%= tables.length %> table(s) in set.

-
TableFrag.Description
><%= htDesc.getNameAsString() %> <%= frags.get(htDesc.getNameAsString()) != null ? frags.get(htDesc.getNameAsString()).intValue() + "%" : "n/a" %><%= htDesc.toString() %>
-<% } %> - -

Region Servers

-<% if (servers != null && servers.size() > 0) { %> -<% int totalRegions = 0; - int totalRequests = 0; -%> - - - -<% ServerName [] serverNames = servers.toArray(new ServerName[servers.size()]); - Arrays.sort(serverNames); - for (ServerName serverName: serverNames) { - int infoPort = conf.getInt("hbase.regionserver.info.port", 60030); - String hostname = serverName.getHostname() + ":" + infoPort; - String url = "http://" + hostname + "/"; - HServerLoad hsl = master.getServerManager().getLoad(serverName); - String loadStr = hsl == null? "-": hsl.toString(); - if (hsl != null) { - totalRegions += hsl.getNumberOfRegions(); - totalRequests += hsl.getNumberOfRequests(); - } - long startCode = serverName.getStartcode(); -%> - -<% } %> - -
AddressStart CodeLoad
<%= hostname %><%= startCode %><%= serverName %><%= loadStr %>
Total: servers: <%= servers.size() %> requests=<%= totalRequests %>, regions=<%= totalRegions %>
- -

Load is requests per second and count of regions loaded

-<% } %> - - + diff --git a/src/main/resources/hbase-webapps/regionserver/index.html b/src/main/resources/hbase-webapps/regionserver/index.html index bdd3c6a561e..78d6d2e1111 100644 --- a/src/main/resources/hbase-webapps/regionserver/index.html +++ b/src/main/resources/hbase-webapps/regionserver/index.html @@ -1 +1 @@ - + diff --git a/src/main/resources/hbase-webapps/regionserver/regionserver.jsp b/src/main/resources/hbase-webapps/regionserver/regionserver.jsp index 7995e91d1a4..bf6f6e2dcf3 100644 --- a/src/main/resources/hbase-webapps/regionserver/regionserver.jsp +++ b/src/main/resources/hbase-webapps/regionserver/regionserver.jsp @@ -1,79 +1 @@ -<%@ page contentType="text/html;charset=UTF-8" - import="java.util.*" - import="java.io.IOException" - import="org.apache.hadoop.io.Text" - import="org.apache.hadoop.hbase.regionserver.HRegionServer" - import="org.apache.hadoop.hbase.regionserver.HRegion" - import="org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics" - import="org.apache.hadoop.hbase.util.Bytes" - import="org.apache.hadoop.hbase.HConstants" - import="org.apache.hadoop.hbase.HServerInfo" - import="org.apache.hadoop.hbase.HServerLoad" - import="org.apache.hadoop.hbase.HRegionInfo" %><% - HRegionServer regionServer = (HRegionServer)getServletContext().getAttribute(HRegionServer.REGIONSERVER); - HServerInfo serverInfo = null; - try { - serverInfo = regionServer.getHServerInfo(); - } catch (IOException e) { - e.printStackTrace(); - } - RegionServerMetrics metrics = regionServer.getMetrics(); - List onlineRegions = regionServer.getOnlineRegions(); - int interval = regionServer.getConfiguration().getInt("hbase.regionserver.msginterval", 3000)/1000; - -%> - - - -HBase Region Server: <%= serverInfo.getServerAddress().getHostname() %>:<%= serverInfo.getServerAddress().getPort() %> - - - - - -

Region Server: <%= serverInfo.getServerAddress().getHostname() %>:<%= serverInfo.getServerAddress().getPort() %>

- -
- -

Region Server Attributes

- - - - - - -
Attribute NameValueDescription
HBase Version<%= org.apache.hadoop.hbase.util.VersionInfo.getVersion() %>, r<%= org.apache.hadoop.hbase.util.VersionInfo.getRevision() %>HBase version and svn revision
HBase Compiled<%= org.apache.hadoop.hbase.util.VersionInfo.getDate() %>, <%= org.apache.hadoop.hbase.util.VersionInfo.getUser() %>When HBase version was compiled and by whom
Metrics<%= metrics.toString() %>RegionServer Metrics; file and heap sizes are in megabytes
Zookeeper Quorum<%= regionServer.getZooKeeper().getQuorum() %>Addresses of all registered ZK servers
- -

Online Regions

-<% if (onlineRegions != null && onlineRegions.size() > 0) { %> - - -<% - Collections.sort(onlineRegions); - for (HRegionInfo r: onlineRegions) { - HServerLoad.RegionLoad load = regionServer.createRegionLoad(r.getEncodedName()); - %> - - - - -<% } %> -
Region NameStart KeyEnd KeyMetrics
<%= r.getRegionNameAsString() %><%= Bytes.toStringBinary(r.getStartKey()) %><%= Bytes.toStringBinary(r.getEndKey()) %><%= load == null? "null": load.toString() %>
-

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 -domains,apache.org,5464829424211263407 is party to the table -domains, has an id of 5464829424211263407 and the first key -in the region is apache.org. The -ROOT- -and .META. 'tables' are internal sytem tables (or 'catalog' tables in db-speak). -The -ROOT- keeps a list of all regions in the .META. table. The .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 region has both an empty start and an empty end key, its the only region in the table. See -HBase Home for further explication.

-<% } else { %> -

Not serving regions

-<% } %> - - + \ No newline at end of file diff --git a/src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java b/src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java new file mode 100644 index 00000000000..d2697c8aeef --- /dev/null +++ b/src/test/java/org/apache/hadoop/hbase/master/TestMasterStatusServlet.java @@ -0,0 +1,123 @@ +/** + * Copyright 2011 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. + */ +package org.apache.hadoop.hbase.master; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.master.HMaster; +import org.apache.hadoop.hbase.master.ServerManager; +import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; +import org.apache.hbase.tmpl.master.MasterStatusTmpl; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.google.common.collect.Lists; + +/** + * Tests for the master status page and its template. + */ +public class TestMasterStatusServlet { + + private HMaster master; + private Configuration conf; + private HBaseAdmin admin; + + @Before + public void setupBasicMocks() { + conf = HBaseConfiguration.create(); + + master = Mockito.mock(HMaster.class); + Mockito.doReturn(new ServerName("fakehost", 12345, 1234567890)) + .when(master).getServerName(); + Mockito.doReturn(conf).when(master).getConfiguration(); + + // Fake serverManager + ServerManager serverManager = Mockito.mock(ServerManager.class); + Mockito.doReturn(1.0).when(serverManager).getAverageLoad(); + Mockito.doReturn(serverManager).when(master).getServerManager(); + + // Fake ZKW + ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class); + Mockito.doReturn("fakequorum").when(zkw).getQuorum(); + Mockito.doReturn(zkw).when(master).getZooKeeperWatcher(); + + // Mock admin + admin = Mockito.mock(HBaseAdmin.class); + } + + + private void setupMockTables() throws IOException { + HTableDescriptor tables[] = new HTableDescriptor[] { + new HTableDescriptor("foo"), + new HTableDescriptor("bar") + }; + Mockito.doReturn(tables).when(admin).listTables(); + } + + @Test + public void testStatusTemplateNoTables() throws IOException { + new MasterStatusTmpl().render(new StringWriter(), + master, admin); + } + + @Test + public void testStatusTemplateRootAvailable() throws IOException { + new MasterStatusTmpl() + .setRootLocation(new ServerName("rootserver:123,12345")) + .render(new StringWriter(), + master, admin); + } + + @Test + public void testStatusTemplateRootAndMetaAvailable() throws IOException { + setupMockTables(); + + new MasterStatusTmpl() + .setRootLocation(new ServerName("rootserver:123,12345")) + .setMetaLocation(new ServerName("metaserver:123,12345")) + .render(new StringWriter(), + master, admin); + } + + @Test + public void testStatusTemplateWithServers() throws IOException { + setupMockTables(); + + List servers = Lists.newArrayList( + new ServerName("rootserver:123,12345"), + new ServerName("metaserver:123,12345")); + + new MasterStatusTmpl() + .setRootLocation(new ServerName("rootserver:123,12345")) + .setMetaLocation(new ServerName("metaserver:123,12345")) + .setServers(servers) + .render(new StringWriter(), + master, admin); + } + +} diff --git a/src/test/java/org/apache/hadoop/hbase/regionserver/TestRSStatusServlet.java b/src/test/java/org/apache/hadoop/hbase/regionserver/TestRSStatusServlet.java new file mode 100644 index 00000000000..40d352e2f69 --- /dev/null +++ b/src/test/java/org/apache/hadoop/hbase/regionserver/TestRSStatusServlet.java @@ -0,0 +1,94 @@ +/** + * Copyright 2011 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. + */ +package org.apache.hadoop.hbase.regionserver; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; + +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HServerAddress; +import org.apache.hadoop.hbase.HServerInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.regionserver.metrics.RegionServerMetrics; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher; +import org.apache.hbase.tmpl.regionserver.RSStatusTmpl; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.google.common.collect.Lists; + +/** + * Tests for the region server status page and its template. + */ +public class TestRSStatusServlet { + private HRegionServer rs; + + static final int FAKE_IPC_PORT = 1585; + static final int FAKE_WEB_PORT = 1586; + + @SuppressWarnings("deprecation") + private HServerAddress fakeAddress = + new HServerAddress("localhost", FAKE_IPC_PORT); + @SuppressWarnings("deprecation") + private HServerInfo fakeInfo = + new HServerInfo(fakeAddress, FAKE_WEB_PORT); + private RegionServerMetrics metrics = + new RegionServerMetrics(); + + @SuppressWarnings("deprecation") + @Before + public void setupBasicMocks() throws IOException { + rs = Mockito.mock(HRegionServer.class); + Mockito.doReturn(HBaseConfiguration.create()) + .when(rs).getConfiguration(); + Mockito.doReturn(fakeInfo).when(rs).getHServerInfo(); + Mockito.doReturn(metrics).when(rs).getMetrics(); + + // Fake ZKW + ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class); + Mockito.doReturn("fakequorum").when(zkw).getQuorum(); + Mockito.doReturn(zkw).when(rs).getZooKeeper(); + } + + @Test + public void testBasic() throws IOException { + new RSStatusTmpl().render(new StringWriter(), rs); + } + + @Test + public void testWithRegions() throws IOException { + HTableDescriptor htd = new HTableDescriptor("mytable"); + List regions = Lists.newArrayList( + new HRegionInfo(htd, Bytes.toBytes("a"), Bytes.toBytes("d")), + new HRegionInfo(htd, Bytes.toBytes("d"), Bytes.toBytes("z")) + ); + Mockito.doReturn(regions).when(rs).getOnlineRegions(); + + new RSStatusTmpl().render(new StringWriter(), rs); + } + + +}