package unit; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; /** * flink-0001: JobGraph user-jar dedup — List.contains() O(n²) vs LinkedHashSet O(n). * * Standalone unit test — no JUnit required. * Compile: javac -d . FlinkJobGraphJarDedupTest.java * Run: java unit.FlinkJobGraphJarDedupTest */ public class FlinkJobGraphJarDedupTest { static long slowOps; static long fastOps; /** Simulates JobGraph.addJar() with ArrayList — O(n) contains per add. */ static List slowAddJars(List jars) { slowOps = 0; List userJars = new ArrayList<>(); for (String jar : jars) { slowOps++; // entry into addJar() for (String existing : userJars) { // ArrayList.contains() scan slowOps++; if (existing.equals(jar)) break; } if (!userJars.contains(jar)) { userJars.add(jar); } } return userJars; } /** Patched: LinkedHashSet.add() is O(1) amortised — no scan needed. */ static List fastAddJars(List jars) { fastOps = 0; LinkedHashSet userJars = new LinkedHashSet<>(); for (String jar : jars) { fastOps++; // O(1) hash add — single op per entry userJars.add(jar); } return new ArrayList<>(userJars); } static void run(int n, int expectedNx) { List jars = new ArrayList<>(); for (int i = 0; i < n; i++) jars.add("jar-" + i + ".jar"); // add duplicates at the end to stress the dedup path for (int i = 0; i < n; i++) jars.add("jar-" + i + ".jar"); List slowResult = slowAddJars(jars); List fastResult = fastAddJars(jars); boolean resultsMatch = slowResult.equals(fastResult); boolean quadraticWorse = slowOps > fastOps * expectedNx; System.out.printf("n=%-4d slow=%6d fast=%4d ratio=%5.1fx match=%b PASS=%b%n", n, slowOps, fastOps, (double) slowOps / fastOps, resultsMatch, resultsMatch && quadraticWorse); if (!resultsMatch || !quadraticWorse) { throw new AssertionError( "FAIL n=" + n + " resultsMatch=" + resultsMatch + " slowOps=" + slowOps + " fastOps=" + fastOps + " needed ratio>" + expectedNx); } } public static void main(String[] args) { System.out.println("=== flink-0001: JobGraph jar dedup O(n^2) vs O(n) ==="); run(50, 5); run(200, 10); run(500, 20); System.out.println("3/3 PASS"); } }