You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2016/01/19 23:47:35 UTC

incubator-kudu git commit: java: allow Java tests to run concurrently without port conflicts

Repository: incubator-kudu
Updated Branches:
  refs/heads/master 53f976f03 -> 5489476ea


java: allow Java tests to run concurrently without port conflicts

This changes the Java minicluster to use the same trick as the C++
external minicluster and generate unique loopback IPs based on the
test's pid. This should allow multiple executors to run on a single
slave without conflicts.

Change-Id: Ic96b45e305dd4da7f9e104c22f806ecdb3f78996
Reviewed-on: http://gerrit.cloudera.org:8080/1814
Tested-by: Internal Jenkins
Reviewed-by: Adar Dembo <ad...@cloudera.com>


Project: http://git-wip-us.apache.org/repos/asf/incubator-kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kudu/commit/5489476e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kudu/tree/5489476e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kudu/diff/5489476e

Branch: refs/heads/master
Commit: 5489476ea2ebfada9e25a7b52beb67ae43413510
Parents: 53f976f
Author: Todd Lipcon <to...@apache.org>
Authored: Fri Jan 15 17:12:48 2016 -0800
Committer: Todd Lipcon <to...@apache.org>
Committed: Mon Jan 18 23:35:50 2016 +0000

----------------------------------------------------------------------
 .../java/org/kududb/client/MiniKuduCluster.java | 57 ++++++++++++++++++--
 1 file changed, 54 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/5489476e/java/kudu-client/src/test/java/org/kududb/client/MiniKuduCluster.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/test/java/org/kududb/client/MiniKuduCluster.java b/java/kudu-client/src/test/java/org/kududb/client/MiniKuduCluster.java
index 7863fc8..4ec0f60 100644
--- a/java/kudu-client/src/test/java/org/kududb/client/MiniKuduCluster.java
+++ b/java/kudu-client/src/test/java/org/kududb/client/MiniKuduCluster.java
@@ -26,12 +26,18 @@ import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import sun.management.VMManagement;
+
 /**
  * Utility class to start and manipulate Kudu clusters. Relies on being IN the Kudu source code with
  * both the kudu-master and kudu-tserver binaries already compiled. {@link BaseKuduTest} should be
@@ -63,6 +69,45 @@ public class MiniKuduCluster implements AutoCloseable {
   }
 
   /**
+   * @return the local PID of this process.
+   * This is used to generate unique loopback IPs for parallel test running.
+   */
+  private static int getPid() {
+    try {
+      RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+      java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
+      jvm.setAccessible(true);
+      VMManagement mgmt = (VMManagement)jvm.get(runtime);
+      Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
+      pid_method.setAccessible(true);
+
+      return (Integer)pid_method.invoke(mgmt);
+    } catch (Exception e) {
+      LOG.warn("Cannot get PID", e);
+      return 1;
+    }
+  }
+
+  /**
+   * @return a unique loopback IP address for this PID. This allows running
+   * tests in parallel, since 127.0.0.0/8 all act as loopbacks on Linux.
+   *
+   * The generated IP is based on pid, so this requires that the parallel tests
+   * run in separate VMs.
+   *
+   * On OSX, the above trick doesn't work, so we can't run parallel tests on OSX.
+   * Given that, we just return the normal localhost IP.
+   */
+  private static String getUniqueLocalhost() {
+    if ("Mac OS X".equals(System.getProperty("os.name"))) {
+      return "127.0.0.1";
+    }
+
+    int pid = getPid();
+    return "127." + ((pid & 0xff00) >> 8) + "." + (pid & 0xff) + ".1";
+  }
+
+  /**
    * Starts a Kudu cluster composed of the provided masters and tablet servers.
    * @param numMasters how many masters to start
    * @param numTservers how many tablet servers to start
@@ -73,6 +118,7 @@ public class MiniKuduCluster implements AutoCloseable {
     Preconditions.checkArgument(numTservers > 0, "Need at least one tablet server");
     // The following props are set via kudu-client's pom.
     String baseDirPath = TestUtils.getBaseDir();
+    String localhost = getUniqueLocalhost();
 
     long now = System.currentTimeMillis();
     LOG.info("Starting {} masters...", numMasters);
@@ -88,7 +134,9 @@ public class MiniKuduCluster implements AutoCloseable {
           "--fs_wal_dir=" + dataDirPath,
           "--fs_data_dirs=" + dataDirPath,
           "--tserver_master_addrs=" + masterAddresses,
-          "--rpc_bind_addresses=127.0.0.1:" + port};
+          "--webserver_interface=" + localhost,
+          "--local_ip_for_outbound_sockets=" + localhost,
+          "--rpc_bind_addresses=" + localhost + ":" + port};
       tserverProcesses.put(port, configureAndStartProcess(tsCmdLine));
       port++;
 
@@ -116,6 +164,7 @@ public class MiniKuduCluster implements AutoCloseable {
     // Get the list of web and RPC ports to use for the master consensus configuration:
     // request NUM_MASTERS * 2 free ports as we want to also reserve the web
     // ports for the consensus configuration.
+    String localhost = getUniqueLocalhost();
     List<Integer> ports = TestUtils.findFreePorts(masterStartPort, numMasters * 2);
     int lastFreePort = ports.get(ports.size() - 1);
     List<Integer> masterRpcPorts = Lists.newArrayListWithCapacity(numMasters);
@@ -123,7 +172,7 @@ public class MiniKuduCluster implements AutoCloseable {
     for (int i = 0; i < numMasters * 2; i++) {
       if (i % 2 == 0) {
         masterRpcPorts.add(ports.get(i));
-        masterHostPorts.add(HostAndPort.fromParts("127.0.0.1", ports.get(i)));
+        masterHostPorts.add(HostAndPort.fromParts(localhost, ports.get(i)));
       } else {
         masterWebPorts.add(ports.get(i));
       }
@@ -145,7 +194,9 @@ public class MiniKuduCluster implements AutoCloseable {
           "--flagfile=" + flagsPath,
           "--fs_wal_dir=" + dataDirPath,
           "--fs_data_dirs=" + dataDirPath,
-          "--rpc_bind_addresses=127.0.0.1:" + masterRpcPorts.get(i),
+          "--webserver_interface=" + localhost,
+          "--local_ip_for_outbound_sockets=" + localhost,
+          "--rpc_bind_addresses=" + localhost + ":" + masterRpcPorts.get(i),
           "--webserver_port=" + masterWebPorts.get(i));
       if (numMasters > 1) {
         masterCmdLine.add("--master_addresses=" + masterAddresses);