java-topology/defects/kubernetes/unit/Kubernetes0007Algorithm.java

299 lines
12 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.*;
/**
* Kubernetes0007Algorithm — CWE-407 unit test for kubernetes-0007
*
* kubernetes-0007: pod_failure_policy.go:126,128
* for _, containerStatus := range containerStatuses { // O(C) containers
* isOnExitCodesOperatorMatching(exitCode, requirement) →
* slices.Contains(requirement.Values, exitCode) // O(V) scan
* }
*
* Called from matchPodFailurePolicy() for every failed pod:
* for _, p := range failedPods { matchPodFailurePolicy(policy, p) }
*
* Total complexity: O(P × R × C × V) — pods × rules × containers × values
*
* SLOW: slices.Contains([]int32, exitCode) — O(V) linear scan per container
* FAST: map[int32]struct{} pre-built once per rule — O(1) per container
*
* No JUnit. Run: javac -d . Kubernetes0007Algorithm.java && java -ea unit.Kubernetes0007Algorithm
*/
public class Kubernetes0007Algorithm {
// -------------------------------------------------------------------------
// Data model — mirrors PodFailurePolicyOnExitCodesRequirement
// -------------------------------------------------------------------------
static class ExitCodeRequirement {
final boolean opIn; // true=In, false=NotIn
final int[] values; // requirement.Values []int32
ExitCodeRequirement(boolean opIn, int[] values) {
this.opIn = opIn;
this.values = values;
}
}
static class PolicyRule {
final ExitCodeRequirement requirement;
PolicyRule(ExitCodeRequirement r) { this.requirement = r; }
}
// -------------------------------------------------------------------------
// Op counters for measuring linear vs map scans
// -------------------------------------------------------------------------
static long slowOps = 0;
static long fastOps = 0;
// -------------------------------------------------------------------------
// SLOW: O(V) linear scan — models slices.Contains(requirement.Values, exitCode)
// -------------------------------------------------------------------------
static boolean isMatchingSlow(int exitCode, ExitCodeRequirement req) {
for (int v : req.values) { // O(V) linear scan
slowOps++;
if (v == exitCode) {
return req.opIn; // In: found → match
}
}
return !req.opIn; // In: not found → no match; NotIn: not found → match
}
/**
* Match one pod's containers against all policy rules.
* Models matchPodFailurePolicy() + getMatchingContainerFromList().
* Returns true if any rule matches any container exit code.
*/
static boolean matchPodSlow(int[] containerExitCodes, List<PolicyRule> rules) {
for (PolicyRule rule : rules) { // O(R) rules
for (int exitCode : containerExitCodes) { // O(C) containers
if (exitCode != 0 && isMatchingSlow(exitCode, rule.requirement)) {
return true;
}
}
}
return false;
}
/**
* Run all failed pods through policy matching.
* Models nonIgnoredFailedPodsCount() hot path.
*/
static int countIgnoredPodsSlow(int[][] failedPods, List<PolicyRule> rules) {
int ignored = 0;
for (int[] podExitCodes : failedPods) { // O(P) pods
if (matchPodSlow(podExitCodes, rules)) {
ignored++;
}
}
return ignored;
}
// -------------------------------------------------------------------------
// FAST: pre-build map[int32]struct{} once per rule — O(1) per container
// -------------------------------------------------------------------------
static boolean isMatchingFast(int exitCode, boolean opIn, Set<Integer> valueSet) {
fastOps++;
boolean found = valueSet.contains(exitCode); // O(1) hash lookup
return opIn ? found : !found;
}
static boolean matchPodFast(int[] containerExitCodes, List<PolicyRule> rules,
List<Set<Integer>> ruleSets) {
for (int i = 0; i < rules.size(); i++) { // O(R)
PolicyRule rule = rules.get(i);
Set<Integer> valueSet = ruleSets.get(i);
for (int exitCode : containerExitCodes) { // O(C)
if (exitCode != 0 && isMatchingFast(exitCode, rule.requirement.opIn, valueSet)) {
return true;
}
}
}
return false;
}
static int countIgnoredPodsFast(int[][] failedPods, List<PolicyRule> rules) {
// Pre-build one set per rule — O(R × V) one-time cost
List<Set<Integer>> ruleSets = new ArrayList<>(rules.size());
for (PolicyRule rule : rules) {
Set<Integer> set = new HashSet<>(rule.requirement.values.length * 2);
for (int v : rule.requirement.values) { set.add(v); }
ruleSets.add(set);
}
// Now match all pods — O(P × R × C × 1)
int ignored = 0;
for (int[] podExitCodes : failedPods) {
if (matchPodFast(podExitCodes, rules, ruleSets)) {
ignored++;
}
}
return ignored;
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
/** Build R rules each with V exit code values (some matching exitSeed) */
static List<PolicyRule> buildRules(int R, int V, int exitSeed) {
List<PolicyRule> rules = new ArrayList<>(R);
for (int i = 0; i < R; i++) {
int[] values = new int[V];
for (int j = 0; j < V; j++) {
values[j] = (exitSeed + i * V + j) % 256 + 1;
}
rules.add(new PolicyRule(new ExitCodeRequirement(true, values)));
}
return rules;
}
/** Build P pods each with C containers, exit codes spread to hit last rule */
static int[][] buildPods(int P, int C) {
int[][] pods = new int[P][C];
for (int i = 0; i < P; i++) {
for (int j = 0; j < C; j++) {
// Use exit code that is unlikely to match early rules → worst case scan
pods[i][j] = (i * C + j) % 200 + 50;
}
}
return pods;
}
// -------------------------------------------------------------------------
// Tests
// -------------------------------------------------------------------------
static void testCorrectness() {
// Single rule: In [1, 2, 3]
List<PolicyRule> rules = new ArrayList<>();
rules.add(new PolicyRule(new ExitCodeRequirement(true, new int[]{1, 2, 3})));
int[][] matchingPod = {{1, 0}}; // exit code 1 → should match
int[][] noMatchPod = {{5, 0}}; // exit code 5 → no match
List<Set<Integer>> sets = new ArrayList<>();
sets.add(new HashSet<>(Arrays.asList(1, 2, 3)));
assert countIgnoredPodsSlow(matchingPod, rules) == 1
: "slow: expected match";
assert countIgnoredPodsFast(matchingPod, rules) == 1
: "fast: expected match";
assert countIgnoredPodsSlow(noMatchPod, rules) == 0
: "slow: expected no match";
assert countIgnoredPodsFast(noMatchPod, rules) == 0
: "fast: expected no match";
// NotIn rule: NotIn [1,2,3] — exit code 5 should match (5 not in set)
List<PolicyRule> notInRules = new ArrayList<>();
notInRules.add(new PolicyRule(new ExitCodeRequirement(false, new int[]{1, 2, 3})));
assert countIgnoredPodsSlow(noMatchPod, notInRules) == 1
: "slow NotIn: expected match for code 5";
assert countIgnoredPodsFast(noMatchPod, notInRules) == 1
: "fast NotIn: expected match for code 5";
System.out.println("PASS correctness: In/NotIn matching verified");
}
static void testOpsCount() {
int P = 100, R = 10, C = 3, V = 20;
List<PolicyRule> rules = buildRules(R, V, 200); // high exit codes → no early match
int[][] pods = buildPods(P, C);
slowOps = 0;
fastOps = 0;
countIgnoredPodsSlow(pods, rules);
countIgnoredPodsFast(pods, rules);
long expectedSlowBound = (long) P * R * C * V;
long expectedFastBound = (long) P * R * C;
System.out.printf("PASS ops_count P=%d R=%d C=%d V=%d: slowOps=%d fastOps=%d ratio=%.0fx%n",
P, R, C, V, slowOps, fastOps, (double) slowOps / Math.max(fastOps, 1));
assert slowOps >= fastOps * 5 :
"expected slowOps >> fastOps, got slowOps=" + slowOps + " fastOps=" + fastOps;
}
static void testPerf_P500_R15_C3_V30() {
int P = 500, R = 15, C = 3, V = 30;
List<PolicyRule> rules = buildRules(R, V, 210);
int[][] pods = buildPods(P, C);
// Warm up JVM
for (int i = 0; i < 20; i++) {
countIgnoredPodsSlow(pods, rules);
countIgnoredPodsFast(pods, rules);
}
long t0 = System.nanoTime();
int slowResult = 0;
for (int i = 0; i < 500; i++) {
slowResult += countIgnoredPodsSlow(pods, rules);
}
long slowNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
int fastResult = 0;
for (int i = 0; i < 500; i++) {
fastResult += countIgnoredPodsFast(pods, rules);
}
long fastNs = System.nanoTime() - t1;
assert slowResult == fastResult : "results differ: " + slowResult + " vs " + fastResult;
double ratio = (double) slowNs / Math.max(fastNs, 1);
System.out.printf("PASS perf P=%d R=%d C=%d V=%d 500x: slow=%dms fast=%dms ratio=%.1fx%n",
P, R, C, V, slowNs / 1_000_000, fastNs / 1_000_000, ratio);
assert ratio >= 0.5 :
"ratio too low: " + ratio + " (slow=" + slowNs + "ns fast=" + fastNs + "ns)";
}
static void testPerf_P2000_R20_C5_V10_stress() {
int P = 2000, R = 20, C = 5, V = 10;
List<PolicyRule> rules = buildRules(R, V, 220);
int[][] pods = buildPods(P, C);
// Warm up
for (int i = 0; i < 10; i++) {
countIgnoredPodsSlow(pods, rules);
countIgnoredPodsFast(pods, rules);
}
long t0 = System.nanoTime();
int slowResult = 0;
for (int i = 0; i < 100; i++) {
slowResult += countIgnoredPodsSlow(pods, rules);
}
long slowNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
int fastResult = 0;
for (int i = 0; i < 100; i++) {
fastResult += countIgnoredPodsFast(pods, rules);
}
long fastNs = System.nanoTime() - t1;
assert slowResult == fastResult : "results differ: " + slowResult + " vs " + fastResult;
double ratio = (double) slowNs / Math.max(fastNs, 1);
System.out.printf("PASS stress P=%d R=%d C=%d V=%d 100x: slow=%dms fast=%dms ratio=%.1fx%n",
P, R, C, V, slowNs / 1_000_000, fastNs / 1_000_000, ratio);
// ops count test already proves O(V) vs O(1) — just verify correctness here
assert slowResult > 0 || fastResult == 0 : "unexpected mismatch";
}
// -------------------------------------------------------------------------
// Main
// -------------------------------------------------------------------------
public static void main(String[] args) {
System.out.println("=== Kubernetes0007Algorithm: pod failure policy exit-code scan (kubernetes-0007) ===");
testCorrectness();
testOpsCount();
testPerf_P500_R15_C3_V30();
testPerf_P2000_R20_C5_V10_stress();
System.out.println("4/4 PASS");
}
}