package water; import water.util.Log; /** * A UDP Rebooted packet: this node recently rebooted * * @author <a href="mailto:cliffc@h2o.ai"></a> * @version 1.0 */ public class UDPRebooted extends UDP { public static boolean BIG_DEBUG = false; public static enum T { none, reboot, shutdown, oom, error, locked, mismatch; public void send(H2ONode target) { assert this != none; new AutoBuffer(target,udp.rebooted._prior).putUdp(udp.rebooted).put1(ordinal()).close(); } void broadcast() { send(H2O.SELF); } } static void checkForSuicide(int first_byte, AutoBuffer ab) { if( first_byte != UDP.udp.rebooted.ordinal() ) return; int type = ab.get1(); suicide( T.values()[type], ab._h2o); } public static class ShutdownTsk extends DTask<ShutdownTsk> { final H2ONode _killer; final int _timeout; final transient boolean [] _confirmations; final int _nodeId; final int _exitCode; public ShutdownTsk(H2ONode killer, int nodeId, int timeout, boolean [] confirmations, int exitCode){ super(H2O.GUI_PRIORITY); _nodeId = nodeId; _killer = killer; _timeout = timeout; _confirmations = confirmations; _exitCode = exitCode; } transient boolean _didShutDown; private synchronized void doShutdown(int exitCode, String msg){ if(_didShutDown)return; Log.info(msg); H2O.closeAll(); H2O.exit(exitCode); } @Override public void compute2() { Log.info("Orderly shutdown from " + _killer); // start a separate thread which will force termination after timeout expires (in case we don't get ack ack in time) new Thread(){ @Override public void run(){ try {Thread.sleep(_timeout);} catch (InterruptedException e) {} doShutdown(_exitCode,"Orderly shutdown may not have been acknowledged to " + _killer + " (no ackack), exiting with exit code " + _exitCode + "."); } }.start(); tryComplete(); } @Override public void onAck(){ _confirmations[_nodeId] = true; } @Override public void onAckAck(){ doShutdown(_exitCode,"Orderly shutdown acknowledged to " + _killer + ", exiting with exit code " + _exitCode + "."); } } static void suicide( T cause, final H2ONode killer ) { String m; switch( cause ) { case none: return; case reboot: return; case shutdown: Log.warn("Orderly shutdown should be handled via ShutdownTsk. Message is from outside of the cloud? Ignoring it."); return; case oom: m = "Out of Memory, Heap Space exceeded, increase Heap Size,"; break; case error: if (BIG_DEBUG) Thread.dumpStack(); m = "Error leading to a cloud kill"; break; case locked: m = "Attempting to join an H2O cloud that is no longer accepting new H2O nodes"; break; case mismatch: m = "Attempting to join an H2O cloud with a different H2O version (is H2O already running?)"; break; default: m = "Received kill " + cause; break; } H2O.closeAll(); Log.err(m+" from "+killer); H2O.die("Exiting."); } @Override AutoBuffer call(AutoBuffer ab) { checkForSuicide(udp.rebooted.ordinal(),ab); if( ab._h2o != null ) ab._h2o.rebooted(); return ab; } // Pretty-print bytes 1-15; byte 0 is the udp_type enum @Override String print16( AutoBuffer ab ) { ab.getPort(); return T.values()[ab.get1()].toString(); } }