package unit; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; /** * pulsar-0005 — PartialRoundRobinMessageRouterImpl CopyOnWriteArrayList.contains O(N×L) → HashSet O(N) * * The hot path in getOrCreatePartialList() is the filter lambda: * .filter(e -> !partialList.contains(e)) * * This benchmark isolates the membership test — N calls to contains() * over a CopyOnWriteArrayList of size L vs a HashSet snapshot. * * SLOW: CopyOnWriteArrayList.contains(e) → O(L) per call → O(N × L) total * FAST: HashSet.contains(e) → O(1) per call → O(N) total */ public class PulsarPartialRoundRobinRouterTest { static long benchSlow(int N, int L) { CopyOnWriteArrayList partialList = new CopyOnWriteArrayList<>(); for (int i = 0; i < L; i++) { partialList.add(i * 2); // even indices present } long start = System.nanoTime(); int found = 0; for (int i = 0; i < N; i++) { if (!partialList.contains(i)) found++; // O(L) per call } return System.nanoTime() - start; } static long benchFast(int N, int L) { CopyOnWriteArrayList partialList = new CopyOnWriteArrayList<>(); for (int i = 0; i < L; i++) { partialList.add(i * 2); } // FIX: snapshot to HashSet before the filter loop Set existing = new HashSet<>(partialList); long start = System.nanoTime(); int found = 0; for (int i = 0; i < N; i++) { if (!existing.contains(i)) found++; // O(1) per call } return System.nanoTime() - start; } public static void main(String[] args) { int passed = 0; int failed = 0; int minRatio = 5; // [N = numPartitions, L = partialList.size() at expand time] int[][] cases = { {500, 250}, {2000, 1000}, {5000, 2500}, }; // warmup for (int w = 0; w < 3; w++) { benchSlow(200, 100); benchFast(200, 100); } for (int[] c : cases) { int N = c[0]; int L = c[1]; long slowTotal = 0, fastTotal = 0; int reps = 10; for (int r = 0; r < reps; r++) { slowTotal += benchSlow(N, L); fastTotal += benchFast(N, L); } long slowAvg = slowTotal / reps; long fastAvg = fastTotal / reps; double ratio = fastAvg > 0 ? (double) slowAvg / fastAvg : 999.0; boolean ok = ratio >= minRatio; System.out.printf(" N=%-5d L=%-5d slow=%8dns fast=%7dns ratio=%.1fx %s%n", N, L, slowAvg, fastAvg, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; else failed++; } System.out.printf("%nTotal: %d/%d PASS%n", passed, passed + failed); if (failed > 0) System.exit(1); } }