wave10b/c: 465/212 hudi/iceberg/scylladb/yugabyte/foundationdb
This commit is contained in:
parent
f7fa333977
commit
70702dff5c
38 changed files with 2073 additions and 5 deletions
148
defects/kylin/unit/JobSchedulerAlgorithm.java
Normal file
148
defects/kylin/unit/JobSchedulerAlgorithm.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
/**
|
||||
* Standalone unit test for kylin-0001:
|
||||
* JdbcJobScheduler — List<String>.contains() in stream filter → O(J²).
|
||||
*
|
||||
* Simulates the releaseJobLock() pattern:
|
||||
* jobInfoIds collected as List<String>, then used in stream filter with .contains().
|
||||
*
|
||||
* Compile: javac -d . JobSchedulerAlgorithm.java
|
||||
* Run: java unit.JobSchedulerAlgorithm
|
||||
*/
|
||||
public class JobSchedulerAlgorithm {
|
||||
|
||||
// ── Result ───────────────────────────────────────────────────────────────
|
||||
|
||||
static class Result {
|
||||
final List<String> toRemoveLocks;
|
||||
final long ns;
|
||||
Result(List<String> locks, long ns) { this.toRemoveLocks = locks; this.ns = ns; }
|
||||
}
|
||||
|
||||
// ── Defective: collects jobInfoIds into List → O(J) .contains per jobId ─
|
||||
|
||||
static class DefectiveAlgorithm {
|
||||
/**
|
||||
* @param jobIds all job IDs found in the lock table
|
||||
* @param jobInfoIds job IDs that have corresponding JobInfo records (as List)
|
||||
*/
|
||||
Result releaseJobLock(List<String> jobIds, List<String> jobInfoIds) {
|
||||
long t0 = System.nanoTime();
|
||||
// Mirrors the defective code:
|
||||
// List<String> jobInfoIds = jobs.stream().map(JobInfo::getJobId).collect(Collectors.toList());
|
||||
// ... filter(jobId -> !jobInfoIds.contains(jobId)) ...
|
||||
List<String> toRemoveLocks = jobIds.stream()
|
||||
.filter(jobId -> !jobInfoIds.contains(jobId)) // CWE-407 site: O(J) per call
|
||||
.collect(Collectors.toList());
|
||||
return new Result(toRemoveLocks, System.nanoTime() - t0);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Fixed: uses Set<String> → O(1) .contains ────────────────────────────
|
||||
|
||||
static class FixedAlgorithm {
|
||||
Result releaseJobLock(List<String> jobIds, List<String> jobInfoIdsList) {
|
||||
long t0 = System.nanoTime();
|
||||
// Fix: collect into HashSet for O(1) membership
|
||||
Set<String> jobInfoIds = new HashSet<>(jobInfoIdsList);
|
||||
List<String> toRemoveLocks = jobIds.stream()
|
||||
.filter(jobId -> !jobInfoIds.contains(jobId)) // O(1)
|
||||
.collect(Collectors.toList());
|
||||
return new Result(toRemoveLocks, System.nanoTime() - t0);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
static List<String> makeJobIds(int N) {
|
||||
List<String> ids = new ArrayList<>(N);
|
||||
for (int i = 0; i < N; i++) ids.add("job-" + i);
|
||||
return ids;
|
||||
}
|
||||
|
||||
// ── Assertions ───────────────────────────────────────────────────────────
|
||||
|
||||
static void assertEquals(Object expected, Object actual, String msg) {
|
||||
if (!expected.equals(actual))
|
||||
throw new AssertionError(msg + ": expected=" + expected + " actual=" + actual);
|
||||
}
|
||||
|
||||
static void assertTrue(boolean cond, String msg) {
|
||||
if (!cond) throw new AssertionError(msg);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== kylin-0001: JobSchedulerAlgorithm ===");
|
||||
|
||||
DefectiveAlgorithm defAlg = new DefectiveAlgorithm();
|
||||
FixedAlgorithm fixAlg = new FixedAlgorithm();
|
||||
|
||||
// Correctness test 1: some jobs have info, some don't
|
||||
{
|
||||
List<String> jobIds = makeJobIds(20);
|
||||
// Only even-numbered jobs have a JobInfo record
|
||||
List<String> jobInfoIds = jobIds.stream()
|
||||
.filter(id -> Integer.parseInt(id.replace("job-", "")) % 2 == 0)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Result dr = defAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds));
|
||||
Result fr = fixAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds));
|
||||
|
||||
// Sort both for comparison (order may differ)
|
||||
List<String> dSorted = new ArrayList<>(dr.toRemoveLocks); Collections.sort(dSorted);
|
||||
List<String> fSorted = new ArrayList<>(fr.toRemoveLocks); Collections.sort(fSorted);
|
||||
|
||||
assertEquals(dSorted, fSorted, "toRemoveLocks contents");
|
||||
// All odd-numbered jobs should be in toRemoveLocks
|
||||
assertTrue(dr.toRemoveLocks.size() == 10, "expected 10 orphan locks, got " + dr.toRemoveLocks.size());
|
||||
System.out.println("PASS correctness (J=20, half missing)");
|
||||
}
|
||||
|
||||
// Correctness test 2: all jobs have info records (no locks to remove)
|
||||
{
|
||||
List<String> jobIds = makeJobIds(10);
|
||||
Result dr = defAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobIds));
|
||||
Result fr = fixAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobIds));
|
||||
assertEquals(0, dr.toRemoveLocks.size(), "no orphan locks (defective)");
|
||||
assertEquals(0, fr.toRemoveLocks.size(), "no orphan locks (fixed)");
|
||||
System.out.println("PASS correctness all-present (J=10)");
|
||||
}
|
||||
|
||||
// Benchmark at J=2000
|
||||
{
|
||||
int J = 2000;
|
||||
List<String> jobIds = makeJobIds(J);
|
||||
// Half the jobs have info records
|
||||
List<String> jobInfoIds = jobIds.subList(0, J / 2);
|
||||
|
||||
// warm up
|
||||
for (int i = 0; i < 5; i++) {
|
||||
defAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds));
|
||||
fixAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds));
|
||||
}
|
||||
|
||||
long defNs = 0, fixNs = 0;
|
||||
int reps = 30;
|
||||
for (int i = 0; i < reps; i++) {
|
||||
defNs += defAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds)).ns;
|
||||
fixNs += fixAlg.releaseJobLock(new ArrayList<>(jobIds), new ArrayList<>(jobInfoIds)).ns;
|
||||
}
|
||||
defNs /= reps; fixNs /= reps;
|
||||
double ratio = (double) defNs / Math.max(1, fixNs);
|
||||
|
||||
System.out.printf("BENCH J=%d reps=%d%n", J, reps);
|
||||
System.out.printf(" defective avg: %,d ns%n", defNs);
|
||||
System.out.printf(" fixed avg: %,d ns%n", fixNs);
|
||||
System.out.printf(" speedup: %.1fx%n", ratio);
|
||||
|
||||
assertTrue(ratio >= 2.0, "Expected fixed >= 2x faster, got " + ratio + "x");
|
||||
System.out.println("PASS speedup >= 2x");
|
||||
}
|
||||
|
||||
System.out.println("=== ALL PASS ===");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue