package water; import water.util.UnsafeUtils; /** * 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 { /** UDP packet types, and their handlers */ public static enum udp { bad(false,null,(byte)-1), // 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(),H2O.MAX_PRIORITY), rebooted ( true, new UDPRebooted() ,H2O.MAX_PRIORITY), // This node has rebooted recently timeline (false, new TimeLine() ,H2O.MAX_PRIORITY), // Get timeline dumps from across the Cloud client_event ( true, new UDPClientEvent(), H2O.MAX_PRIORITY), // This packet informs about a client action (connect/disconnect) // 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(),H2O.ACK_ACK_PRIORITY), // 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(),H2O.FETCH_ACK_PRIORITY), // a class/id fetch ACK ack (false,new UDPAck (),H2O.ACK_PRIORITY), // a generic ACK for a UDP async task nack (false,new UDPNack(),H2O.ACK_PRIORITY), // a generic NACK // 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(),H2O.DESERIAL_PRIORITY), // Remote hi-q execution request i_o (false,new UDP.IO_record(),(byte)-1); // Only used to profile I/O final UDP _udp; // The Callable S.A.M. instance final byte _prior; // Priority final boolean _paxos; // Ignore (or not) packets from outside the Cloud udp( boolean paxos, UDP udp, byte prior ) { _paxos = paxos; _udp = udp; _prior = prior; } 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))); } String print16( AutoBuffer ab ) { for( int i=0; i<16; i++ ) { int b = ab.get1U(); cs[(i<<1) ] = 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 ) { UnsafeUtils.set8(pbuf, 0, lo); UnsafeUtils.set8(pbuf, 8, hi); return udp.UDPS[(int)(lo&0xFF)]._udp.print16(new AutoBuffer(pbuf)); } private static class IO_record extends UDP { AutoBuffer call(AutoBuffer ab) { throw H2O.fail(); } String print16( AutoBuffer ab ) { int flavor = ab.get1U(3); int iotime = ab.get4 (4); int size = ab.get4 (8); return "I/O "+Value.nameOfPersist(flavor)+" "+iotime+"ms "+size+"b"; } } }