| /** |
| * @@@ START COPYRIGHT @@@ |
| |
| 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. |
| |
| * @@@ END COPYRIGHT @@@ |
| */ |
| |
| package org.trafodion.dcs; |
| |
| import com.sun.management.UnixOperatingSystemMXBean; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| 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(); |
| } |
| } |
| |
| 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; |
| |
| 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(); |
| |
| 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 + "). " : " ") + |
| (initialThreadsCount > 0 && threadCount > initialThreadsCount ? |
| " -thread leak?- " : "") + |
| (initialFileHandlesCount > 0 && |
| rc.getOpenFileDescriptorCount() > initialFileHandlesCount ? |
| " -file handle 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() |
| ); |
| } |
| } |
| } |