package unit; import java.util.HashMap; import java.util.Map; /** * nginx-0001: ngx_http_upstream_cache_get linear name scan vs O(1) hash lookup. * * slow() models the defect: iterates all cache zone names with string comparison. * fast() models the fix: uses a HashMap keyed on zone name. * * Assert: slowOps > fastOps * 5 for N=16 zones. */ public class NginxCacheGetAlgorithmTest { static long slowOps; static long fastOps; // ---- simulated cache zone entry ---------------------------------------- static class CacheZone { final String name; CacheZone(String name) { this.name = name; } } // ---- slow: O(n) linear strncmp scan (defect) --------------------------- static CacheZone slowFindCache(CacheZone[] zones, String val) { for (CacheZone z : zones) { slowOps++; // one comparison per zone if (z.name.equals(val)) return z; } return null; } // ---- fast: O(1) hash lookup (fix) -------------------------------------- static CacheZone fastFindCache(Map index, String val) { fastOps++; // one map lookup return index.get(val); } // ---- benchmark driver -------------------------------------------------- public static void main(String[] args) { final int N = 16; // cache zones final int REQUESTS = 10_000; // Build zone array and lookup index CacheZone[] zones = new CacheZone[N]; Map index = new HashMap<>(); for (int i = 0; i < N; i++) { zones[i] = new CacheZone("cache_zone_" + i); index.put(zones[i].name, zones[i]); } // Worst-case lookup: always the last zone (max linear scan) String target = "cache_zone_" + (N - 1); slowOps = 0; fastOps = 0; for (int r = 0; r < REQUESTS; r++) { CacheZone s = slowFindCache(zones, target); if (s == null) throw new AssertionError("slow: zone not found"); } for (int r = 0; r < REQUESTS; r++) { CacheZone f = fastFindCache(index, target); if (f == null) throw new AssertionError("fast: zone not found"); } long ratio = slowOps / Math.max(fastOps, 1); boolean pass = slowOps > fastOps * (N - 1); System.out.printf("nginx-0001 slow=%d fast=%d ratio=%dx %s%n", slowOps, fastOps, ratio, pass ? "PASS" : "FAIL"); if (!pass) { System.err.printf("FAIL: expected slowOps(%d) > fastOps(%d) * %d%n", slowOps, fastOps, N - 1); System.exit(1); } } }