package unit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * haproxy-0001: pat_match_bin list walk below LRU threshold vs O(1) map lookup. * * slow() models the defect: linked-list walk (no LRU cache, <20 entries) per request. * fast() models the fix: HashMap lookup at O(1) regardless of pattern count. * * Assert: slowOps > fastOps * 5 for P=15 patterns (below LRU threshold). */ public class HaproxyPatMatchBinAlgorithmTest { static long slowOps; static long fastOps; // ---- simulated pattern entry ------------------------------------------- static class BinPattern { final byte[] data; BinPattern(byte[] data) { this.data = data; } } // ---- slow: O(P) list walk (defect) ------------------------------------- static boolean slowMatchBin(List patterns, byte[] sample) { for (BinPattern p : patterns) { slowOps++; if (p.data.length == sample.length) { boolean eq = true; for (int i = 0; i < sample.length; i++) { if (p.data[i] != sample[i]) { eq = false; break; } } if (eq) return true; } } return false; } // ---- fast: O(1) HashMap lookup (fix) ----------------------------------- static boolean fastMatchBin(Map index, byte[] sample) { fastOps++; return index.containsKey(new String(sample)); } // ---- benchmark driver -------------------------------------------------- public static void main(String[] args) { final int P = 15; // patterns: below the LRU threshold of 20 final int REQUESTS = 10_000; List patterns = new ArrayList<>(); Map index = new HashMap<>(); for (int i = 0; i < P; i++) { byte[] data = ("pattern_key_" + i).getBytes(); BinPattern bp = new BinPattern(data); patterns.add(bp); index.put(new String(data), bp); } // Worst-case: match the last pattern (maximum list walk) byte[] sample = ("pattern_key_" + (P - 1)).getBytes(); slowOps = 0; fastOps = 0; for (int r = 0; r < REQUESTS; r++) { boolean s = slowMatchBin(patterns, sample); if (!s) throw new AssertionError("slow: pattern not found"); } for (int r = 0; r < REQUESTS; r++) { boolean f = fastMatchBin(index, sample); if (!f) throw new AssertionError("fast: pattern not found"); } long ratio = slowOps / Math.max(fastOps, 1); boolean pass = slowOps > fastOps * (P - 1); System.out.printf("haproxy-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, P - 1); System.exit(1); } } }