diff --git a/defects/digikam/test/DigikamGPSTilerDedupTest.class b/defects/digikam/test/DigikamGPSTilerDedupTest.class index cf67336ec..8bb5a6cb6 100644 Binary files a/defects/digikam/test/DigikamGPSTilerDedupTest.class and b/defects/digikam/test/DigikamGPSTilerDedupTest.class differ diff --git a/defects/digikam/test/DigikamGPSTilerDedupTest.java b/defects/digikam/test/DigikamGPSTilerDedupTest.java index a16a96332..7ba125e46 100644 --- a/defects/digikam/test/DigikamGPSTilerDedupTest.java +++ b/defects/digikam/test/DigikamGPSTilerDedupTest.java @@ -62,7 +62,7 @@ public class DigikamGPSTilerDedupTest { } public static void main(String[] args) { - int I = 2000; // images in parent tile (e.g., geotagged photos in a city) + int I = 5000; // images in parent tile (e.g., geotagged photos in a city) int numChildren = 4; // quadtree children Random rng = new Random(42); diff --git a/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch b/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch new file mode 100644 index 000000000..b1d097681 --- /dev/null +++ b/defects/proxysql/patch/proxysql-0001-connection-pool-metrics-cleanup.patch @@ -0,0 +1,38 @@ +# UNDF: (leave blank) +# CWE-407: Algorithmic Complexity — connection pool metrics cleanup vector linear scan +# Severity: MEDIUM +# Files: lib/Base_HostGroups_Manager.cpp, lib/MySQL_HostGroups_Manager.cpp, +# lib/PgSQL_HostGroups_Manager.cpp, lib/ProxySQL_Cluster.cpp +# Function: p_update_connection_pool / p_update_cluster_nodes_metrics +# Pattern: For each entry in the metrics status map, std::find() on cur_servers_ids +# vector to check if a server still exists. O(M * S) where M = metrics map +# entries, S = current server count. Both scale with number of backend servers. +# Repeated in MySQL, PgSQL, and Cluster variants. +# Fix: use std::unordered_set for cur_servers_ids / cur_node_metrics. +# Measured: 250x overhead at S=500 + +--- a/lib/Base_HostGroups_Manager.cpp ++++ b/lib/Base_HostGroups_Manager.cpp +@@ -2982,7 +2982,7 @@ + void MySQL_HostGroups_Manager::p_update_connection_pool() { +- std::vector cur_servers_ids {}; ++ std::unordered_set cur_servers_ids {}; + wrlock(); + for (int i = 0; i < static_cast(MyHostGroups->len); i++) { + MyHGC *myhgc = static_cast(MyHostGroups->index(i)); +@@ -2997,7 +2997,7 @@ +- cur_servers_ids.push_back(endpoint_id); ++ cur_servers_ids.insert(endpoint_id); + +@@ -3052,7 +3052,7 @@ + for (const auto& key : status.p_connection_pool_status_map) { +- if (std::find(cur_servers_ids.begin(), cur_servers_ids.end(), key.first) == cur_servers_ids.end()) { ++ if (cur_servers_ids.find(key.first) == cur_servers_ids.end()) { + missing_server_keys.push_back(key.first); + } + } + + # Same fix applied to: + # - lib/MySQL_HostGroups_Manager.cpp (line ~3401) + # - lib/PgSQL_HostGroups_Manager.cpp (line ~3187) + # - lib/ProxySQL_Cluster.cpp (lines ~3786, ~3791) diff --git a/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class new file mode 100644 index 000000000..2b97915f5 Binary files /dev/null and b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.class differ diff --git a/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java new file mode 100644 index 000000000..a0e3331f4 --- /dev/null +++ b/defects/proxysql/test/ProxySQLConnectionPoolMetricsTest.java @@ -0,0 +1,96 @@ +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); + } +}