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,186 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* nginx-0003: ngx_http_variables_init_vars O(V×K) nested scan at startup.
*
* Models the resolution of V indexed variables against K registered variable
* keys using ngx_strncmp (SLOW: nested loop) vs a HashMap (FAST: O(1) lookup).
*
* Run: javac NginxVariablesInitAlgorithmTest.java && java unit.NginxVariablesInitAlgorithmTest
*/
public class NginxVariablesInitAlgorithmTest {
static long slowOps = 0;
static long fastOps = 0;
/**
* SLOW: O(V×K) nested loop mirrors ngx_http_variables_init_vars.
* For each indexed variable, scan all variable_keys entries with strcmp.
*
* @param indexedVars list of indexed variable names (V)
* @param keyNames list of registered key names (K)
* @param handlers map from key name to handler index (simulated)
* @return resolved handler array (one per indexed var, -1 if not found)
*/
static int[] resolveVarsSlow(List<String> indexedVars, List<String> keyNames) {
int[] handlers = new int[indexedVars.size()];
for (int i = 0; i < indexedVars.size(); i++) { // outer: V
handlers[i] = -1;
for (int n = 0; n < keyNames.size(); n++) { // inner: K
slowOps++;
if (indexedVars.get(i).equals(keyNames.get(n))) {
handlers[i] = n; // "set handler"
break;
}
}
}
return handlers;
}
/**
* FAST: O(V + K) build a HashMap from keyNames first, then O(1) per var.
* Models the fix: build a temporary hash of variables_keys, then resolve.
*/
static int[] resolveVarsFast(List<String> indexedVars, List<String> keyNames) {
// Build map: O(K)
HashMap<String, Integer> keyMap = new HashMap<>(keyNames.size() * 2);
for (int n = 0; n < keyNames.size(); n++) {
fastOps++;
keyMap.put(keyNames.get(n), n);
}
// Resolve: O(V)
int[] handlers = new int[indexedVars.size()];
for (int i = 0; i < indexedVars.size(); i++) {
fastOps++;
Integer h = keyMap.get(indexedVars.get(i));
handlers[i] = (h != null) ? h : -1;
}
return handlers;
}
static boolean runTest(String name, int numVars, int numKeys, int expectedResolved) {
// Build keyNames: all registered variable names (built-ins + module vars)
List<String> keyNames = new ArrayList<>(numKeys);
for (int n = 0; n < numKeys; n++) {
keyNames.add("var_key_" + n);
}
// Build indexedVars: a subset of keyNames (vars referenced in config)
// First numVars entries from keyNames are referenced
List<String> indexedVars = new ArrayList<>(numVars);
for (int i = 0; i < numVars; i++) {
indexedVars.add("var_key_" + i); // all should resolve
}
slowOps = 0;
fastOps = 0;
int[] slowResult = resolveVarsSlow(indexedVars, keyNames);
long slowCount = slowOps;
slowOps = 0;
fastOps = 0;
int[] fastResult = resolveVarsFast(indexedVars, keyNames);
long fastCount = fastOps;
// Verify correctness
int resolvedSlow = 0, resolvedFast = 0;
for (int i = 0; i < numVars; i++) {
if (slowResult[i] != -1) resolvedSlow++;
if (fastResult[i] != -1) resolvedFast++;
if (slowResult[i] != fastResult[i]) {
System.out.printf("FAIL [%s] N=%d,K=%d: result mismatch at i=%d slow=%d fast=%d%n",
name, numVars, numKeys, i, slowResult[i], fastResult[i]);
return false;
}
}
if (resolvedSlow != expectedResolved) {
System.out.printf("FAIL [%s] N=%d,K=%d: expected %d resolved, got %d%n",
name, numVars, numKeys, expectedResolved, resolvedSlow);
return false;
}
double ratio = (double) slowCount / fastCount;
System.out.printf("PASS [%s] N=%d K=%d resolved=%d slow=%d fast=%d ratio=%.1fx%n",
name, numVars, numKeys, resolvedSlow, slowCount, fastCount, ratio);
if (numVars >= 50 && ratio < 5.0) {
System.out.printf("FAIL [%s] ratio %.1f < 5.0 minimum%n", name, ratio);
return false;
}
return true;
}
public static void main(String[] args) {
int passed = 0, total = 0;
// Test 1: small config V=10, K=60 (built-ins only)
total++;
if (runTest("small-config", 10, 60, 10)) passed++;
// Test 2: medium config V=50, K=150 (built-ins + module vars)
total++;
if (runTest("medium-config", 50, 150, 50)) passed++;
// Test 3: large config V=150, K=300 (heavy module load)
total++;
if (runTest("large-config", 150, 300, 150)) passed++;
// Test 4: extra-large V=300, K=500
total++;
if (runTest("xlarge-config", 300, 500, 300)) passed++;
// Test 5: partial resolution (some vars are prefix-matched, not in key list)
// Only first half of indexed vars are in keyNames
{
total++;
int numVars = 100;
int numKeys = 200;
List<String> keyNames = new ArrayList<>(numKeys);
for (int n = 0; n < numKeys; n++) {
keyNames.add("key_" + n);
}
List<String> indexedVars = new ArrayList<>(numVars);
for (int i = 0; i < numVars; i++) {
if (i < numVars / 2) {
indexedVars.add("key_" + i); // will resolve
} else {
indexedVars.add("prefix_var_" + i); // will NOT resolve via keys (prefix path)
}
}
slowOps = 0;
int[] slowResult = resolveVarsSlow(indexedVars, keyNames);
long slowCount = slowOps;
slowOps = 0;
int[] fastResult = resolveVarsFast(indexedVars, keyNames);
long fastCount = fastOps;
boolean ok = true;
for (int i = 0; i < numVars; i++) {
if (slowResult[i] != fastResult[i]) {
ok = false;
break;
}
}
double ratio = (double) slowCount / fastCount;
if (ok) {
System.out.printf("PASS [partial-resolution] N=%d K=%d slow=%d fast=%d ratio=%.1fx%n",
numVars, numKeys, slowCount, fastCount, ratio);
passed++;
} else {
System.out.printf("FAIL [partial-resolution] result mismatch%n");
}
}
System.out.printf("%n%d/%d PASS%n", passed, total);
if (passed != total) System.exit(1);
}
}