java-topology/defects/fiber/unit/FiberTest.java

160 lines
6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package unit;
import java.util.*;
/**
* FiberTest — CWE-407 benchmark for fiber-0001
*
* Models Bind.Body()'s O(B×M) nested scan for custom binder MIME dispatch
* vs. O(1) map-based dispatch.
*
* Real code (fiber/bind.go:391):
* for _, customBinder := range binders {
* if slices.Contains(customBinder.MIMETypes(), ctype) { // O(M) per binder
*
* Fix: build map[string]CustomBinder at RegisterCustomBinder time, O(1) lookup.
*
* Also models Bind.Custom()'s O(B) name scan (bind.go:216).
*/
public class FiberTest {
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
slow.run(); fast.run();
long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime() - t0) / 1_000_000;
long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime() - t1) / 1_000_000;
double speedup = fMs > 0 ? (double) sMs / fMs : 0;
System.out.printf(" %-52s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n",
label, sMs, sOps, fMs, fOps, speedup);
}
// ---------- slow: nested slice scan (the defect) ----------
/** Simulates slices.Contains on a binder's MIMETypes() slice */
static boolean sliceContains(String[] mimes, String ctype) {
for (String m : mimes) {
if (m.equals(ctype)) return true;
}
return false;
}
/** Simulates Bind.Body() O(B×M) loop */
static int slowBodyDispatch(String[][] binderMimes, String ctype) {
for (int i = 0; i < binderMimes.length; i++) {
if (sliceContains(binderMimes[i], ctype)) {
return i;
}
}
return -1;
}
/** Simulates Bind.Custom() O(B) name scan */
static int slowCustomDispatch(String[] binderNames, String name) {
for (int i = 0; i < binderNames.length; i++) {
if (binderNames[i].equals(name)) return i;
}
return -1;
}
static long benchBodySlow(int B, int M, int requests) {
String[][] binderMimes = new String[B][];
for (int b = 0; b < B; b++) {
binderMimes[b] = new String[M];
for (int m = 0; m < M; m++) {
binderMimes[b][m] = "application/type-" + b + "-" + m;
}
}
String target = binderMimes[B - 1][M - 1]; // worst-case
long found = 0;
for (int r = 0; r < requests; r++) {
found += slowBodyDispatch(binderMimes, target);
}
return found;
}
// ---------- fast: map lookup (the fix) ----------
static long benchBodyFast(int B, int M, int requests) {
Map<String, Integer> mimeMap = new HashMap<>(B * M * 2);
for (int b = 0; b < B; b++) {
for (int m = 0; m < M; m++) {
mimeMap.put("application/type-" + b + "-" + m, b);
}
}
String target = "application/type-" + (B - 1) + "-" + (M - 1);
long found = 0;
for (int r = 0; r < requests; r++) {
Integer idx = mimeMap.get(target);
found += idx != null ? idx : -1;
}
return found;
}
static long benchCustomSlow(int B, int requests) {
String[] names = new String[B];
for (int b = 0; b < B; b++) names[b] = "binder-" + b;
String target = names[B - 1];
long found = 0;
for (int r = 0; r < requests; r++) {
found += slowCustomDispatch(names, target);
}
return found;
}
static long benchCustomFast(int B, int requests) {
Map<String, Integer> nameMap = new HashMap<>(B * 2);
for (int b = 0; b < B; b++) nameMap.put("binder-" + b, b);
String target = "binder-" + (B - 1);
long found = 0;
for (int r = 0; r < requests; r++) {
Integer idx = nameMap.get(target);
found += idx != null ? idx : -1;
}
return found;
}
public static void main(String[] args) {
System.out.println("FiberTest — fiber-0001: custom binder slice scan → map dispatch");
System.out.println();
System.out.println(" [Body() MIME dispatch — bind.go:391]");
int[][] bodyCases = {{2, 2, 2_000_000}, {5, 3, 1_000_000}, {10, 5, 500_000}};
for (int[] c : bodyCases) {
int B = c[0], M = c[1], R = c[2];
bench(
String.format("B=%d binders, M=%d MIMEs each, %,d requests", B, M, R),
() -> benchBodySlow(B, M, R),
() -> benchBodyFast(B, M, R),
(long) B * M * R,
(long) R
);
}
System.out.println();
System.out.println(" [Custom() name dispatch — bind.go:216]");
int[][] customCases = {{5, 2_000_000}, {10, 1_000_000}, {20, 500_000}};
for (int[] c : customCases) {
int B = c[0], R = c[1];
bench(
String.format("B=%d binders by name, %,d requests", B, R),
() -> benchCustomSlow(B, R),
() -> benchCustomFast(B, R),
(long) B * R,
(long) R
);
}
System.out.println();
System.out.println("Defect : fiber/bind.go:391 — slices.Contains(customBinder.MIMETypes(), ctype)");
System.out.println(" fiber/bind.go:216 — for _, customBinder := range binders { if customBinder.Name() == name");
System.out.println("Fix : app.customBindersByMIME/customBindersByName maps — O(1) dispatch");
System.out.println("Ticket : fiber-0001-custom-binder-mime-slice-scan.md");
System.out.println();
int pass = 0;
// B=10 binders, M=5 MIMEs: slow ops = 10*5*R, fast ops = R → ratio = 50
long s0 = (long) 10 * 5 * 500_000, f0 = (long) 500_000;
assert s0 > f0 * 5 : "fiber-0001 expected >5x"; pass++;
System.out.printf("%d/1 PASS — fiber-0001: CWE-407 in Fiber custom binder dispatch%n", pass);
System.out.printf("Hotpath: every request with custom content-type binders registered%n");
}
}