org.gridkit.jvmtool.stacktrace.StackTraceReaderV2 Maven / Gradle / Ivy
package org.gridkit.jvmtool.stacktrace;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.zip.InflaterInputStream;
class StackTraceReaderV2 implements StackTraceReader {
private DataInputStream dis;
private List stringDic = new ArrayList();
private List frameDic = new ArrayList();
private Map frameCache = new HashMap();
private List dynStringDic = new ArrayList();
private boolean loaded;
private long threadId;
private String threadName;
private long timestamp;
private State threadState;
private String[] counterNames = new String[0];
private long[] counterValues = new long[0];
private CounterArray counters = new CounterArray(counterNames, counterValues);
private StackFrameList trace;
public StackTraceReaderV2(InputStream is) {
this.dis = new DataInputStream(new BufferedInputStream(new InflaterInputStream(is), 64 << 10));
stringDic.add(null);
dynStringDic.add(null);
frameDic.add(null);
loaded = false;;
}
@Override
public boolean isLoaded() {
return loaded;
}
@Override
public long getThreadId() {
if (!isLoaded()) {
throw new NoSuchElementException();
}
return threadId;
}
@Override
public long getTimestamp() {
if (!isLoaded()) {
throw new NoSuchElementException();
}
return timestamp;
}
@Override
public StackTraceElement[] getTrace() {
if (!isLoaded()) {
throw new NoSuchElementException();
}
StackTraceElement[] strace = new StackTraceElement[trace.depth()];
for(int i = 0; i != strace.length; ++i) {
StackFrame frame = trace.frameAt(i);
StackTraceElement e = frameCache.get(frame);
if (e == null) {
frameCache.put(frame, e = frame.toStackTraceElement());
}
strace[i] = e;
}
return strace;
}
@Override
public StackFrameList getStackTrace() {
if (!isLoaded()) {
throw new NoSuchElementException();
}
return trace;
}
@Override
public String getThreadName() {
return threadName;
}
@Override
public State getThreadState() {
return threadState;
}
@Override
public CounterCollection getCounters() {
return counters;
}
@Override
public boolean loadNext() throws IOException {
loaded = false;
while(true) {
int tag = dis.read();
if (tag < 0) {
dis.close();
break;
}
else if (tag == StackTraceCodec.TAG_STRING) {
String str = dis.readUTF();
stringDic.add(str);
}
else if (tag == StackTraceCodec.TAG_FRAME) {
StackFrame ste = readStackTraceElement();
frameDic.add(ste);
}
else if (tag == StackTraceCodec.TAG_EVENT) {
readTraceInfo();
loaded = true;
break;
}
else if (tag == StackTraceCodec.TAG_DYN_STRING) {
int id = StackTraceCodec.readVarInt(dis);
String str = dis.readUTF();
while(dynStringDic.size() <= id) {
dynStringDic.add(null);
}
dynStringDic.set(id, str);
}
else if (tag == StackTraceCodec.TAG_COUNTER) {
String str = dis.readUTF();
int n = counterNames.length;
counterNames = Arrays.copyOf(counterNames, n + 1);
counterValues = Arrays.copyOf(counterValues, n + 1);
counterNames[n] = str;
counters = new CounterArray(counterNames, counterValues);
}
else {
throw new IOException("Data format error");
}
}
return loaded;
}
protected void readTraceInfo() throws IOException {
threadId = StackTraceCodec.readVarLong(dis);
threadName = dynStringDic.get(StackTraceCodec.readVarInt(dis));
timestamp = StackTraceCodec.readTimestamp(dis);
threadState = readState();
readCounters();
readStackTrace();
}
protected State readState() throws IOException {
int n = StackTraceCodec.readVarInt(dis);
return n == 0 ? null : State.values()[n - 1];
}
protected void readCounters() throws IOException {
Arrays.fill(counterValues, Long.MIN_VALUE);
boolean[] mask = new boolean[counterNames.length];
int n = 0;
while(n < mask.length) {
byte b = dis.readByte();
for(int i = 0; i != 8; ++i) {
if (n + i < mask.length) {
mask[n + i] = (b & 1 << i) != 0;
}
}
n += 8;
}
for(int i = 0; i != mask.length; ++i) {
if (mask[i]) {
counterValues[i] = StackTraceCodec.readVarLong(dis);
}
}
}
protected void readStackTrace() throws IOException {
int len = StackTraceCodec.readVarInt(dis);
StackFrame[] frames = new StackFrame[len];
for(int i = 0; i != len; ++i) {
int ref = StackTraceCodec.readVarInt(dis);
frames[i] = frameDic.get(ref);
}
trace = new StackFrameArray(frames);
}
private StackFrame readStackTraceElement() throws IOException {
int npkg = StackTraceCodec.readVarInt(dis);
int ncn = StackTraceCodec.readVarInt(dis);
int nmtd = StackTraceCodec.readVarInt(dis);
int nfile = StackTraceCodec.readVarInt(dis);
int line = StackTraceCodec.readVarInt(dis) - 2;
String cp = stringDic.get(npkg);
String cn = stringDic.get(ncn);
String mtd = stringDic.get(nmtd);
String file = stringDic.get(nfile);
StackFrame e = new StackFrame(cp, cn, mtd, file, line);
return e;
}
}