import java.util.*; /** * CWE-407 unit test for proxysql-0001: connection pool metrics cleanup * std::find() on vector for each entry in metrics map: O(M * S). * Fix: std::unordered_set for O(1) lookup. * * Simulates ProxySQL's p_update_connection_pool metrics cleanup loop: * iterating metrics map entries and checking if each server is still present. */ public class ProxySQLConnectionPoolMetricsTest { // --- DEFECTIVE: vector linear scan --- static List findMissingDefective(Map metricsMap, List curServers) { List missing = new ArrayList<>(); for (String key : metricsMap.keySet()) { if (!curServers.contains(key)) { // O(S) per entry missing.add(key); } } return missing; } // --- PATCHED: unordered_set lookup --- static List findMissingPatched(Map metricsMap, Set curServersSet) { List missing = new ArrayList<>(); for (String key : metricsMap.keySet()) { if (!curServersSet.contains(key)) { // O(1) per entry missing.add(key); } } return missing; } public static void main(String[] args) { int S = 500; // backend servers across hostgroups // Build current server IDs (as vector/list and set) List curServersList = new ArrayList<>(); Set curServersSet = new HashSet<>(); for (int i = 0; i < S; i++) { String id = "hg" + (i % 20) + ":" + "10.0.0." + (i % 256) + ":" + (3306 + i); curServersList.add(id); curServersSet.add(id); } // Build metrics map (slightly larger than current, some stale entries) Map metricsMap = new LinkedHashMap<>(); for (String id : curServersList) { metricsMap.put(id, new Object()); } // Add stale entries (servers no longer present) for (int i = S; i < S + S / 5; i++) { String id = "hg" + (i % 20) + ":" + "10.0.1." + (i % 256) + ":" + (3306 + i); metricsMap.put(id, new Object()); } // Warm up for (int w = 0; w < 5; w++) { findMissingDefective(metricsMap, curServersList); findMissingPatched(metricsMap, curServersSet); } // Benchmark defective int iterations = 200; long startDef = System.nanoTime(); List resultDef = null; for (int i = 0; i < iterations; i++) { resultDef = findMissingDefective(metricsMap, curServersList); } long defectiveNs = System.nanoTime() - startDef; // Benchmark patched long startPat = System.nanoTime(); List resultPat = null; for (int i = 0; i < iterations; i++) { resultPat = findMissingPatched(metricsMap, curServersSet); } long patchedNs = System.nanoTime() - startPat; double ratio = (double) defectiveNs / patchedNs; System.out.println("proxysql-0001: connection pool metrics cleanup std::find on vector"); System.out.println("S=" + S + " servers, M=" + metricsMap.size() + " metrics entries"); System.out.println("Defective missing: " + resultDef.size() + " Patched missing: " + resultPat.size()); System.out.printf("Defective: %.3f ms%n", defectiveNs / 1e6); System.out.printf("Patched: %.3f ms%n", patchedNs / 1e6); System.out.printf("Ratio: %.1fx%n", ratio); assert resultDef.size() == resultPat.size() : "Results must match!"; boolean pass = ratio > 2.0; System.out.println(pass ? "PASS" : "FAIL"); if (!pass) System.exit(1); } }