package water.zookeeper; import java.io.*; import java.net.*; import java.util.List; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import water.H2O; import water.zookeeper.nodes.ClusterPayload; import water.zookeeper.nodes.MasterPayload; import water.zookeeper.nodes.WorkerPayload; public class h2oworker { static EmbeddedH2OConfig _embeddedH2OConfig; /** * Start an H2O instance in the local JVM. */ public static class UserMain { private static void usage() { String s = "H2O Zookeeper worker wrapper options:\n" + "\n" + "Usage: java [-Xmx<size>] -cp h2o-zookeeper.jar water.zookeeper.h2oworker -zk a:b:c:d:e -zkroot /zk/path/h2o-uuid [-timeout sec] [h2o options...]\n" + "\n"; System.out.println(s); H2O.printHelp(); System.exit(1); } private static void registerEmbeddedH2OConfig(String[] args) { String zk = null; String zkroot = null; long timeout = Constants.DEFAULT_CLOUD_FORMATION_TIMEOUT_SECONDS; for (int i = 0; i < args.length; i++) { if (args[i].equals("-zk")) { i++; zk = args[i]; } else if (args[i].equals("-zkroot")) { i++; zkroot = args[i]; } else if (args[i].equals("-timeout")) { i++; timeout = Long.parseLong(args[i]); } } if (zk == null) { System.out.println("\nERROR: -zk must be specified\n"); usage(); } if (zkroot == null) { System.out.println("\nERROR: -zkroot must be specified\n"); usage(); } if (timeout < 0) { timeout = Integer.MAX_VALUE; // Integer max value, big but not too big when multiplied by 1000. } _embeddedH2OConfig = new EmbeddedH2OConfig(); _embeddedH2OConfig.setZk(zk); _embeddedH2OConfig.setZkRoot(zkroot); _embeddedH2OConfig.setCloudFormationTimeoutSeconds(timeout); H2O.setEmbeddedH2OConfig(_embeddedH2OConfig); } public static void main(String[] args) { registerEmbeddedH2OConfig(args); H2O.main(args); } } private static class EmbeddedH2OConfig extends water.AbstractEmbeddedH2OConfig { volatile String _zk; volatile String _zkroot; volatile long _cloudFormationTimeoutSeconds; volatile String _embeddedWebServerIp = "(Unknown)"; volatile int _embeddedWebServerPort = -1; volatile int _numNodes = -1; void setZk(String value) { _zk = value; } void setZkRoot(String value) { _zkroot = value; } void setCloudFormationTimeoutSeconds(long value) { _cloudFormationTimeoutSeconds = value; } private static long getProcessId() throws Exception { // Note: may fail in some JVM implementations // therefore fallback has to be provided // something like '<pid>@<hostname>', at least in SUN / Oracle JVMs final String jvmName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); final int index = jvmName.indexOf('@'); if (index < 1) { // part before '@' empty (index = 0) / '@' not found (index = -1) throw new Exception ("Can't get process Id"); } return Long.parseLong(jvmName.substring(0, index)); } @Override public void notifyAboutEmbeddedWebServerIpPort (InetAddress ip, int port) { _embeddedWebServerIp = ip.getHostAddress(); _embeddedWebServerPort = port; try { ZooKeeper z = ZooKeeperFactory.makeZk(_zk); byte[] payload; payload = z.getData(_zkroot, null, null); ClusterPayload cp = ClusterPayload.fromPayload(payload, ClusterPayload.class); _numNodes = cp.numNodes; if (_numNodes <= 0) { System.out.println("ERROR: numNodes must be > 0 (" + _numNodes + ")"); System.exit(1); } WorkerPayload wp = new WorkerPayload(); wp.ip = ip.getHostAddress(); wp.port = port; wp.pid = getProcessId(); payload = wp.toPayload(); z.create(_zkroot + "/nodes/", payload, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); z.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } @Override public boolean providesFlatfile() { return true; } @Override public String fetchFlatfile() throws Exception { System.out.printf("EmbeddedH2OConfig: fetchFlatfile called\n"); StringBuffer flatfile = new StringBuffer(); long startMillis = System.currentTimeMillis(); while (true) { ZooKeeper z = ZooKeeperFactory.makeZk(_zk); List<String> list = z.getChildren(_zkroot + "/nodes", true); z.close(); if (list.size() == _numNodes) { for (String child : list) { byte[] payload; String zkpath = _zkroot + "/nodes/" + child; z = ZooKeeperFactory.makeZk(_zk); payload = z.getData(zkpath, null, null); WorkerPayload wp = WorkerPayload.fromPayload(payload, WorkerPayload.class); flatfile.append(wp.ip).append(":").append(wp.port).append("\n"); z.close(); } break; } else if (list.size() > _numNodes) { System.out.println("EmbeddedH2OConfig: fetchFlatfile sees too many nodes (" + list.size() + " > " + _numNodes + ")"); System.exit(1); } long now = System.currentTimeMillis(); if (Math.abs(now - startMillis) > (_cloudFormationTimeoutSeconds * 1000)) { System.out.printf("EmbeddedH2OConfig: fetchFlatfile timed out waiting for cloud to form\n"); System.exit(1); } Thread.sleep(1000); } System.out.printf("EmbeddedH2OConfig: fetchFlatfile returned\n"); System.out.println("------------------------------------------------------------"); System.out.println(flatfile); System.out.println("------------------------------------------------------------"); return flatfile.toString(); } @Override public void notifyAboutCloudSize (InetAddress ip, int port, int size) { _embeddedWebServerIp = ip.getHostAddress(); _embeddedWebServerPort = port; System.out.printf("EmbeddedH2OConfig: notifyAboutCloudSize called (%s, %d, %d)\n", ip.getHostAddress(), port, size); if (size == _numNodes) { System.out.printf("EmbeddedH2OConfig: notifyAboutCloudSize attempting to claim master...\n"); ZooKeeper z = null; try { z = ZooKeeperFactory.makeZk(_zk); MasterPayload mp = new MasterPayload(); mp.ip = ip.getHostAddress(); mp.port = port; mp.pid = getProcessId(); byte[] payload; payload = mp.toPayload(); z.create(_zkroot + "/master", payload, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.printf("EmbeddedH2OConfig: notifyAboutCloudSize claimed master\n"); } catch (KeeperException.NodeExistsException e) { System.out.printf("EmbeddedH2OConfig: notifyAboutCloudSize lost claiming race to another node (this is normal)\n"); } catch (Exception e) { e.printStackTrace(); System.exit(1); } finally { if (z != null) { try { z.close(); } catch (Exception xe) {} } } } } @Override public void exit(int status) { System.out.printf("EmbeddedH2OConfig: exit called (%d)\n", status); System.exit(status); } @Override public void print() { System.out.println("EmbeddedH2OConfig print()"); } } public void run(String[] args) throws IOException, InterruptedException { try { water.Boot.main(UserMain.class, args); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public static void main (String[] args) { try { h2oworker m = new h2oworker(); m.run(args); } catch (Exception e) { e.printStackTrace(); } } }