wave7: 433/194 — kafka/flink/pulsar, spring/micronaut/quarkus, nginx/haproxy/traefik, linux/nomad/consul, numpy/pandas/sklearn, ES/OS/pg/sqlite/rustc/cargo
This commit is contained in:
parent
3735145aa5
commit
5fe6da7cc2
69 changed files with 6793 additions and 32 deletions
227
defects/cargo/unit/EdgesAddEdgeAlgorithm.java
Normal file
227
defects/cargo/unit/EdgesAddEdgeAlgorithm.java
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
package unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Models cargo's Edges::add_edge() in src/cargo/ops/tree/graph.rs —
|
||||
* deduplicates outgoing edges from a dependency graph node.
|
||||
*
|
||||
* SLOW: Vec<Edge>.contains() before each push — O(k) per insertion → O(E²) total.
|
||||
* FAST: LinkedHashSet<Edge> (insertion-ordered, O(1) contains) — O(E) total.
|
||||
*
|
||||
* CWE-407: src/cargo/ops/tree/graph.rs:122-126
|
||||
*/
|
||||
public class EdgesAddEdgeAlgorithm {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Edge model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
enum EdgeKind { DEP, FEATURE }
|
||||
|
||||
static final class Edge {
|
||||
final EdgeKind kind;
|
||||
final int node; // NodeId (simplified as int)
|
||||
final boolean pub;
|
||||
|
||||
Edge(EdgeKind kind, int node, boolean pub) {
|
||||
this.kind = kind;
|
||||
this.node = node;
|
||||
this.pub = pub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Edge)) return false;
|
||||
Edge e = (Edge) o;
|
||||
return kind == e.kind && node == e.node && pub == e.pub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(kind, node, pub);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Slow (defective) implementation — mirrors current cargo Vec<Edge>
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class SlowEdges {
|
||||
final Map<EdgeKind, List<Edge>> map = new HashMap<>();
|
||||
long containsChecks = 0;
|
||||
|
||||
/** O(k) membership test before push — quadratic when k grows. */
|
||||
void addEdge(Edge edge) {
|
||||
List<Edge> bucket = map.computeIfAbsent(edge.kind, k -> new ArrayList<>());
|
||||
containsChecks += bucket.size(); // count comparisons (worst case = full scan)
|
||||
if (!bucket.contains(edge)) {
|
||||
bucket.add(edge);
|
||||
}
|
||||
}
|
||||
|
||||
int edgeCount() {
|
||||
return map.values().stream().mapToInt(List::size).sum();
|
||||
}
|
||||
|
||||
List<Edge> ofKind(EdgeKind k) {
|
||||
return map.getOrDefault(k, List.of());
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Fast (fixed) implementation — LinkedHashSet preserves insertion order
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class FastEdges {
|
||||
final Map<EdgeKind, LinkedHashSet<Edge>> map = new HashMap<>();
|
||||
long insertCalls = 0;
|
||||
|
||||
/** O(1) amortized insert — LinkedHashSet ignores duplicates. */
|
||||
void addEdge(Edge edge) {
|
||||
LinkedHashSet<Edge> bucket = map.computeIfAbsent(edge.kind, k -> new LinkedHashSet<>());
|
||||
insertCalls++;
|
||||
bucket.add(edge);
|
||||
}
|
||||
|
||||
int edgeCount() {
|
||||
return map.values().stream().mapToInt(LinkedHashSet::size).sum();
|
||||
}
|
||||
|
||||
List<Edge> ofKind(EdgeKind k) {
|
||||
return new ArrayList<>(map.getOrDefault(k, new LinkedHashSet<>()));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Test helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static int passed = 0;
|
||||
static int total = 0;
|
||||
|
||||
static void check(String desc, boolean cond) {
|
||||
total++;
|
||||
if (cond) {
|
||||
passed++;
|
||||
System.out.printf(" PASS %s%n", desc);
|
||||
} else {
|
||||
System.out.printf(" FAIL %s%n", desc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("EdgesAddEdgeAlgorithm — CWE-407 unit test");
|
||||
System.out.println("cargo-0002: Edges::add_edge Vec<Edge>.contains() → LinkedHashSet");
|
||||
System.out.println();
|
||||
|
||||
// --- Correctness: no duplicate edges ---
|
||||
{
|
||||
SlowEdges slow = new SlowEdges();
|
||||
FastEdges fast = new FastEdges();
|
||||
|
||||
Edge e1 = new Edge(EdgeKind.DEP, 1, true);
|
||||
Edge e2 = new Edge(EdgeKind.DEP, 2, false);
|
||||
Edge e3 = new Edge(EdgeKind.FEATURE, 3, true);
|
||||
Edge e1dup = new Edge(EdgeKind.DEP, 1, true); // duplicate of e1
|
||||
|
||||
for (Edge e : List.of(e1, e2, e3, e1dup, e2, e3)) {
|
||||
slow.addEdge(e);
|
||||
fast.addEdge(e);
|
||||
}
|
||||
|
||||
check("no-dup: slow drops duplicates", slow.edgeCount() == 3);
|
||||
check("no-dup: fast drops duplicates", fast.edgeCount() == 3);
|
||||
check("no-dup: same DEP edges",
|
||||
slow.ofKind(EdgeKind.DEP).equals(fast.ofKind(EdgeKind.DEP)));
|
||||
check("no-dup: same FEATURE edges",
|
||||
slow.ofKind(EdgeKind.FEATURE).equals(fast.ofKind(EdgeKind.FEATURE)));
|
||||
}
|
||||
|
||||
// --- Correctness: insertion order preserved ---
|
||||
{
|
||||
SlowEdges slow = new SlowEdges();
|
||||
FastEdges fast = new FastEdges();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
slow.addEdge(new Edge(EdgeKind.FEATURE, i, true));
|
||||
fast.addEdge(new Edge(EdgeKind.FEATURE, i, true));
|
||||
}
|
||||
|
||||
check("order: slow preserves insertion order",
|
||||
slow.ofKind(EdgeKind.FEATURE).get(0).node == 0 &&
|
||||
slow.ofKind(EdgeKind.FEATURE).get(9).node == 9);
|
||||
check("order: fast preserves insertion order",
|
||||
fast.ofKind(EdgeKind.FEATURE).get(0).node == 0 &&
|
||||
fast.ofKind(EdgeKind.FEATURE).get(9).node == 9);
|
||||
}
|
||||
|
||||
// --- Performance: O(E²) vs O(E) ---
|
||||
{
|
||||
// Simulate adding E unique FEATURE edges (no duplicates) — worst case for slow
|
||||
// because each insertion must scan the entire existing bucket.
|
||||
// Model: a package node with F feature edges, e.g. tokio with 50+ features.
|
||||
int F = 200; // feature edge count per node (--graph-features mode, large workspace)
|
||||
|
||||
// Build edge list: F unique Feature edges
|
||||
List<Edge> edges = new ArrayList<>();
|
||||
for (int i = 0; i < F; i++) {
|
||||
edges.add(new Edge(EdgeKind.FEATURE, i, true));
|
||||
}
|
||||
|
||||
// Warm up JIT
|
||||
for (int w = 0; w < 50; w++) {
|
||||
SlowEdges s = new SlowEdges();
|
||||
FastEdges f = new FastEdges();
|
||||
for (Edge e : edges) { s.addEdge(e); f.addEdge(e); }
|
||||
}
|
||||
|
||||
int RUNS = 2_000;
|
||||
long slowContains = 0;
|
||||
long fastInserts = 0;
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
for (int r = 0; r < RUNS; r++) {
|
||||
SlowEdges s = new SlowEdges();
|
||||
for (Edge e : edges) s.addEdge(e);
|
||||
slowContains += s.containsChecks;
|
||||
}
|
||||
long slowNs = System.nanoTime() - t0;
|
||||
|
||||
long t1 = System.nanoTime();
|
||||
for (int r = 0; r < RUNS; r++) {
|
||||
FastEdges f = new FastEdges();
|
||||
for (Edge e : edges) f.addEdge(e);
|
||||
fastInserts += f.insertCalls;
|
||||
}
|
||||
long fastNs = System.nanoTime() - t1;
|
||||
|
||||
double ratio = (double) slowNs / fastNs;
|
||||
long slowOpsPerRun = slowContains / RUNS;
|
||||
long fastOpsPerRun = fastInserts / RUNS;
|
||||
|
||||
System.out.printf(" INFO F=%d slow_contains_checks=%d fast_inserts=%d ratio=%.1fx%n",
|
||||
F, slowOpsPerRun, fastOpsPerRun, ratio);
|
||||
|
||||
// Slow: F unique edges → 0+1+2+...+(F-1) = F*(F-1)/2 contains checks total
|
||||
long expectedSlowTotal = (long) F * (F - 1) / 2;
|
||||
check("slow: contains checks = F*(F-1)/2 per run (triangular O(F²))",
|
||||
slowOpsPerRun >= expectedSlowTotal);
|
||||
// Fast: exactly F insert calls per run
|
||||
check("fast: insert calls = F per run (O(F))",
|
||||
fastOpsPerRun == F);
|
||||
// Op ratio matches O(F²)/O(F) = O(F) = 200/2 = 100x difference in ops
|
||||
check("slow op count >> fast op count (>= 50x)",
|
||||
slowOpsPerRun >= fastOpsPerRun * 50);
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.printf("%d/%d PASS%n", passed, total);
|
||||
if (passed != total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue