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:
parent
dde5ec97fb
commit
e4ee168b1e
50 changed files with 4775 additions and 5 deletions
186
defects/nginx/unit/NginxVariablesInitAlgorithmTest.java
Normal file
186
defects/nginx/unit/NginxVariablesInitAlgorithmTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue