[ASTERIXDB-2353][HYR][RT][FAIL] Provide complete thread dumps
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Implements a thread dump mechanism that does not truncate stack
frames after the top 8
Change-Id: Id778615b3ac8951113d6b9ea027ad8650b784cb2
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2564
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
index 221d4b0..2de6700 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
@@ -19,7 +19,9 @@
package org.apache.hyracks.util;
import java.io.IOException;
+import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
@@ -29,6 +31,8 @@
import java.util.Map;
import java.util.stream.Stream;
+import org.apache.commons.lang3.mutable.MutableInt;
+
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -100,8 +104,62 @@
}
public static String takeDumpString() {
- StringBuilder buf = new StringBuilder(2048);
- Stream.of(threadMXBean.dumpAllThreads(true, true)).forEach(buf::append);
- return buf.toString();
+ ThreadDumpHelper helper = new ThreadDumpHelper();
+ Stream.of(threadMXBean.dumpAllThreads(true, true)).forEach(helper::addThread);
+ return helper.dumpAsString();
+ }
+
+ static class ThreadDumpHelper {
+
+ private final StringBuilder buf = new StringBuilder(32 * 1024);
+
+ private ThreadDumpHelper() {
+ }
+
+ private void addThread(ThreadInfo ti) {
+ buf.append('\n');
+ quote(ti.getThreadName()).append(" [tid=").append(ti.getThreadId()).append(" state=")
+ .append(ti.getThreadState());
+
+ if (ti.getLockName() != null) {
+ buf.append(" lock=").append(ti.getLockName());
+ if (ti.getLockOwnerName() != null) {
+ buf.append(" lockOwner=");
+ quote(ti.getLockOwnerName()).append(" (tid=").append(ti.getLockOwnerId());
+ }
+ }
+ if (ti.isSuspended()) {
+ buf.append(" suspended=true");
+ }
+ buf.append("]\n");
+ MutableInt depth = new MutableInt();
+ for (StackTraceElement frame : ti.getStackTrace()) {
+ int thisDepth = depth.getAndIncrement();
+ buf.append("\tat ").append(frame).append('\n');
+ Stream.of(ti.getLockedMonitors()).filter(m -> m.getLockedStackDepth() == thisDepth)
+ .forEach(this::output);
+ }
+ LockInfo[] lockedSynchronizers = ti.getLockedSynchronizers();
+ if (lockedSynchronizers.length > 0) {
+ buf.append("\n\tLocked synchronizers:\n");
+ Stream.of(lockedSynchronizers).forEachOrdered(this::output);
+ }
+ }
+
+ private StringBuilder quote(Object quotable) {
+ return buf.append('"').append(quotable).append('"');
+ }
+
+ private StringBuilder output(MonitorInfo info) {
+ return buf.append("\t- <").append("locked ").append(info).append(">\n");
+ }
+
+ private StringBuilder output(LockInfo info) {
+ return buf.append("\t- ").append("").append(info).append("\n");
+ }
+
+ public String dumpAsString() {
+ return buf.toString();
+ }
}
}