From 0ac601263a54149f97484d273a66916778e0f104 Mon Sep 17 00:00:00 2001 From: Sean Busbey Date: Tue, 19 May 2015 00:06:29 -0500 Subject: [PATCH] HBASE-13710 Remove dependency on Hadoop's ReflectionUtil. --- .../apache/hadoop/hbase/util/ReflectionUtils.java | 98 ++++++++++++++++++++ .../org/apache/hadoop/hbase/http/HttpServer.java | 2 +- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ReflectionUtils.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ReflectionUtils.java index 5e8980d..650c544 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ReflectionUtils.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ReflectionUtils.java @@ -18,8 +18,17 @@ */ package org.apache.hadoop.hbase.util; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; + +import org.apache.commons.logging.Log; import org.apache.hadoop.hbase.classification.InterfaceAudience; @@ -89,4 +98,93 @@ public class ReflectionUtils { throw new UnsupportedOperationException( "Unable to find suitable constructor for class " + type.getName()); } + + /* synchronized on ReflectionUtils.class */ + private static long previousLogTime = 0; + private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + + /** + * Log the current thread stacks at INFO level. + * @param log the logger that logs the stack trace + * @param title a descriptive title for the call stacks + * @param minInterval the minimum time from the last + */ + public static void logThreadInfo(Log log, + String title, + long minInterval) { + boolean dumpStack = false; + if (log.isInfoEnabled()) { + synchronized (ReflectionUtils.class) { + long now = System.currentTimeMillis(); + if (now - previousLogTime >= minInterval * 1000) { + previousLogTime = now; + dumpStack = true; + } + } + if (dumpStack) { + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + printThreadInfo(new PrintStream(buffer, false, "UTF-8"), title); + log.info(buffer.toString(Charset.defaultCharset().name())); + } catch (UnsupportedEncodingException ignored) { + log.warn("Could not write thread info about '" + title + + "' due to a string encoding issue."); + } + } + } + } + + /** + * Print all of the thread's information and stack traces. + * + * @param stream the stream to + * @param title a string title for the stack trace + */ + private static void printThreadInfo(PrintStream stream, + String title) { + final int STACK_DEPTH = 20; + boolean contention = threadBean.isThreadContentionMonitoringEnabled(); + long[] threadIds = threadBean.getAllThreadIds(); + stream.println("Process Thread Dump: " + title); + stream.println(threadIds.length + " active threads"); + for (long tid: threadIds) { + ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH); + if (info == null) { + stream.println(" Inactive"); + continue; + } + stream.println("Thread " + + getTaskName(info.getThreadId(), + info.getThreadName()) + ":"); + Thread.State state = info.getThreadState(); + stream.println(" State: " + state); + stream.println(" Blocked count: " + info.getBlockedCount()); + stream.println(" Waited count: " + info.getWaitedCount()); + if (contention) { + stream.println(" Blocked time: " + info.getBlockedTime()); + stream.println(" Waited time: " + info.getWaitedTime()); + } + if (state == Thread.State.WAITING) { + stream.println(" Waiting on " + info.getLockName()); + } else if (state == Thread.State.BLOCKED) { + stream.println(" Blocked on " + info.getLockName()); + stream.println(" Blocked by " + + getTaskName(info.getLockOwnerId(), + info.getLockOwnerName())); + } + stream.println(" Stack:"); + for (StackTraceElement frame: info.getStackTrace()) { + stream.println(" " + frame.toString()); + } + } + stream.flush(); + } + + private static String getTaskName(long id, String name) { + if (name == null) { + return Long.toString(id); + } + return id + " (" + name + ")"; + } + } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java index e2688b1..39bced5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java @@ -57,12 +57,12 @@ import org.apache.hadoop.hbase.http.conf.ConfServlet; import org.apache.hadoop.hbase.http.jmx.JMXJsonServlet; import org.apache.hadoop.hbase.http.log.LogLevel; import org.apache.hadoop.hbase.util.Threads; +import org.apache.hadoop.hbase.util.ReflectionUtils; import org.apache.hadoop.metrics.MetricsServlet; import org.apache.hadoop.security.SecurityUtil; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; import org.apache.hadoop.security.authorize.AccessControlList; -import org.apache.hadoop.util.ReflectionUtils; import org.apache.hadoop.util.Shell; import org.mortbay.io.Buffer; import org.mortbay.jetty.Connector; -- 1.7.10.2 (Apple Git-33)