wave13: 514/239 — flink/nifi/artemis + K8s/cilium/linkerd2 + ES/OpenSearch/Solr + hadoop/hbase/spark

This commit is contained in:
russell@unturf.com 2026-03-27 17:50:40 -04:00
parent 424a2a7787
commit 8f0bc73afa
32 changed files with 3977 additions and 5 deletions

View file

@ -0,0 +1,163 @@
package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* CWE-407 unit test: solr-003
* SplitShardCmd.cleanupAfterFailedSplit subSlices.contains(s.getName()) (List)
* inside a loop over all collection slices O(S × n).
*
* Slow path: List<String>.contains() O(n) per slice.
* Fast path: HashSet<String>.contains() O(1) per slice.
*
* Compile: javac -d . SplitShardSubSlicesContains.java
* Run: java -ea unit.SplitShardSubSlicesContains
*/
public class SplitShardSubSlicesContains {
static final class Slice {
final String name;
final String state;
Slice(String name, String state) {
this.name = name;
this.state = state;
}
String getName() { return name; }
}
// ---- Slow: List.contains O(n) per slice ----
static Map<String, String> slowCleanupStateUpdate(List<Slice> allSlices, List<String> subSlices) {
Map<String, String> propMap = new HashMap<>();
for (Slice s : allSlices) {
if (!subSlices.contains(s.getName())) { // O(n) per iteration
continue;
}
propMap.put(s.getName(), "CONSTRUCTION");
}
return propMap;
}
static long countSlowOps(List<Slice> allSlices, List<String> subSlices) {
long ops = 0;
for (Slice s : allSlices) {
// each contains() scan is O(n) count all comparisons
for (String sub : subSlices) {
ops++;
if (sub.equals(s.getName())) break;
}
}
return ops;
}
// ---- Fast: HashSet.contains O(1) per slice ----
static Map<String, String> fastCleanupStateUpdate(List<Slice> allSlices, List<String> subSlices) {
Set<String> subSliceSet = new HashSet<>(subSlices);
Map<String, String> propMap = new HashMap<>();
for (Slice s : allSlices) {
if (!subSliceSet.contains(s.getName())) { // O(1)
continue;
}
propMap.put(s.getName(), "CONSTRUCTION");
}
return propMap;
}
static long countFastOps(List<Slice> allSlices, List<String> subSlices) {
long ops = subSlices.size(); // build set: O(n)
ops += allSlices.size(); // O(1) per lookup
return ops;
}
public static void main(String[] args) {
int passed = 0;
// ---- Test 1: correctness at small scale ----
{
List<Slice> allSlices = new ArrayList<>();
List<String> subSlices = new ArrayList<>();
// 20 total slices, 3 sub-shards from split
for (int i = 0; i < 20; i++) allSlices.add(new Slice("shard" + i, "ACTIVE"));
subSlices.add("shard5_0");
subSlices.add("shard5_1");
subSlices.add("shard5_2");
// Add the sub-slices to allSlices too
for (String s : subSlices) allSlices.add(new Slice(s, "INACTIVE"));
Map<String, String> slow = slowCleanupStateUpdate(allSlices, subSlices);
Map<String, String> fast = fastCleanupStateUpdate(allSlices, subSlices);
assert slow.equals(fast) : "FAIL: slow=" + slow + " fast=" + fast;
assert slow.size() == 3 : "FAIL: expected 3 in propMap, got " + slow.size();
System.out.println("PASS test1: correctness — propMap size=" + fast.size());
passed++;
}
// ---- Test 2: no subslices found ----
{
List<Slice> allSlices = new ArrayList<>();
List<String> subSlices = new ArrayList<>();
for (int i = 0; i < 50; i++) allSlices.add(new Slice("shard" + i, "ACTIVE"));
subSlices.add("nonexistent_0");
subSlices.add("nonexistent_1");
Map<String, String> slow = slowCleanupStateUpdate(allSlices, subSlices);
Map<String, String> fast = fastCleanupStateUpdate(allSlices, subSlices);
assert slow.isEmpty() && fast.isEmpty() : "FAIL: expected empty maps";
System.out.println("PASS test2: no subslices found");
passed++;
}
// ---- Test 3: operation count ratio >= 5x (theoretical max ~n for n subslices) ----
{
int S = 5000; // large collection with many shards
int n = 8; // MAX_NUM_SUB_SHARDS
List<Slice> allSlices = new ArrayList<>();
List<String> subSlices = new ArrayList<>();
for (int i = 0; i < S; i++) allSlices.add(new Slice("shard" + i, "ACTIVE"));
for (int i = 0; i < n; i++) subSlices.add("newshard" + i);
// none overlap worst case for slow: each contains() exhausts all n items
long slowOps = countSlowOps(allSlices, subSlices);
long fastOps = countFastOps(allSlices, subSlices);
double ratio = (double) slowOps / fastOps;
System.out.printf("PASS test3: S=%d n=%d slow=%d fast=%d ratio=%.1fx%n",
S, n, slowOps, fastOps, ratio);
assert ratio >= 5.0 : "FAIL: ratio " + ratio + " < 5x";
passed++;
}
// ---- Test 4: timing benchmark (larger subSlices list to amplify O(n) factor) ----
{
// Use a larger synthetic n (100 sub-shards) to show timing ratio clearly.
// The real cap is MAX_NUM_SUB_SHARDS=8 but the algorithmic structure is identical.
int S = 5000;
int n = 100;
List<Slice> allSlices = new ArrayList<>();
List<String> subSlices = new ArrayList<>();
for (int i = 0; i < S; i++) allSlices.add(new Slice("shard" + i, "ACTIVE"));
for (int i = 0; i < n; i++) subSlices.add("newshard" + i);
int reps = 500;
long t0 = System.nanoTime();
for (int r = 0; r < reps; r++) slowCleanupStateUpdate(allSlices, subSlices);
long slowNs = System.nanoTime() - t0;
long t1 = System.nanoTime();
for (int r = 0; r < reps; r++) fastCleanupStateUpdate(allSlices, subSlices);
long fastNs = System.nanoTime() - t1;
double ratio = (double) slowNs / fastNs;
System.out.printf("PASS test4: timing S=%d n=%d slow=%.2fms fast=%.2fms ratio=%.1fx%n",
S, n, slowNs / 1e6 / reps, fastNs / 1e6 / reps, ratio);
assert ratio >= 10.0 : "FAIL: timing ratio " + ratio + " < 10x";
passed++;
}
System.out.println(passed + "/" + passed + " PASS");
}
}