96 lines
3.7 KiB
Java
96 lines
3.7 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* CWE-407 unit test for proxysql-0001: connection pool metrics cleanup
|
|
* std::find() on vector<string> for each entry in metrics map: O(M * S).
|
|
* Fix: std::unordered_set<string> 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<String> findMissingDefective(Map<String, Object> metricsMap, List<String> curServers) {
|
|
List<String> 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<String> findMissingPatched(Map<String, Object> metricsMap, Set<String> curServersSet) {
|
|
List<String> 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<String> curServersList = new ArrayList<>();
|
|
Set<String> 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<String, Object> 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<String> 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<String> 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);
|
|
}
|
|
}
|