package unit; import java.util.*; /** * EnvoyTest — CWE-407 benchmark for envoy-0001 * * envoy-0001: PreviousHostsRetryPredicate shouldSelectAnotherHost() * SLOW: std::find on std::vector — O(attempted) per call * FAST: absl::flat_hash_set::contains — O(1) per call * * Model: R retry attempts, each calling shouldSelectAnotherHost once. * After each attempt, onHostAttempted adds the host to the collection. * Total ops slow: 0 + 1 + 2 + ... + (R-1) = R*(R-1)/2 → O(R²) * Total ops fast: R × 1 = R → O(R) */ public class EnvoyTest { // ------------------------------------------------------------------------- // Simulated host type — identity by object reference (pointer in C++) // ------------------------------------------------------------------------- static class Host { final int id; Host(int id) { this.id = id; } } // ------------------------------------------------------------------------- // SLOW: vector + linear find // ------------------------------------------------------------------------- static long retryPredicate_slow(Host[] candidateHosts, int maxAttempts) { List attemptedHosts = new ArrayList<>(); long ops = 0; for (int attempt = 0; attempt < maxAttempts && attempt < candidateHosts.length; attempt++) { Host candidate = candidateHosts[attempt]; // shouldSelectAnotherHost: O(attempted) scan for (Host h : attemptedHosts) { ops++; if (h == candidate) break; } // onHostAttempted attemptedHosts.add(candidate); } return ops; } // ------------------------------------------------------------------------- // FAST: hash set + O(1) contains // ------------------------------------------------------------------------- static long retryPredicate_fast(Host[] candidateHosts, int maxAttempts) { Set attemptedHosts = new HashSet<>(); long ops = 0; for (int attempt = 0; attempt < maxAttempts && attempt < candidateHosts.length; attempt++) { Host candidate = candidateHosts[attempt]; // shouldSelectAnotherHost: O(1) hash lookup — count as 1 op ops++; attemptedHosts.contains(candidate); // onHostAttempted attemptedHosts.add(candidate); } return ops; } // ------------------------------------------------------------------------- // Helpers // ------------------------------------------------------------------------- static Host[] makeHosts(int n) { Host[] hosts = new Host[n]; for (int i = 0; i < n; i++) hosts[i] = new Host(i); return hosts; } static void bench(String label, long sOps, long fOps) { System.out.printf(" %-50s slow=%7d fast=%5d ratio=%5.1fx%n", label, sOps, fOps, (double) sOps / Math.max(fOps, 1)); } // ------------------------------------------------------------------------- // Main // ------------------------------------------------------------------------- public static void main(String[] args) { System.out.println("EnvoyTest — CWE-407 envoy-0001 retry predicate linear scan"); System.out.println(); // --- R=50 retries, H=50 candidate hosts --- { int R = 50; Host[] hosts = makeHosts(R); long sOps = retryPredicate_slow(hosts, R); long fOps = retryPredicate_fast(hosts, R); bench("retry R=50 (each host attempted once)", sOps, fOps); assert sOps > fOps * 10 : "Expected slow >> fast, got slow=" + sOps + " fast=" + fOps; } // --- R=100 retries --- { int R = 100; Host[] hosts = makeHosts(R); long sOps = retryPredicate_slow(hosts, R); long fOps = retryPredicate_fast(hosts, R); bench("retry R=100", sOps, fOps); assert sOps > fOps * 25 : "Expected slow >> fast, got slow=" + sOps + " fast=" + fOps; } // --- R=200 retries (large cluster, high retry budget) --- { int R = 200; Host[] hosts = makeHosts(R); long sOps = retryPredicate_slow(hosts, R); long fOps = retryPredicate_fast(hosts, R); bench("retry R=200", sOps, fOps); assert sOps > fOps * 50 : "Expected slow >> fast, got slow=" + sOps + " fast=" + fOps; } // --- R=500 retries (stress: Envoy max_attempts=500) --- { int R = 500; Host[] hosts = makeHosts(R); long sOps = retryPredicate_slow(hosts, R); long fOps = retryPredicate_fast(hosts, R); bench("retry R=500 (stress)", sOps, fOps); assert sOps > fOps * 100 : "Expected slow >> fast, got slow=" + sOps + " fast=" + fOps; } System.out.println(); System.out.println("All assertions passed."); } }