/* * 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; import com.sun.management.UnixOperatingSystemMXBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.client.HConnectionTestingUtility; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.util.*; /** * Check the resources used: * - threads * - file descriptor */ public class ResourceChecker { private static final Log LOG = LogFactory.getLog(ResourceChecker.class); enum Phase { INITIAL, INTERMEDIATE, END } private static Set<String> initialThreadNames = new HashSet<String>(); /** * On unix, we know how to get the number of open file descriptor */ private static class ResourceAnalyzer { private static final OperatingSystemMXBean osStats; private static final UnixOperatingSystemMXBean unixOsStats; public long getThreadsCount(Phase phase) { Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces(); if (phase == Phase.INITIAL) { for (Thread t : stackTraces.keySet()) { initialThreadNames.add(t.getName()); } } return stackTraces.size(); } public long getOpenFileDescriptorCount() { if (unixOsStats == null) { return 0; } else { return unixOsStats.getOpenFileDescriptorCount(); } } public long getMaxFileDescriptorCount() { if (unixOsStats == null) { return 0; } else { return unixOsStats.getMaxFileDescriptorCount(); } } public long getConnectionCount(){ return HConnectionTestingUtility.getConnectionCount(); } static { osStats = ManagementFactory.getOperatingSystemMXBean(); if (osStats instanceof UnixOperatingSystemMXBean) { unixOsStats = (UnixOperatingSystemMXBean) osStats; } else { unixOsStats = null; } } } private static final ResourceAnalyzer rc = new ResourceAnalyzer(); /** * Maximum we set for the thread. Will get a warning in logs * if we go other this limit */ private static final long MAX_THREADS_COUNT = 500; /** * Maximum we set for the thread. Will get a warning in logs * if we go other this limit */ private static final long MAX_FILE_HANDLES_COUNT = 1024; private long initialThreadsCount; private long initialFileHandlesCount; private long initialConnectionCount; public boolean checkThreads(String tagLine) { boolean isOk = true; long threadCount = rc.getThreadsCount(Phase.INTERMEDIATE); if (threadCount > MAX_THREADS_COUNT) { LOG.error( tagLine + ": too many threads used. We use " + threadCount + " our max is " + MAX_THREADS_COUNT); isOk = false; } return isOk; } public boolean check(String tagLine) { boolean isOk = checkThreads(tagLine); if (!checkFileHandles(tagLine)) isOk = false; return isOk; } public ResourceChecker(String tagLine) { init(tagLine); } public final void init(String tagLine) { if (rc.getMaxFileDescriptorCount() < MAX_FILE_HANDLES_COUNT) { LOG.error( "Bad configuration: the operating systems file handles maximum is " + rc.getMaxFileDescriptorCount() + " our is " + MAX_FILE_HANDLES_COUNT); } logInfo(Phase.INITIAL, tagLine); initialThreadsCount = rc.getThreadsCount(Phase.INITIAL); initialFileHandlesCount = rc.getOpenFileDescriptorCount(); initialConnectionCount= rc.getConnectionCount(); check(tagLine); } public void logInfo(Phase phase, String tagLine) { long threadCount = rc.getThreadsCount(phase); LOG.info( tagLine + ": " + threadCount + " threads" + (initialThreadsCount > 0 ? " (was " + initialThreadsCount + "), " : ", ") + rc.getOpenFileDescriptorCount() + " file descriptors" + (initialFileHandlesCount > 0 ? " (was " + initialFileHandlesCount + "). " : " ") + rc.getConnectionCount() + " connections" + (initialConnectionCount > 0 ? " (was " + initialConnectionCount + "), " : ", ") + (initialThreadsCount > 0 && threadCount > initialThreadsCount ? " -thread leak?- " : "") + (initialFileHandlesCount > 0 && rc.getOpenFileDescriptorCount() > initialFileHandlesCount ? " -file handle leak?- " : "") + (initialConnectionCount > 0 && rc.getConnectionCount() > initialConnectionCount ? " -connection leak?- " : "" ) ); if (phase == Phase.END) { Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces(); if (stackTraces.size() > initialThreadNames.size()) { for (Thread t : stackTraces.keySet()) { if (!initialThreadNames.contains(t.getName())) { LOG.info(tagLine + ": potentially hanging thread - " + t.getName()); StackTraceElement[] stackElements = stackTraces.get(t); for (StackTraceElement ele : stackElements) { LOG.info("\t" + ele); } } } } } } public boolean checkFileHandles(String tagLine) { boolean isOk = true; if (rc.getOpenFileDescriptorCount() > MAX_FILE_HANDLES_COUNT) { LOG.error( tagLine + ": too many file handles used. We use " + rc.getOpenFileDescriptorCount() + " our max is " + MAX_FILE_HANDLES_COUNT); isOk = false; } return isOk; } /** * Helper function: print the threads */ public static void printThreads(){ Set<Thread> threads = Thread.getAllStackTraces().keySet(); System.out.println("name; state; isDameon; isAlive; isInterrupted"); for (Thread t: threads){ System.out.println( t.getName()+";"+t.getState()+";"+t.isDaemon()+";"+t.isAlive()+ ";"+t.isInterrupted() ); } } }