package water.api.schemas3;
import water.*;
import water.api.API;
import water.api.TimelineHandler.Timeline;
import water.init.TimelineSnapshot;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
/**
* Display of a Timeline
*/
public class TimelineV3 extends RequestSchemaV3<Timeline,TimelineV3> {
// This schema has no input params
@API(help="Current time in millis.", direction=API.Direction.OUTPUT)
private long now;
@API(help="This node", direction=API.Direction.OUTPUT)
private String self;
@API(help="recorded timeline events", direction=API.Direction.OUTPUT)
public EventV3[] events;
public static class EventV3<I, S extends EventV3<I, S>> extends SchemaV3<Iced, S> {
@API(help="Time when the event was recorded. Format is hh:mm:ss:ms")
private final String date;
@API(help="Time in nanos")
private final long nanos;
enum EventType {unknown, heartbeat, network_msg, io}
@API(help="type of recorded event", values = {"unknown", "heartbeat", "network_msg", "io"})
private final EventType type;
@SuppressWarnings("unused")
public EventV3() { date = null; nanos = -1; type = EventType.unknown; }
private EventV3(EventType type, long millis, long nanos){
this.type = type;
this.date = new SimpleDateFormat("HH:mm:ss:SSS").format(new Date(millis));
this.nanos = nanos;
}
protected String who() { throw H2O.unimpl(); };
protected String ioType() { throw H2O.unimpl(); };
protected String event() { throw H2O.unimpl(); };
public String bytes() { throw H2O.unimpl(); };
} // Event
public static class HeartBeatEvent extends EventV3<Iced, HeartBeatEvent> {
@API(help = "number of sent heartbeats")
final int sends;
@API(help = "number of received heartbeats")
final int recvs;
public HeartBeatEvent() { super(); sends = -1; recvs = -1; }
private HeartBeatEvent(int sends, int recvs, long lastMs, long lastNs){
super(EventType.heartbeat,lastMs,lastNs);
this.sends = sends;
this.recvs = recvs;
}
@Override protected String who() { return "many -> many";}
@Override protected String ioType() {return "UDP";}
@Override protected String event() {return "heartbeat";}
@Override public String bytes() {return sends + " sent " + ", " + recvs + " received";}
@Override public String toString() { return "HeartBeat(" + sends + " sends, " + recvs + " receives)"; }
} // HeartBeatEvent
public static class NetworkEvent extends EventV3<Iced, NetworkEvent> {
@API(help="Boolean flag distinguishing between sends (true) and receives(false)")
public final boolean is_send;
@API(help="network protocol (UDP/TCP)")
private final String protocol;
@API(help="UDP type (exec,ack, ackack,...")
private final String msg_type; // udp
@API(help="Sending node")
public final String from;
@API(help="Receiving node")
public final String to;
@API(help="Pretty print of the first few bytes of the msg payload. Contains class name for tasks.")
private final String data;
public NetworkEvent() { super(); is_send = false; protocol = "unknown"; msg_type = "unknown"; from = "unknown"; to = "unknown"; data = "unknown"; }
private NetworkEvent(long ms, long ns, boolean is_send, String protocol, String msg_type, String from, String to, String data){
super(EventType.network_msg,ms,ns);
this.is_send = is_send;
this.protocol = protocol;
this.msg_type = msg_type;
this.from = from;
this.to = to;
this.data = data;
}
@Override protected String who() { return from + " -> " + to;}
@Override protected String ioType() {return protocol;}
@Override protected String event() {return msg_type;}
@Override public String bytes() {return data;}
@Override public String toString() {
return "NetworkMsg(" + from + " -> " + to + ", protocol = '" + protocol + "', data = '" + data + "')";
}
} // NetworkEvent
public static class IOEvent extends EventV3<Iced, IOEvent> {
@API(help="flavor of the recorded io (ice/hdfs/...)")
private final String io_flavor;
@API(help="node where this io event happened")
private final String node;
@API(help="data info")
private final String data;
public IOEvent() { this(-1, -1, "unknown", "unknown", "unknown"); }
private IOEvent(long ms, long ns, String node, String io_flavor, String data){
super(EventType.io,ms,ns);
this.io_flavor = io_flavor;
this.node = node;
this.data = data;
}
@Override protected String who(){return node;}
@Override protected String ioType() {return io_flavor;}
@Override protected String event() {return "i_o";}
@Override public String bytes() { return data;}
@Override public String toString() { return "I_O('" + io_flavor + "')"; }
} // IOEvent
@Override public TimelineV3 fillFromImpl(Timeline timeline) {
ArrayList<EventV3> outputEvents = new ArrayList<>();
ArrayList<TimelineSnapshot.Event> heartbeats = new ArrayList();
H2O cloud = TimeLine.getCLOUD();
if (null != timeline.snapshot) {
for (TimelineSnapshot.Event event : timeline.snapshot) {
H2ONode h2o = cloud.members()[event._nodeId];
// The event type. First get payload.
UDP.udp msgType = event.udpType();
// Accumulate repeated heartbeats
if (msgType == UDP.udp.heartbeat) {
heartbeats.add(event);
continue;
}
// Now dump out accumulated heartbeats
if (!heartbeats.isEmpty()) {
long firstMs = heartbeats.get(0).ms();
long lastMs = heartbeats.get(heartbeats.size() - 1).ms();
int totalSends = 0;
int totalRecvs = 0;
int totalDrops = 0;
int[] sends = new int[cloud.size()];
int[] recvs = new int[cloud.size()];
for (TimelineSnapshot.Event h : heartbeats) {
if (h.isSend()) {
++totalSends;
++sends[h._nodeId];
} else if (h.isDropped()) {
++totalDrops;
} else {
++totalRecvs;
++recvs[h._nodeId];
}
}
heartbeats.clear();
outputEvents.add(new HeartBeatEvent(totalSends, totalRecvs, firstMs, lastMs));
}
long ms = event.ms();
long ns = event.ns();
if (msgType == UDP.udp.i_o) { // handle io event
outputEvents.add(new IOEvent(ms, ns, event.recoH2O().toString(), event.ioflavor(), UDP.printx16(event.dataLo(), event.dataHi())));
} else { // network msg
String from, to;
if (event.isSend()) {
from = h2o.toString();
to = event.packH2O() == null ? "multicast" : event.packH2O().toString();
} else {
from = event.packH2O().toString();
to = h2o.toString();
}
outputEvents.add(new NetworkEvent(ms, ns, event.isSend(), event.isTCP() ? "TCP" : "UDP", msgType.toString(), from, to, UDP.printx16(event.dataLo(), event.dataHi())));
}
}
} // if timeline.snapshot
events = outputEvents.toArray(new EventV3[null == outputEvents ? 0 : outputEvents.size()]);
return this;
}
}