import java.util.*; /** * Java simulation unit test for Loki CWE-407 defect. * Simulates the O(E^2) edge dedup pattern in Loki's DAG implementation. * * loki-0001: DAG AddEdge slices.Contains on children/parents O(E^2) * * In practice, Loki query plans have small fan-out (1-3 children per node), * so this is LOW severity. The test uses synthetic high fan-out to * demonstrate the algorithmic defect. */ public class LokiTest { // --------------------------------------------------------------- // loki-0001: DAG AddEdge edge dedup O(E^2) vs O(E) // --------------------------------------------------------------- /** BEFORE: linear scan of children list for uniqueness */ static class DagBefore { Map> children = new HashMap<>(); Map> parents = new HashMap<>(); void addEdge(String parent, String child) { children.computeIfAbsent(parent, k -> new ArrayList<>()); parents.computeIfAbsent(child, k -> new ArrayList<>()); List ch = children.get(parent); if (!ch.contains(child)) { // O(E) linear scan ch.add(child); } List pa = parents.get(child); if (!pa.contains(parent)) { // O(E) linear scan pa.add(parent); } } } /** AFTER: parallel set for O(1) membership */ static class DagAfter { Map> children = new HashMap<>(); Map> parents = new HashMap<>(); Map> childrenSet = new HashMap<>(); Map> parentSet = new HashMap<>(); void addEdge(String parent, String child) { children.computeIfAbsent(parent, k -> new ArrayList<>()); parents.computeIfAbsent(child, k -> new ArrayList<>()); childrenSet.computeIfAbsent(parent, k -> new HashSet<>()); parentSet.computeIfAbsent(child, k -> new HashSet<>()); if (childrenSet.get(parent).add(child)) { children.get(parent).add(child); } if (parentSet.get(child).add(parent)) { parents.get(child).add(parent); } } } static void testLoki0001() { int E = 500; // edges from one parent to many children String parent = "root"; // Warm up for (int w = 0; w < 3; w++) { DagBefore db = new DagBefore(); DagAfter da = new DagAfter(); for (int i = 0; i < E; i++) { db.addEdge(parent, "child-" + i); da.addEdge(parent, "child-" + i); } } int ITER = 200; long t0 = System.nanoTime(); for (int it = 0; it < ITER; it++) { DagBefore db = new DagBefore(); for (int i = 0; i < E; i++) { db.addEdge(parent, "child-" + i); } // Also add duplicates to exercise the contains path for (int i = 0; i < E; i++) { db.addEdge(parent, "child-" + i); } } long befNs = System.nanoTime() - t0; t0 = System.nanoTime(); for (int it = 0; it < ITER; it++) { DagAfter da = new DagAfter(); for (int i = 0; i < E; i++) { da.addEdge(parent, "child-" + i); } for (int i = 0; i < E; i++) { da.addEdge(parent, "child-" + i); } } long aftNs = System.nanoTime() - t0; // Correctness check DagBefore db = new DagBefore(); DagAfter da = new DagAfter(); for (int i = 0; i < E; i++) { db.addEdge(parent, "child-" + i); da.addEdge(parent, "child-" + i); } assert db.children.get(parent).size() == da.children.get(parent).size() : "loki-0001 correctness: children sizes differ"; assert db.children.get(parent).equals(da.children.get(parent)) : "loki-0001 correctness: children order differs"; double ratio = (double) befNs / aftNs; System.out.printf("loki-0001 dag-edge-dedup BEFORE=%,dns AFTER=%,dns ratio=%.1fx %s%n", befNs, aftNs, ratio, ratio > 2.0 ? "PASS" : "FAIL"); assert ratio > 2.0 : "loki-0001: expected >2x speedup, got " + ratio; } // --------------------------------------------------------------- public static void main(String[] args) { testLoki0001(); System.out.println("\nAll 1 Loki CWE-407 test PASSED."); } }