578/240 — rustc-0004/vertx-0001/asterisk-0003/bitcoin-0001/actix-web-0003/hazelcast-0001+0002/rabbitmq-0005/nginx-0003/haproxy-0003/envoy-0003/istio-0003

This commit is contained in:
russell@unturf.com 2026-03-27 21:25:37 -04:00
parent dde5ec97fb
commit e4ee168b1e
50 changed files with 4775 additions and 5 deletions

View file

@ -0,0 +1,260 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* haproxy-0003: flt_spoe.c spoe_check_config O(P×M), O(P×G), O(G×P×M) nested resolution.
*
* Models placeholder-to-message and group resolution using nested list walks (SLOW)
* vs ebtree/HashMap-based O(log N) or O(1) lookup (FAST).
*
* Run: javac HaproxySpoeCheckConfigAlgorithmTest.java && java unit.HaproxySpoeCheckConfigAlgorithmTest
*/
public class HaproxySpoeCheckConfigAlgorithmTest {
// --- Data structures mirroring SPOE config objects ---
static class SpoeMessage {
String id;
String group; // resolved group name (null initially)
SpoeMessage(String id) { this.id = id; }
}
static class SpoeGroup {
String id;
List<String> phIds; // placeholder message ids
List<SpoeMessage> messages = new ArrayList<>();
SpoeGroup(String id, List<String> phIds) {
this.id = id;
this.phIds = phIds;
}
}
// -------------------------------------------------------
static long slowOps = 0;
static long fastOps = 0;
/**
* SLOW Pattern 1: O(P×M) placeholder-to-message resolution.
* mirrors lines ~24072504 in spoe_check_config.
*/
static int[] resolvePlaceholdersSlow(List<String> placeholderIds, List<SpoeMessage> messages) {
int[] result = new int[placeholderIds.size()];
for (int p = 0; p < placeholderIds.size(); p++) { // outer: P
result[p] = -1;
for (int m = 0; m < messages.size(); m++) { // inner: M
slowOps++;
if (placeholderIds.get(p).equals(messages.get(m).id)) {
result[p] = m;
break;
}
}
}
return result;
}
/**
* FAST Pattern 1: O(P + M) build HashMap from messages, then O(1) per placeholder.
* mirrors the ebtst fix.
*/
static int[] resolvePlaceholdersFast(List<String> placeholderIds, List<SpoeMessage> messages) {
HashMap<String, Integer> msgMap = new HashMap<>(messages.size() * 2);
for (int m = 0; m < messages.size(); m++) {
fastOps++;
msgMap.put(messages.get(m).id, m);
}
int[] result = new int[placeholderIds.size()];
for (int p = 0; p < placeholderIds.size(); p++) {
fastOps++;
Integer idx = msgMap.get(placeholderIds.get(p));
result[p] = (idx != null) ? idx : -1;
}
return result;
}
/**
* SLOW Pattern 3: O(G×P×M) group message assignment.
* mirrors lines ~25262553 in spoe_check_config.
*/
static int slowTripleResolution(List<SpoeGroup> groups, List<SpoeMessage> messages) {
int assigned = 0;
for (SpoeGroup grp : groups) { // outer: G
for (String phId : grp.phIds) { // mid: P per group
for (SpoeMessage msg : messages) { // inner: M
slowOps++;
if (phId.equals(msg.id)) {
grp.messages.add(msg);
assigned++;
break;
}
}
}
}
return assigned;
}
/**
* FAST Pattern 3: O((G×P) + M) HashMap for messages.
*/
static int fastTripleResolution(List<SpoeGroup> groups, List<SpoeMessage> messages) {
// Build message map once: O(M)
HashMap<String, SpoeMessage> msgMap = new HashMap<>(messages.size() * 2);
for (SpoeMessage msg : messages) {
fastOps++;
msgMap.put(msg.id, msg);
}
int assigned = 0;
for (SpoeGroup grp : groups) { // outer: G
for (String phId : grp.phIds) { // inner: P per group
fastOps++;
SpoeMessage msg = msgMap.get(phId);
if (msg != null) {
grp.messages.add(msg);
assigned++;
}
}
}
return assigned;
}
// --- Test helpers ---
static List<SpoeMessage> makeMessages(int count) {
List<SpoeMessage> msgs = new ArrayList<>(count);
for (int i = 0; i < count; i++) msgs.add(new SpoeMessage("msg_" + i));
return msgs;
}
/**
* Build placeholders that reference messages near the END of the message list,
* forcing worst-case O(M) inner scan in the SLOW path.
*/
static List<String> makePlaceholders(int count) {
List<String> phs = new ArrayList<>(count);
for (int i = 0; i < count; i++) phs.add("msg_" + i);
return phs;
}
/**
* Build worst-case placeholders: each placeholder references the last message
* in the list, maximizing inner-loop iterations.
*/
static List<String> makeWorstCasePlaceholders(int count, int numMsg) {
List<String> phs = new ArrayList<>(count);
for (int i = 0; i < count; i++) phs.add("msg_" + (numMsg - 1 - (i % (numMsg / 2))));
return phs;
}
static List<SpoeGroup> makeGroups(int numGroups, int phsPerGroup, int msgCount) {
List<SpoeGroup> groups = new ArrayList<>(numGroups);
for (int g = 0; g < numGroups; g++) {
List<String> phs = new ArrayList<>(phsPerGroup);
for (int p = 0; p < phsPerGroup; p++) {
// Each group references messages round-robin
phs.add("msg_" + ((g * phsPerGroup + p) % msgCount));
}
groups.add(new SpoeGroup("grp_" + g, phs));
}
return groups;
}
// --- Tests ---
static boolean testPattern1(String name, int numPh, int numMsg) {
List<String> phs = makePlaceholders(numPh);
// Worst case: pad front with non-matching messages so matches are near end.
List<SpoeMessage> msgs = new ArrayList<>(numMsg);
int padding = numMsg - numPh;
for (int i = 0; i < padding; i++) msgs.add(new SpoeMessage("nomatch_" + i));
msgs.addAll(makeMessages(numPh)); // matching messages at the end
slowOps = 0;
int[] slowResult = resolvePlaceholdersSlow(phs, msgs);
long slowCount = slowOps;
slowOps = 0;
fastOps = 0;
int[] fastResult = resolvePlaceholdersFast(phs, msgs);
long fastCount = fastOps;
// Verify
for (int i = 0; i < numPh; i++) {
if (slowResult[i] != fastResult[i]) {
System.out.printf("FAIL [%s P1] P=%d M=%d mismatch at i=%d%n", name, numPh, numMsg, i);
return false;
}
}
double ratio = (double) slowCount / fastCount;
System.out.printf("PASS [%s P1] P=%d M=%d slow=%d fast=%d ratio=%.1fx%n",
name, numPh, numMsg, slowCount, fastCount, ratio);
if (numPh >= 20 && ratio < 5.0) {
System.out.printf("FAIL [%s P1] ratio %.1f < 5.0%n", name, ratio);
return false;
}
return true;
}
static boolean testPattern3(String name, int numGroups, int phsPerGroup, int numMsg) {
List<SpoeMessage> msgs = makeMessages(numMsg);
List<SpoeGroup> slowGroups = makeGroups(numGroups, phsPerGroup, numMsg);
List<SpoeGroup> fastGroups = makeGroups(numGroups, phsPerGroup, numMsg);
slowOps = 0;
int slowAssigned = slowTripleResolution(slowGroups, msgs);
long slowCount = slowOps;
slowOps = 0;
fastOps = 0;
int fastAssigned = fastTripleResolution(fastGroups, msgs);
long fastCount = fastOps;
if (slowAssigned != fastAssigned) {
System.out.printf("FAIL [%s P3] G=%d P=%d M=%d assigned mismatch slow=%d fast=%d%n",
name, numGroups, phsPerGroup, numMsg, slowAssigned, fastAssigned);
return false;
}
// Verify group messages match
for (int g = 0; g < numGroups; g++) {
List<SpoeMessage> sl = slowGroups.get(g).messages;
List<SpoeMessage> fl = fastGroups.get(g).messages;
if (sl.size() != fl.size()) {
System.out.printf("FAIL [%s P3] group %d size mismatch%n", name, g);
return false;
}
}
double ratio = (double) slowCount / fastCount;
System.out.printf("PASS [%s P3] G=%d P=%d M=%d slow=%d fast=%d ratio=%.1fx%n",
name, numGroups, phsPerGroup, numMsg, slowCount, fastCount, ratio);
if (numGroups >= 5 && ratio < 5.0) {
System.out.printf("FAIL [%s P3] ratio %.1f < 5.0%n", name, ratio);
return false;
}
return true;
}
public static void main(String[] args) {
int passed = 0, total = 0;
// Pattern 1: placeholder-to-message resolution (worst-case: match near end)
total++; if (testPattern1("tiny", 5, 10)) passed++;
total++; if (testPattern1("small", 20, 80)) passed++; // more messages worse ratio
total++; if (testPattern1("medium", 50, 200)) passed++;
total++; if (testPattern1("large", 100, 400)) passed++;
// Pattern 3: triple-nested groupplaceholdermessage
total++; if (testPattern3("tiny", 3, 3, 10)) passed++;
total++; if (testPattern3("small", 5, 5, 20)) passed++;
total++; if (testPattern3("medium", 10, 10, 50)) passed++;
total++; if (testPattern3("large", 20, 10, 100)) passed++;
total++; if (testPattern3("xlarge", 30, 15, 150)) passed++;
System.out.printf("%n%d/%d PASS%n", passed, total);
if (passed != total) System.exit(1);
}
}