@@ -197,7 +197,6 @@ public abstract class ESTestCase extends LuceneTestCase {
197
197
private static final AtomicInteger portGenerator = new AtomicInteger ();
198
198
199
199
private static final Collection <String > loggedLeaks = new ArrayList <>();
200
- public static final int MIN_PRIVATE_PORT = 13301 ;
201
200
202
201
private HeaderWarningAppender headerWarningAppender ;
203
202
@@ -1708,38 +1707,71 @@ public static boolean inFipsJvm() {
1708
1707
return Boolean .parseBoolean (System .getProperty (FIPS_SYSPROP ));
1709
1708
}
1710
1709
1710
+ /*
1711
+ * [NOTE: Port ranges for tests]
1712
+ *
1713
+ * Some tests involve interactions over the localhost interface of the machine running the tests. The tests run concurrently in multiple
1714
+ * JVMs, but all have access to the same network, so there's a risk that different tests will interact with each other in unexpected
1715
+ * ways and trigger spurious failures. Gradle numbers its workers sequentially starting at 1 and each worker can determine its own
1716
+ * identity from the {@link #TEST_WORKER_SYS_PROPERTY} system property. We use this to try and assign disjoint port ranges to each test
1717
+ * worker, avoiding any unexpected interactions, although if we spawn enough test workers then we will wrap around to the beginning
1718
+ * again.
1719
+ */
1720
+
1711
1721
/**
1712
- * Returns a unique port range for this JVM starting from the computed base port
1722
+ * Defines the size of the port range assigned to each worker, which must be large enough to supply enough ports to run the tests, but
1723
+ * not so large that we run out of ports. See also [NOTE: Port ranges for tests].
1713
1724
*/
1714
- public static String getPortRange () {
1715
- return getBasePort () + "-" + (getBasePort () + 99 ); // upper bound is inclusive
1725
+ private static final int PORTS_PER_WORKER = 30 ;
1726
+
1727
+ /**
1728
+ * Defines the minimum port that test workers should use. See also [NOTE: Port ranges for tests].
1729
+ */
1730
+ protected static final int MIN_PRIVATE_PORT = 13301 ;
1731
+
1732
+ /**
1733
+ * Defines the maximum port that test workers should use. See also [NOTE: Port ranges for tests].
1734
+ */
1735
+ private static final int MAX_PRIVATE_PORT = 36600 ;
1736
+
1737
+ /**
1738
+ * Wrap around after reaching this worker ID.
1739
+ */
1740
+ private static final int MAX_EFFECTIVE_WORKER_ID = (MAX_PRIVATE_PORT - MIN_PRIVATE_PORT - PORTS_PER_WORKER + 1 ) / PORTS_PER_WORKER - 1 ;
1741
+
1742
+ static {
1743
+ assert getWorkerBasePort (MAX_EFFECTIVE_WORKER_ID ) + PORTS_PER_WORKER - 1 <= MAX_PRIVATE_PORT ;
1716
1744
}
1717
1745
1718
- protected static int getBasePort () {
1719
- // some tests use MockTransportService to do network based testing. Yet, we run tests in multiple JVMs that means
1720
- // concurrent tests could claim port that another JVM just released and if that test tries to simulate a disconnect it might
1721
- // be smart enough to re-connect depending on what is tested. To reduce the risk, since this is very hard to debug we use
1722
- // a different default port range per JVM unless the incoming settings override it
1723
- // use a non-default base port otherwise some cluster in this JVM might reuse a port
1746
+ /**
1747
+ * Returns a port range for this JVM according to its Gradle worker ID. See also [NOTE: Port ranges for tests].
1748
+ */
1749
+ public static String getPortRange () {
1750
+ final int firstPort = getWorkerBasePort ();
1751
+ final int lastPort = firstPort + PORTS_PER_WORKER - 1 ; // upper bound is inclusive
1752
+ assert MIN_PRIVATE_PORT <= firstPort && lastPort <= MAX_PRIVATE_PORT ;
1753
+ return firstPort + "-" + lastPort ;
1754
+ }
1724
1755
1725
- // We rely on Gradle implementation details here, the worker IDs are long values incremented by one for the
1726
- // lifespan of the daemon this means that they can get larger than the allowed port range.
1727
- // Ephemeral ports on Linux start at 32768 so we modulo to make sure that we don't exceed that.
1728
- // This is safe as long as we have fewer than 224 Gradle workers running in parallel
1729
- // See also: https://github.com/elastic/elasticsearch/issues/44134
1756
+ /**
1757
+ * Returns the start of the port range for this JVM according to its Gradle worker ID. See also [NOTE: Port ranges for tests].
1758
+ */
1759
+ protected static int getWorkerBasePort () {
1730
1760
final String workerIdStr = System .getProperty (ESTestCase .TEST_WORKER_SYS_PROPERTY );
1731
- final int startAt ;
1732
1761
if (workerIdStr == null ) {
1733
- startAt = 0 ; // IDE
1734
- } else {
1735
- // we adjust the gradle worker id with mod so as to not go over the ephemoral port ranges, but gradle continually
1736
- // increases this value, so the mod can eventually become zero, thus we shift on both sides by 1
1737
- final long workerId = Long .valueOf (workerIdStr );
1738
- assert workerId >= 1 : "Non positive gradle worker id: " + workerIdStr ;
1739
- startAt = (int ) Math .floorMod (workerId - 1 , 223L ) + 1 ;
1762
+ // running in IDE
1763
+ return MIN_PRIVATE_PORT ;
1740
1764
}
1741
- assert startAt >= 0 : "Unexpected test worker Id, resulting port range would be negative" ;
1742
- return MIN_PRIVATE_PORT + (startAt * 100 );
1765
+
1766
+ final int workerId = Integer .parseInt (workerIdStr );
1767
+ assert workerId >= 1 : "Non positive gradle worker id: " + workerIdStr ;
1768
+ return getWorkerBasePort (workerId % (MAX_EFFECTIVE_WORKER_ID + 1 ));
1769
+ }
1770
+
1771
+ private static int getWorkerBasePort (int effectiveWorkerId ) {
1772
+ assert 0 <= effectiveWorkerId && effectiveWorkerId <= MAX_EFFECTIVE_WORKER_ID ;
1773
+ // the range [MIN_PRIVATE_PORT, MIN_PRIVATE_PORT+PORTS_PER_WORKER) is only for running outside of Gradle
1774
+ return MIN_PRIVATE_PORT + PORTS_PER_WORKER + effectiveWorkerId * PORTS_PER_WORKER ;
1743
1775
}
1744
1776
1745
1777
protected static InetAddress randomIp (boolean v4 ) {
0 commit comments