package unit; import java.util.HashMap; /** * uwsgi-0001: HTTP header deduplication O(H^2) vs O(H) * * Models the uWSGI pattern: for each incoming header, scan the * previously-seen-header linked list to find duplicates (O(H) per header, * O(H^2) total). Fix: use a HashMap for O(1) lookup. * * Worst-case input: all-unique header names. For each header H_i, the slow * path must walk the entire list built so far (i-1 entries) and find nothing. * Total comparisons = 0+1+2+...+(H-1) = H*(H-1)/2 = O(H^2). */ public class UwsgiHeaderDedupAlgorithm { // ---- SLOW: linked-list scan (mirrors uwsgi_string_list_has_item) -------- static class ListEntry { String key; String value; ListEntry next; ListEntry(String k, String v) { key = k; value = v; } } static long slowOps; static ListEntry listFind(ListEntry head, String key) { ListEntry cur = head; while (cur != null) { slowOps++; if (cur.key.equalsIgnoreCase(key)) return cur; cur = cur.next; } return null; } /** Parse H unique header names using linked-list dedup. */ static void slowDedup(String[] headers) { slowOps = 0; ListEntry head = null, tail = null; for (String h : headers) { ListEntry found = listFind(head, h); if (found != null) { found.value = found.value + ", " + h; } else { ListEntry e = new ListEntry(h, h); if (head == null) { head = tail = e; } else { tail.next = e; tail = e; } } } } // ---- FAST: HashMap lookup O(1) per header -------------------------------- static long fastOps; static void fastDedup(String[] headers) { fastOps = 0; HashMap map = new HashMap<>(); for (String h : headers) { fastOps++; // one O(1) map operation String lk = h.toLowerCase(); if (map.containsKey(lk)) { map.put(lk, map.get(lk) + ", " + h); } else { map.put(lk, h); } } } // ---- Test ---------------------------------------------------------------- static boolean pass = true; static void test(String name, int N, int minRatio) { // Worst case: all-unique header names — maximises the list-scan cost // because each new header must scan all prior entries and finds nothing String[] headers = new String[N]; for (int i = 0; i < N; i++) { headers[i] = "X-Header-" + i; } slowDedup(headers); fastDedup(headers); long sOps = slowOps; long fOps = fastOps; double ratio = (fOps > 0) ? (double) sOps / fOps : sOps; boolean ok = ratio >= minRatio; if (!ok) pass = false; System.out.printf("%-40s N=%4d slow=%7d fast=%4d ratio=%6.1fx %s%n", name, N, sOps, fOps, ratio, ok ? "PASS" : "FAIL"); } static void testCorrectness() { // Verify both algorithms produce same number of unique keys String[] input = {"Cookie", "Cookie", "Accept", "X-Foo", "Cookie", "Accept"}; // Slow slowOps = 0; ListEntry head = null, tail = null; for (String h : input) { ListEntry found = listFind(head, h); if (found != null) { found.value += ",v"; } else { ListEntry e = new ListEntry(h, h); if (head == null) { head = tail = e; } else { tail.next = e; tail = e; } } } int slowUnique = 0; for (ListEntry c = head; c != null; c = c.next) slowUnique++; // Fast fastOps = 0; HashMap map = new HashMap<>(); for (String h : input) { fastOps++; String lk = h.toLowerCase(); if (map.containsKey(lk)) map.put(lk, map.get(lk) + ",v"); else map.put(lk, h); } int fastUnique = map.size(); boolean ok = slowUnique == fastUnique && slowUnique == 3; if (!ok) pass = false; System.out.printf("%-40s correctness: slow=%d fast=%d unique %s%n", "correctness-check", slowUnique, fastUnique, ok ? "PASS" : "FAIL"); } public static void main(String[] args) { System.out.println("uwsgi-0001: HTTP header dedup O(H^2) -> O(H)"); System.out.println("=".repeat(72)); testCorrectness(); test("all-unique/N=50", 50, 5); test("all-unique/N=100", 100, 20); test("all-unique/N=200", 200, 50); test("all-unique/N=500", 500, 100); System.out.println("=".repeat(72)); if (!pass) { System.out.println("RESULT: FAIL"); System.exit(1); } System.out.println("RESULT: PASS"); } }