package unit; import java.util.*; /** * sqlalchemy-0003: evaluated_keys list → set in _apply_evaluators() * * Models SQLAlchemy bulk_persistence.py _apply_evaluators(): * evaluated_keys = list(value_evaluators.keys()) * then: c.key not in evaluated_keys (inside set comprehension over prefetch_cols) * and: .difference(evaluated_keys) (set subtraction) * * Fix: evaluated_keys = set(value_evaluators) * * Standalone Java — no JUnit required. */ public class EvaluatedKeysAlgorithm { // ----------------------------------------------------------------------- // Simulated column model // ----------------------------------------------------------------------- static class Column { final String key; Column(String key) { this.key = key; } @Override public boolean equals(Object o) { return o instanceof Column && ((Column) o).key.equals(this.key); } @Override public int hashCode() { return key.hashCode(); } } // ----------------------------------------------------------------------- // SLOW: evaluated_keys as plain List // ----------------------------------------------------------------------- static Result slowApplyEvaluators(Map valueEvaluators, List prefetchCols, List postfetchCols) { List evaluatedKeys = new ArrayList<>(valueEvaluators.keySet()); // ← plain list // to_prefetch: {c for c in prefetch_cols if c.key not in evaluated_keys} Set toPrefetch = new HashSet<>(); for (Column c : prefetchCols) { if (!evaluatedKeys.contains(c.key)) { // ← O(K) scan toPrefetch.add(c); } } // to_expire = {col.key for col in postfetch_cols}.difference(evaluated_keys) Set toExpire = new HashSet<>(); for (Column c : postfetchCols) { toExpire.add(c.key); } toExpire.removeAll(evaluatedKeys); // removeAll(List) = O(P×K) return new Result(toPrefetch, toExpire); } // ----------------------------------------------------------------------- // FAST: evaluated_keys as HashSet // ----------------------------------------------------------------------- static Result fastApplyEvaluators(Map valueEvaluators, List prefetchCols, List postfetchCols) { Set evaluatedKeys = new HashSet<>(valueEvaluators.keySet()); // ← set (or just use valueEvaluators directly) Set toPrefetch = new HashSet<>(); for (Column c : prefetchCols) { if (!evaluatedKeys.contains(c.key)) { // ← O(1) toPrefetch.add(c); } } Set toExpire = new HashSet<>(); for (Column c : postfetchCols) { toExpire.add(c.key); } toExpire.removeAll(evaluatedKeys); // removeAll(Set) = O(P) return new Result(toPrefetch, toExpire); } static class Result { final Set toPrefetch; final Set toExpire; Result(Set toPrefetch, Set toExpire) { this.toPrefetch = toPrefetch; this.toExpire = toExpire; } } // ----------------------------------------------------------------------- // Test helpers // ----------------------------------------------------------------------- static Map makeEvaluators(int n) { Map m = new LinkedHashMap<>(); for (int i = 0; i < n; i++) { m.put("eval_key_" + i, new Object()); } return m; } static List makeCols(int n, String prefix) { List cols = new ArrayList<>(); for (int i = 0; i < n; i++) { cols.add(new Column(prefix + i)); } return cols; } // ----------------------------------------------------------------------- // Main // ----------------------------------------------------------------------- public static void main(String[] args) { int passed = 0; int total = 0; // ---- Correctness: basic case ---- { Map evals = new LinkedHashMap<>(); evals.put("col_a", new Object()); evals.put("col_b", new Object()); List prefetch = Arrays.asList( new Column("col_a"), // in evaluatedKeys → NOT in toPrefetch new Column("col_c"), // not in evaluatedKeys → in toPrefetch new Column("col_d") // not in evaluatedKeys → in toPrefetch ); List postfetch = Arrays.asList( new Column("col_a"), // in evaluatedKeys → NOT in toExpire new Column("col_b"), // in evaluatedKeys → NOT in toExpire new Column("col_e") // not in evaluatedKeys → in toExpire ); Result slow = slowApplyEvaluators(evals, prefetch, postfetch); Result fast = fastApplyEvaluators(evals, prefetch, postfetch); total++; assert slow.toPrefetch.size() == fast.toPrefetch.size() : "toPrefetch size: slow=" + slow.toPrefetch.size() + " fast=" + fast.toPrefetch.size(); assert slow.toExpire.size() == fast.toExpire.size() : "toExpire size: slow=" + slow.toExpire.size() + " fast=" + fast.toExpire.size(); assert slow.toPrefetch.size() == 2 : "expected 2 in toPrefetch, got " + slow.toPrefetch.size(); assert slow.toExpire.size() == 1 : "expected 1 in toExpire, got " + slow.toExpire.size(); System.out.println("PASS 1/4: correctness basic case"); passed++; } // ---- Correctness: empty evaluators ---- { Map evals = new HashMap<>(); List prefetch = Arrays.asList(new Column("c1"), new Column("c2")); List postfetch = Arrays.asList(new Column("c3")); Result slow = slowApplyEvaluators(evals, prefetch, postfetch); Result fast = fastApplyEvaluators(evals, prefetch, postfetch); total++; assert slow.toPrefetch.size() == fast.toPrefetch.size() : "empty evals toPrefetch mismatch"; assert slow.toExpire.size() == fast.toExpire.size() : "empty evals toExpire mismatch"; // When no evaluators, all cols go to prefetch, all to expire assert slow.toPrefetch.size() == 2 : "expected 2 prefetch"; assert slow.toExpire.size() == 1 : "expected 1 expire"; System.out.println("PASS 2/4: correctness empty evaluators"); passed++; } // ---- Performance: N=1000 evaluated keys, 2000 cols ---- { int K = 1000; int C = 2000; Map evals = makeEvaluators(K); // half prefetch cols are in evaluated keys List prefetch = new ArrayList<>(); for (int i = 0; i < C/2; i++) prefetch.add(new Column("eval_key_" + i)); for (int i = 0; i < C/2; i++) prefetch.add(new Column("other_" + i)); List postfetch = new ArrayList<>(); for (int i = 0; i < C/2; i++) postfetch.add(new Column("eval_key_" + i)); for (int i = 0; i < C/2; i++) postfetch.add(new Column("post_" + i)); long t0 = System.nanoTime(); for (int iter = 0; iter < 10; iter++) slowApplyEvaluators(evals, prefetch, postfetch); long slowNs = (System.nanoTime() - t0) / 10; long t1 = System.nanoTime(); for (int iter = 0; iter < 10; iter++) fastApplyEvaluators(evals, prefetch, postfetch); long fastNs = (System.nanoTime() - t1) / 10; double ratio = (double) slowNs / fastNs; total++; System.out.printf("PERF 3/4: sqlalchemy-0003 K=%d C=%d slow=%dms fast=%dms ratio=%.1fx%n", K, C, slowNs/1_000_000, fastNs/1_000_000, ratio); assert ratio >= 5.0 : "ratio too low: " + ratio; System.out.println("PASS 3/4: sqlalchemy-0003 ratio >= 5x"); passed++; } // ---- Edge case: all cols in evaluated_keys ---- { Map evals = makeEvaluators(50); List prefetch = new ArrayList<>(); List postfetch = new ArrayList<>(); for (int i = 0; i < 50; i++) { prefetch.add(new Column("eval_key_" + i)); postfetch.add(new Column("eval_key_" + i)); } Result slow = slowApplyEvaluators(evals, prefetch, postfetch); Result fast = fastApplyEvaluators(evals, prefetch, postfetch); total++; assert slow.toPrefetch.isEmpty() && fast.toPrefetch.isEmpty() : "all-in-evals toPrefetch not empty"; assert slow.toExpire.isEmpty() && fast.toExpire.isEmpty() : "all-in-evals toExpire not empty"; System.out.println("PASS 4/4: edge case all cols in evaluated_keys"); passed++; } System.out.printf("%n%d/%d PASS%n", passed, total); if (passed < total) throw new AssertionError("Some tests failed"); } }