package org.graalvm.compiler.salver.handler;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedByInterruptException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.graalvm.compiler.debug.DebugDumpHandler;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.salver.Salver;
import org.graalvm.compiler.salver.SalverOptions;
import org.graalvm.compiler.salver.dumper.AbstractGraalDumper;
import org.graalvm.compiler.salver.serialize.JSONSerializer;
import org.graalvm.compiler.salver.serialize.Serializer;
public abstract class AbstractGraalDumpHandler<D extends AbstractGraalDumper> extends AbstractDumpHandler<D> implements DebugDumpHandler {
private Serializer serializer;
private static final int MAX_FAILURES = 7;
private int failures;
public static final class NotInitializedException extends IOException {
private static final long serialVersionUID = 1L;
}
protected void ensureInitialized() throws IOException {
if (writer == null) {
if (failures < MAX_FAILURES) {
if (SalverOptions.SalverToFile.getValue()) {
initializeFileChannelWriter();
} else {
initializeSocketChannelWriter();
}
}
if (writer == null) {
throw new NotInitializedException();
}
}
if (dumper == null) {
dumper = createDumper();
if (dumper == null) {
throw new NotInitializedException();
}
if (serializer == null) {
serializer = createSerializer();
}
if (serializer.getWriter() != writer) {
serializer.setWriter(writer);
}
dumper.setSerializer(serializer);
dumper.beginDump();
}
}
protected abstract D createDumper();
protected Serializer createSerializer() {
return new JSONSerializer();
}
protected abstract void handle(Object obj, String msg) throws IOException;
protected void initializeSocketChannelWriter() {
InetSocketAddress socketAddress = Salver.getSocketAddress();
try {
setWriter(socketAddress);
printlnTTY("Connected to %s:%d (ECID = %s)", socketAddress.getHostName(), socketAddress.getPort(), Salver.ECID);
} catch (ClosedByInterruptException e) {
} catch (IOException e) {
printlnTTY("Couldn't connect to %s:%d (%s)", socketAddress.getHostName(), socketAddress.getPort(), e);
failures++;
}
}
private static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("YYYY-MM-dd_HH-mm");
}
};
protected void initializeFileChannelWriter() {
String filename = sdf.get().format(new Date());
if (label != null) {
filename += "_" + Salver.ECID + "_" + label.replaceAll("(?i)[^a-z0-9-]", "-");
}
String fileExt = JSONSerializer.getFileExtension();
File file = new File(filename + "." + fileExt);
try {
for (int i = 1; file.exists(); i++) {
if (i < 1 << 7) {
file = new File(filename + "_" + i + "." + fileExt);
} else {
throw new IOException();
}
}
setWriter(file.toPath());
printlnTTY("Dumping to \"%s\"", file.getName());
} catch (ClosedByInterruptException e) {
} catch (IOException e) {
printlnTTY("Failed to open %s for dumping (%s)", file.getName(), e);
failures++;
}
}
public void dump(Object obj) {
dump(obj, null);
}
@Override
public void dump(Object obj, String msg) {
try {
handle(obj, msg);
} catch (NotInitializedException e) {
} catch (IOException e) {
printlnTTY("%s", e);
if (failures < MAX_FAILURES) {
failures++;
} else {
close();
}
}
}
@Override
public void close() {
try {
super.close();
} catch (IOException e) {
printlnTTY("%s", e);
} finally {
failures = 0;
}
}
protected void printlnTTY(String format, Object... args) {
if (label != null) {
TTY.println("[" + label + "] " + format, args);
} else {
TTY.println(format, args);
}
}
}