HBASE-7086 Enhance ResourceChecker to log stack trace for potentially hanging threads

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1405443 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Zhihong Yu 2012-11-04 00:20:27 +00:00
parent d3d763ca51
commit 73911b1740
3 changed files with 64 additions and 15 deletions

View File

@ -24,7 +24,6 @@ import org.apache.commons.logging.LogFactory;
import java.util.*; import java.util.*;
/** /**
* Utility class to check the resources: * Utility class to check the resources:
* - log them before and after each test method * - log them before and after each test method
@ -35,6 +34,10 @@ public class ResourceChecker {
private static final Log LOG = LogFactory.getLog(ResourceChecker.class); private static final Log LOG = LogFactory.getLog(ResourceChecker.class);
private String tagLine; private String tagLine;
enum Phase {
INITIAL, INTERMEDIATE, END
}
/** /**
* Constructor * Constructor
* @param tagLine - the tagLine is added to the logs. Must be be null. * @param tagLine - the tagLine is added to the logs. Must be be null.
@ -80,10 +83,15 @@ public class ResourceChecker {
/** /**
* The value for the resource. * The value for the resource.
* @param phase
*/ */
abstract public int getVal(); abstract public int getVal(Phase phase);
}
/*
* Retrieves List of Strings which would be logged in logEndings()
*/
public List<String> getStringsToLog() { return null; }
}
private List<ResourceAnalyzer> ras = new ArrayList<ResourceAnalyzer>(); private List<ResourceAnalyzer> ras = new ArrayList<ResourceAnalyzer>();
private int[] initialValues; private int[] initialValues;
@ -92,18 +100,18 @@ public class ResourceChecker {
private void fillInit() { private void fillInit() {
initialValues = new int[ras.size()]; initialValues = new int[ras.size()];
fill(initialValues); fill(Phase.INITIAL, initialValues);
} }
private void fillEndings() { private void fillEndings() {
endingValues = new int[ras.size()]; endingValues = new int[ras.size()];
fill(endingValues); fill(Phase.END, endingValues);
} }
private void fill(int[] vals) { private void fill(Phase phase, int[] vals) {
int i = 0; int i = 0;
for (ResourceAnalyzer ra : ras) { for (ResourceAnalyzer ra : ras) {
vals[i++] = ra.getVal(); vals[i++] = ra.getVal(phase);
} }
} }
@ -151,6 +159,12 @@ public class ResourceChecker {
if (sb.length() > 0) sb.append(", "); if (sb.length() > 0) sb.append(", ");
sb.append(ra.getName()).append("=").append(curN).append(" (was ").append(curP).append(")"); sb.append(ra.getName()).append("=").append(curN).append(" (was ").append(curP).append(")");
if (curN > curP) { if (curN > curP) {
List<String> strings = ra.getStringsToLog();
if (strings != null) {
for (String s : strings) {
sb.append(s);
}
}
sb.append(" - ").append(ra.getName()).append(" LEAK? -"); sb.append(" - ").append(ra.getName()).append(" LEAK? -");
} }
} }

View File

@ -20,14 +20,20 @@
package org.apache.hadoop.hbase; package org.apache.hadoop.hbase;
import com.sun.management.UnixOperatingSystemMXBean;
import org.junit.runner.notification.RunListener;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean; import java.lang.management.OperatingSystemMXBean;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.hadoop.hbase.ResourceChecker.Phase;
import org.junit.runner.notification.RunListener;
import com.sun.management.UnixOperatingSystemMXBean;
/** /**
* Listen to the test progress and check the usage of: * Listen to the test progress and check the usage of:
* - threads * - threads
@ -40,15 +46,43 @@ public class ResourceCheckerJUnitListener extends RunListener {
private Map<String, ResourceChecker> rcs = new ConcurrentHashMap<String, ResourceChecker>(); private Map<String, ResourceChecker> rcs = new ConcurrentHashMap<String, ResourceChecker>();
static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer { static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
private static Set<String> initialThreadNames = new HashSet<String>();
private static List<String> stringsToLog = null;
@Override @Override
public int getVal() { public int getVal(Phase phase) {
return Thread.getAllStackTraces().size(); Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
if (phase == Phase.INITIAL) {
stringsToLog = null;
for (Thread t : stackTraces.keySet()) {
initialThreadNames.add(t.getName());
}
} else if (phase == Phase.END) {
if (stackTraces.size() > initialThreadNames.size()) {
stringsToLog = new ArrayList<String>();
for (Thread t : stackTraces.keySet()) {
if (!initialThreadNames.contains(t.getName())) {
stringsToLog.add("\nPotentially hanging thread: " + t.getName() + "\n");
StackTraceElement[] stackElements = stackTraces.get(t);
for (StackTraceElement ele : stackElements) {
stringsToLog.add("\t" + ele + "\n");
}
}
}
}
}
return stackTraces.size();
} }
@Override @Override
public int getMax() { public int getMax() {
return 500; return 500;
} }
@Override
public List<String> getStringsToLog() {
return stringsToLog;
}
} }
/** /**
@ -71,7 +105,7 @@ public class ResourceCheckerJUnitListener extends RunListener {
static class OpenFileDescriptorResourceAnalyzer extends OSResourceAnalyzer { static class OpenFileDescriptorResourceAnalyzer extends OSResourceAnalyzer {
@Override @Override
public int getVal() { public int getVal(Phase phase) {
if (unixOsStats == null) { if (unixOsStats == null) {
return 0; return 0;
} else { } else {
@ -87,7 +121,7 @@ public class ResourceCheckerJUnitListener extends RunListener {
static class MaxFileDescriptorResourceAnalyzer extends OSResourceAnalyzer { static class MaxFileDescriptorResourceAnalyzer extends OSResourceAnalyzer {
@Override @Override
public int getVal() { public int getVal(Phase phase) {
if (unixOsStats == null) { if (unixOsStats == null) {
return 0; return 0;
} else { } else {

View File

@ -19,6 +19,7 @@
package org.apache.hadoop.hbase; package org.apache.hadoop.hbase;
import org.apache.hadoop.hbase.ResourceChecker.Phase;
import org.apache.hadoop.hbase.client.HConnectionTestingUtility; import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
/** /**
@ -29,7 +30,7 @@ public class ServerResourceCheckerJUnitListener extends ResourceCheckerJUnitList
static class ConnectionCountResourceAnalyzer extends ResourceChecker.ResourceAnalyzer { static class ConnectionCountResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override @Override
public int getVal() { public int getVal(Phase phase) {
return HConnectionTestingUtility.getConnectionCount(); return HConnectionTestingUtility.getConnectionCount();
} }
} }