diff --git a/source/net/yacy/kelondro/logging/ThreadDump.java b/source/net/yacy/kelondro/logging/ThreadDump.java index a5a193580..2f6d51fa4 100644 --- a/source/net/yacy/kelondro/logging/ThreadDump.java +++ b/source/net/yacy/kelondro/logging/ThreadDump.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.regex.Pattern; import net.yacy.document.parser.html.CharacterCoding; @@ -49,19 +50,19 @@ public class ThreadDump extends HashMap> imp private static final String multiDumpFilter = ".*((java.net.DatagramSocket.receive)|(java.lang.Thread.getAllStackTraces)|(java.net.SocketInputStream.read)|(java.net.ServerSocket.accept)|(java.net.Socket.connect)).*"; private static final Pattern multiDumpFilterPattern = Pattern.compile(multiDumpFilter); - + public static class StackTrace { public String text; public Thread.State state; - public StackTrace(final String text, Thread.State state) { + public StackTrace(final String text, final Thread.State state) { this.state = state; this.text = text; } @Override - public boolean equals(Object a) { + public boolean equals(final Object a) { return (a != null && a instanceof StackTrace && this.text.equals(((StackTrace) a).text)); } - public boolean equals(StackTrace a) { + public boolean equals(final StackTrace a) { return (a != null && this.text.equals(a.text)); } @Override @@ -73,17 +74,17 @@ public class ThreadDump extends HashMap> imp return this.text; } } - + public static class Lock { public String id; public Lock(final String name) { this.id = name; } @Override - public boolean equals(Object a) { + public boolean equals(final Object a) { return (a != null && a instanceof Lock && this.id.equals(((Lock) a).id)); } - public boolean equals(Lock a) { + public boolean equals(final Lock a) { return (a != null && this.id.equals(a.id)); } @Override @@ -99,71 +100,71 @@ public class ThreadDump extends HashMap> imp public static Map getAllStackTraces() { return Thread.getAllStackTraces(); } - - public static boolean canProduceLockedBy(File logFile) { + + public static boolean canProduceLockedBy(final File logFile) { // check os version if (!OS.canExecUnix) return false; - + // check if log file exists if (!logFile.exists()) return false; - + // check last modification date of log file if (System.currentTimeMillis() - logFile.lastModified() > 60000) return false; - + return true; } - - public ThreadDump(File logFile) throws IOException { + + public ThreadDump(final File logFile) throws IOException { super(); - + // try to get the thread dump from yacy.log which is available when YaCy is started with // startYACY.sh -l long sizeBefore = 0; if (canProduceLockedBy(logFile)) { sizeBefore = logFile.length(); - + // get the current process PID - int pid = OS.getPID(); - + final int pid = OS.getPID(); + // call kill -3 on the pid - if (pid >= 0) try {OS.execSynchronous("kill -3 " + pid);} catch (IOException e) {} + if (pid >= 0) try {OS.execSynchronous("kill -3 " + pid);} catch (final IOException e) {} } // read the log from the dump - long sizeAfter = logFile.length(); + final long sizeAfter = logFile.length(); if (sizeAfter <= sizeBefore) return; - - RandomAccessFile raf = new RandomAccessFile(logFile, "r"); + + final RandomAccessFile raf = new RandomAccessFile(logFile, "r"); raf.seek(sizeBefore); - byte[] b = new byte[(int) (sizeAfter - sizeBefore)]; + final byte[] b = new byte[(int) (sizeAfter - sizeBefore)]; raf.readFully(b); raf.close(); - + // import the thread dump; importText(new ByteArrayInputStream(b)); } - + public ThreadDump(final InputStream is) throws IOException { super(); importText(is); } private static final String statestatement = "java.lang.Thread.State:"; - + public static Thread.State threadState(String line) { int p = line.indexOf(statestatement); - if (p >= 0) line = line.substring(p + statestatement.length()).trim(); + if (p < 0) return null; + line = line.substring(p + statestatement.length()).trim(); p = line.indexOf(' '); if (p >= 0) line = line.substring(0, p).trim(); try { return Thread.State.valueOf(line); - } catch (IllegalArgumentException e) { - System.out.println("wong state: " + line); + } catch (final IllegalArgumentException e) { return null; } } - + private void importText(final InputStream is) throws IOException { final BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; @@ -171,16 +172,13 @@ public class ThreadDump extends HashMap> imp int p; List list = new ArrayList(); Thread.State state = null; + Thread.State state0; while ((line = br.readLine()) != null) { - p = line.indexOf(statestatement); - if (p >= 0) try { - state = Thread.State.valueOf(line.substring(p + statestatement.length()).trim()); - } catch (IllegalArgumentException e) { - System.out.println("wong state: " + line); - } + state0 = threadState(line); + if (state0 != null) state = state0; if (line.isEmpty()) { if (thread != null) { - this.put(new ThreadDump.StackTrace(thread, state), list); + put(new ThreadDump.StackTrace(thread, state), list); } list = new ArrayList(); thread = null; @@ -198,10 +196,10 @@ public class ThreadDump extends HashMap> imp } // recognize last thread if (thread != null) { - this.put(new ThreadDump.StackTrace(thread, state), list); + put(new ThreadDump.StackTrace(thread, state), list); } } - + public ThreadDump( final File appPath, final Map stackTraces, @@ -209,7 +207,7 @@ public class ThreadDump extends HashMap> imp final Thread.State stateIn) { super(); final File classPath = new File(appPath, "source"); - + Thread thread; // collect single dumps for (final Entry entry: stackTraces.entrySet()) { @@ -220,16 +218,16 @@ public class ThreadDump extends HashMap> imp String tracename = ""; File classFile; if ((stateIn == null || stateIn.equals(thread.getState())) && stackTraceElements.length > 0) { - StringBuilder sb = new StringBuilder(3000); + final StringBuilder sb = new StringBuilder(3000); if (plain) { classFile = getClassFile(classPath, stackTraceElements[stackTraceElements.length - 1].getClassName()); tracename = classFile.getName(); if (tracename.endsWith(".java")) tracename = tracename.substring(0, tracename.length() - 5); if (tracename.length() > 20) tracename = tracename.substring(0, 20); while (tracename.length() < 20) tracename = tracename + "_"; - tracename = "[" + tracename + "] "; - } - String threadtitle = tracename + "Thread= " + thread.getName() + " " + (thread.isDaemon()?"daemon":"") + " id=" + thread.getId() + " " + thread.getState().toString(); + tracename = "[" + tracename + "] "; + } + final String threadtitle = tracename + "Thread= " + thread.getName() + " " + (thread.isDaemon()?"daemon":"") + " id=" + thread.getId() + " " + thread.getState().toString(); String className; boolean cutcore = true; for (int i = 0; i < stackTraceElements.length; i++) { @@ -253,31 +251,31 @@ public class ThreadDump extends HashMap> imp } } final String threaddump = sb.toString(); - List threads = this.get(threaddump); + List threads = get(threaddump); if (threads == null) threads = new ArrayList(); Thread.State state = null; - for (String t: threads) { - int p = t.indexOf(statestatement); + for (final String t: threads) { + final int p = t.indexOf(statestatement); if (p >= 0) { state = Thread.State.valueOf(t.substring(p + statestatement.length()).trim()); } } threads.add(threadtitle); - this.put(new StackTrace(threaddump, state), threads); + put(new StackTrace(threaddump, state), threads); } } } - + public void appendStackTraces( final StringBuilder buffer, final boolean plain, final Thread.State stateIn) { bufferappend(buffer, plain, "THREADS WITH STATES: " + stateIn.toString()); bufferappend(buffer, plain, ""); - + // write dumps - for (final Entry> entry: this.entrySet()) { - List threads = entry.getValue(); + for (final Entry> entry: entrySet()) { + final List threads = entry.getValue(); for (final String t: threads) bufferappend(buffer, plain, t); bufferappend(buffer, plain, entry.getKey().text); bufferappend(buffer, plain, ""); @@ -290,30 +288,30 @@ public class ThreadDump extends HashMap> imp final boolean plain) { bufferappend(buffer, plain, "THREADS WITH STATES: LOCK FOR OTHERS"); bufferappend(buffer, plain, ""); - - Map locks = this.countLocks(); - for (int i = this.size() + 10; i > 0; i--) { - for (Map.Entry entry: locks.entrySet()) { + + final Map locks = countLocks(); + for (int i = size() + 10; i > 0; i--) { + for (final Map.Entry entry: locks.entrySet()) { if (entry.getValue().intValue() == i) { bufferappend(buffer, plain, "holds lock for " + i + " threads:"); - final List list = this.get(entry.getKey()); + final List list = get(entry.getKey()); if (list == null) continue; bufferappend(buffer, plain, "Thread= " + entry.getKey()); - for (String s: list) bufferappend(buffer, plain, " " + (plain ? s : s.replaceAll("<", "<").replaceAll(">", ">"))); + for (final String s: list) bufferappend(buffer, plain, " " + (plain ? s : s.replaceAll("<", "<").replaceAll(">", ">"))); bufferappend(buffer, plain, ""); } } } bufferappend(buffer, plain, ""); } - - + + public static void appendStackTraceStats( final File rootPath, final StringBuilder buffer, final List> stackTraces, final boolean plain) { - + // collect single dumps final Map dumps = new HashMap(); ThreadDump x; @@ -329,7 +327,7 @@ public class ThreadDump extends HashMap> imp } } } - + // write dumps while (!dumps.isEmpty()) { final Entry e = removeMax(dumps); @@ -338,7 +336,7 @@ public class ThreadDump extends HashMap> imp } bufferappend(buffer, plain, ""); } - + private static Entry removeMax(final Map result) { Entry max = null; for (final Entry e: result.entrySet()) { @@ -349,13 +347,13 @@ public class ThreadDump extends HashMap> imp result.remove(max.getKey()); return max; } - + private static File getClassFile(final File sourcePath, final String classname) { final String classPath = classname.replace('.', '/') + ".java"; final File file = new File(sourcePath, classPath); return file; } - + private static String getLine(final File file, final int line) { // find class if (!file.exists()) return ""; @@ -367,16 +365,16 @@ public class ThreadDump extends HashMap> imp return "@EXCEPTION: " + e.getMessage(); } } - + public static void bufferappend(final StringBuilder buffer, final boolean plain, final String a) { buffer.append(a); buffer.append(plain ? "\n" : "
"); } - + public List>> freerun() { final List>> runner = new ArrayList>>(); - runf: for (final Map.Entry> entry: this.entrySet()) { + runf: for (final Map.Entry> entry: entrySet()) { // check if the thread is locked or holds a lock if (entry.getKey().state != Thread.State.RUNNABLE) continue runf; for (final String s: entry.getValue()) { @@ -386,7 +384,7 @@ public class ThreadDump extends HashMap> imp } return runner; } - + /** * find all locks in this dump * @return a map from lock ids to the name of the thread where the lock occurs @@ -394,17 +392,17 @@ public class ThreadDump extends HashMap> imp public Map locks() { int p; final Map locks = new HashMap(); - for (final Map.Entry> entry: this.entrySet()) { + for (final Map.Entry> entry: entrySet()) { for (final String s: entry.getValue()) { if ((p = s.indexOf("locked <")) > 0) { locks.put(new Lock(s.substring(p + 8, s.indexOf('>'))), entry.getKey()); - + } } } return locks; } - + /** * check if a thread is locked by another thread * @param threadName @@ -412,7 +410,7 @@ public class ThreadDump extends HashMap> imp */ public Lock lockedBy(final StackTrace threadName) { int p; - final List list = this.get(threadName); + final List list = get(threadName); if (list == null) return null; for (final String s: list) { if ((p = s.indexOf("<")) > 0 && s.indexOf("locked <") < 0) { @@ -421,64 +419,64 @@ public class ThreadDump extends HashMap> imp } return null; } - + public Map countLocks() { final Map locks = locks(); final Map count = new HashMap(); for (final Map.Entry entry: locks.entrySet()) { // look where the lock has an effect int c = 0; - for (final StackTrace thread: this.keySet()) if (entry.getKey().equals(lockedBy(thread))) c++; + for (final StackTrace thread: keySet()) if (entry.getKey().equals(lockedBy(thread))) c++; if (c > 0) count.put(entry.getValue(), c); } return count; } - + public void print() { - for (final StackTrace thread: this.keySet()) print(thread); + for (final StackTrace thread: keySet()) print(thread); } - public void print(StackTrace thread) { - final List list = this.get(thread); + public void print(final StackTrace thread) { + final List list = get(thread); if (list == null) return; System.out.println("Thread: " + thread); - for (String s: list) System.out.println(" " + s); + for (final String s: list) System.out.println(" " + s); System.out.println(""); } - - public static void main(String[] args) { + + public static void main(final String[] args) { ThreadDump dump = null; if (args.length == 0) { //dump = new ThreadDump(); } if (args.length == 2 && args[0].equals("-f")) { - File dumpfile = new File(args[1]); + final File dumpfile = new File(args[1]); try { dump = new ThreadDump(dumpfile); - } catch (IOException e) { + } catch (final IOException e) { e.printStackTrace(); } } //dump.print(); assert dump != null; - Map locks = dump.countLocks(); - List>> freerun = dump.freerun(); + final Map locks = dump.countLocks(); + final List>> freerun = dump.freerun(); assert locks != null; System.out.println("*** Thread Dump Lock report; dump size = " + dump.size() + ", locks = " + locks.size() + ", freerunner = " + freerun.size()); for (int i = 0; i < dump.size() + 10; i++) { - for (Map.Entry entry: locks.entrySet()) { + for (final Map.Entry entry: locks.entrySet()) { if (entry.getValue().intValue() == i) { System.out.println("holds lock for " + i + " threads:"); dump.print(entry.getKey()); } } } - + System.out.println("*** Thread freerunner report; dump size = " + dump.size() + ", locks = " + locks.size() + ", freerunner = " + freerun.size()); - for (Map.Entry> entry: freerun) { + for (final Map.Entry> entry: freerun) { System.out.println("freerunner:"); dump.print(entry.getKey()); } - + } }