blob: 225d94f42b4531496356181e8e9a8f7b455ca249 [file] [log] [blame]
/**
* 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;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hadoop.hbase.ResourceChecker.Phase;
import org.apache.hadoop.hbase.util.JVM;
import org.junit.runner.notification.RunListener;
/**
* Listen to the test progress and check the usage of:
* <ul>
* <li>threads</li>
* <li>open file descriptor</li>
* <li>max open file descriptor</li>
* </ul>
* <p>
* When surefire forkMode=once/always/perthread, this code is executed on the forked process.
*/
public class ResourceCheckerJUnitListener extends RunListener {
private Map<String, ResourceChecker> rcs = new ConcurrentHashMap<>();
static class ThreadResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
private static Set<String> initialThreadNames = new HashSet<>();
private static List<String> stringsToLog = null;
@Override
public int getVal(Phase phase) {
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<>();
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
public int getMax() {
return 500;
}
@Override
public List<String> getStringsToLog() {
return stringsToLog;
}
}
static class OpenFileDescriptorResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
return 0;
}
JVM jvm = new JVM();
return (int) jvm.getOpenFileDescriptorCount();
}
@Override
public int getMax() {
return 1024;
}
}
static class MaxFileDescriptorResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
return 0;
}
JVM jvm = new JVM();
return (int) jvm.getMaxFileDescriptorCount();
}
}
static class SystemLoadAverageResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
return 0;
}
return (int) (new JVM().getSystemLoadAverage() * 100);
}
}
static class ProcessCountResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
return 0;
}
return new JVM().getNumberOfRunningProcess();
}
}
static class AvailableMemoryMBResourceAnalyzer extends ResourceChecker.ResourceAnalyzer {
@Override
public int getVal(Phase phase) {
if (!JVM.isUnix()) {
return 0;
}
return (int) (new JVM().getFreeMemory() / (1024L * 1024L));
}
}
/**
* To be implemented by sub classes if they want to add specific ResourceAnalyzer.
*/
protected void addResourceAnalyzer(ResourceChecker rc) {
}
private void start(String testName) {
ResourceChecker rc = new ResourceChecker(testName);
rc.addResourceAnalyzer(new ThreadResourceAnalyzer());
rc.addResourceAnalyzer(new OpenFileDescriptorResourceAnalyzer());
rc.addResourceAnalyzer(new MaxFileDescriptorResourceAnalyzer());
rc.addResourceAnalyzer(new SystemLoadAverageResourceAnalyzer());
rc.addResourceAnalyzer(new ProcessCountResourceAnalyzer());
rc.addResourceAnalyzer(new AvailableMemoryMBResourceAnalyzer());
addResourceAnalyzer(rc);
rcs.put(testName, rc);
rc.start();
}
private void end(String testName) {
ResourceChecker rc = rcs.remove(testName);
assert rc != null;
rc.end();
}
/**
* Get the test name from the JUnit Description
*
* @return the string for the short test name
*/
private String descriptionToShortTestName(
org.junit.runner.Description description) {
final int toRemove = "org.apache.hadoop.hbase.".length();
return description.getTestClass().getName().substring(toRemove) +
"#" + description.getMethodName();
}
@Override
public void testStarted(org.junit.runner.Description description) throws java.lang.Exception {
start(descriptionToShortTestName(description));
}
@Override
public void testFinished(org.junit.runner.Description description) throws java.lang.Exception {
end(descriptionToShortTestName(description));
}
}