package water;
import sun.misc.Unsafe;
import water.nbhm.UtilUnsafe;
/**
* Do Something with an incoming UDP packet
*
* Classic Single Abstract Method pattern.
* @author <a href="mailto:cliffc@h2o.ai"></a>
* @version 1.0
*/
public abstract class UDP {
// Types of UDP packets I grok
public static enum udp {
bad(false,null), // Do not use the zero packet, too easy to make mistakes
// Some health-related packet types. These packets are all stateless, in
// that we do not need to send any replies back.
heartbeat ( true, new UDPHeartbeat()),
rebooted ( true, new UDPRebooted()), // This node has rebooted recently
timeline (false, new TimeLine()), // Get timeline dumps from across the Cloud
// All my *reliable* tasks (below), are sent to remote nodes who then ACK
// back an answer. To be reliable, I might send the TASK multiple times.
// To get a reliable answer, the remote might send me multiple ACKs with
// the same answer every time. When does the remote know it can quit
// tracking reply ACKs? When it recieves an ACKACK.
ackack(false,new UDPAckAck()), // a generic ACKACK for a UDP async task
// In order to unpack an ACK (which contains an arbitrary returned POJO)
// the reciever might need to fetch a id/class mapping from the leader -
// while inside an ACK-priority thread holding onto lots of resources
// (e.g. TCP channel). Allow the fetch to complete on a higher priority
// thread.
fetchack(false,new UDPFetchAck()), // a class/id fetch ACK
ack (false,new UDPAck ()), // a generic ACK for a UDP async task
// These packets all imply some sort of request/response handshake.
// We'll hang on to these packets; filter out dup sends and auto-reply
// identical result ACK packets.
exec(false,new RPC.RemoteHandler()), // Remote hi-q execution request
i_o (false,new UDP.IO_record()); // Only used to profile I/O
final UDP _udp; // The Callable S.A.M. instance
final boolean _paxos; // Ignore (or not) packets from outside the Cloud
udp( boolean paxos, UDP udp ) { _paxos = paxos; _udp = udp; }
static udp[] UDPS = values();
}
public static udp getUdp(int id){return udp.UDPS[id];}
// Handle an incoming I/O transaction, probably from a UDP packet. The
// returned Autobuffer will be closed(). If the returned buffer is not the
// passed-in buffer, the call() method must close it's AutoBuffer arg.
abstract AutoBuffer call(AutoBuffer ab);
// Pretty-print bytes 1-15; byte 0 is the udp_type enum
static final char[] cs = new char[32];
static char hex(int x) { x &= 0xf; return (char)(x+((x<10)?'0':('a'-10))); }
public String print16( AutoBuffer ab ) {
for( int i=0; i<16; i++ ) {
int b = ab.get1();
cs[(i<<1)+0 ] = hex(b>>4);
cs[(i<<1)+1 ] = hex(b );
}
return new String(cs);
}
// Dispatch on the enum opcode and return a pretty string
static private final byte[] pbuf = new byte[16];
static public String printx16( long lo, long hi ) {
set8(pbuf,0,lo);
set8(pbuf,8,hi);
return udp.UDPS[(int)(lo&0xFF)]._udp.print16(new AutoBuffer(pbuf));
}
// ---
private static final Unsafe _unsafe = UtilUnsafe.getUnsafe();
private static final long _Bbase = _unsafe.arrayBaseOffset(byte[].class);
public static int get2 ( byte[] buf, int off ) { return _unsafe.getShort (buf, _Bbase+off); }
public static int get2u( byte[] buf, int off ) { return _unsafe.getChar (buf, _Bbase+off); }
public static int get4 ( byte[] buf, int off ) { return _unsafe.getInt (buf, _Bbase+off); }
public static long get8 ( byte[] buf, int off ) { return _unsafe.getLong (buf, _Bbase+off); }
public static float get4f( byte[] buf, int off ) { return _unsafe.getFloat (buf, _Bbase+off); }
public static double get8d( byte[] buf, int off ) { return _unsafe.getDouble(buf, _Bbase+off); }
public static int set2 (byte[] buf, int off, short x ) {_unsafe.putShort (buf, _Bbase+off, x); return 2;}
public static int set4 (byte[] buf, int off, int x ) {_unsafe.putInt (buf, _Bbase+off, x); return 4;}
public static int set4f(byte[] buf, int off, float f ) {_unsafe.putFloat (buf, _Bbase+off, f); return 4;}
public static int set8 (byte[] buf, int off, long x ) {_unsafe.putLong (buf, _Bbase+off, x); return 8;}
public static int set8d(byte[] buf, int off, double x) {_unsafe.putDouble(buf, _Bbase+off, x); return 8;}
private static class IO_record extends UDP {
public AutoBuffer call(AutoBuffer ab) { throw H2O.unimpl(); }
public String print16( AutoBuffer ab ) {
int flavor = ab.get1(3);
int iotime = ab.get4(4);
int size = ab.get4(8);
return "I/O "+Value.nameOfPersist(flavor)+" "+iotime+"ms "+size+"b";
}
}
}