use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::{Duration, Instant};
use subetha_cxc::adaptive_ring::{
AdaptiveRing, AdaptiveRingSidecar, DefaultRingShapePolicy,
};
use subetha_cxc::ring_contract::{RingContract, OrderingContract};
use subetha_cxc::{RingShape, SharedAtomicU64};
const CAP: usize = 256;
fn fifo(push: u8, pop: u8) -> RingContract {
RingContract { max_concurrent_push: push, max_concurrent_pop: pop,
ordering: OrderingContract::Fifo, capacity_bound: None }
}
fn per_producer(push: u8, pop: u8) -> RingContract {
RingContract { max_concurrent_push: push, max_concurrent_pop: pop,
ordering: OrderingContract::FifoPerProducer, capacity_bound: None }
}
fn wait_for_shape(ring: &AdaptiveRing, target: RingShape, timeout: Duration) {
let deadline = Instant::now() + timeout;
while ring.current_shape() != target && Instant::now() < deadline {
std::thread::sleep(Duration::from_millis(2));
}
}
fn run_morph_arm(label: &str, contract: Option<RingContract>, expect: RingShape) -> RingShape {
let mut ring = AdaptiveRing::create_anon(4, 4, CAP).expect("create");
if let Some(g) = contract {
ring = ring.with_contract(g);
}
let ring = Arc::new(ring);
let sidecar = AdaptiveRingSidecar::spawn(
Arc::clone(&ring),
DefaultRingShapePolicy { hysteresis: Duration::from_millis(15) },
Duration::from_millis(5),
);
let _p: Vec<_> = (0..4).map(|_| ring.register_producer().expect("p")).collect();
let _c: Vec<_> = (0..4).map(|_| ring.register_consumer().expect("c")).collect();
wait_for_shape(&ring, expect, Duration::from_secs(3));
let shape = ring.current_shape();
let n = 2000u64;
let rp = Arc::clone(&ring);
let producer = thread::spawn(move || {
let mut payload = [0u8; 16];
for i in 0..n {
payload[..8].copy_from_slice(&i.to_le_bytes());
while rp.try_send(0, &payload).is_err() {
std::hint::spin_loop();
}
}
});
let mut out = [0u8; 64];
let mut got = 0u64;
let deadline = Instant::now() + Duration::from_secs(5);
while got < n {
if ring.try_recv(0, &mut out).is_ok() {
got += 1;
} else if Instant::now() > deadline {
break;
} else {
std::hint::spin_loop();
}
}
producer.join().unwrap();
sidecar.shutdown();
println!(" {label:<22} -> shape {shape:?}, round-tripped {got}/{n}");
assert_eq!(got, n, "{label}: the contract-selected shape must carry data");
shape
}
fn admission_child(counter_path: &str, max_push: u8, attempts: usize) {
let counter = SharedAtomicU64::open(counter_path).expect("open counter");
let contract = RingContract {
max_concurrent_push: max_push, max_concurrent_pop: 0,
ordering: OrderingContract::Unordered, capacity_bound: None,
};
let mut admitted = 0;
let mut rejected = 0;
for _ in 0..attempts {
let cur = counter.fetch_add(1, Ordering::AcqRel);
if contract.permits_producer(cur as usize) {
admitted += 1;
} else {
counter.fetch_sub(1, Ordering::AcqRel);
rejected += 1;
}
}
println!("child(pid {}): {admitted} admitted, {rejected} rejected (global limit {max_push})",
std::process::id());
}
fn main() {
let argv: Vec<String> = std::env::args().collect();
if argv.get(1).map(String::as_str) == Some("--admission-child") {
admission_child(&argv[2], argv[3].parse().unwrap(), argv[4].parse().unwrap());
return;
}
println!("operation-contract legality layer - E2E\n");
println!("[1/4] attach check: contract caps producers at 3 on a ring sized for 8");
let ring = AdaptiveRing::create_anon(8, 8, CAP).expect("create")
.with_contract(RingContract {
max_concurrent_push: 3, max_concurrent_pop: 8,
ordering: OrderingContract::Unordered, capacity_bound: None,
});
for i in 0..3 {
ring.register_producer().unwrap_or_else(|_| panic!("producer {i} should register"));
}
let rejected = ring.register_producer();
println!(" registered 3 producers OK; 4th -> {rejected:?}");
assert!(rejected.is_err(), "4th producer must be rejected by the contract");
println!("\n[2/4] adversarial: 4P/4C; policy wants Mpmc; contract should steer the morph");
let fifo_shape = run_morph_arm("Fifo contract", Some(fifo(8, 8)), RingShape::Vyukov);
let control_shape = run_morph_arm("no contract (control)", None, RingShape::Mpmc);
assert_eq!(fifo_shape, RingShape::Vyukov,
"Fifo contract must steer the auto-morph to order-preserving Vyukov");
assert_eq!(control_shape, RingShape::Mpmc,
"no contract morphs to the sharded Mpmc default");
println!("\n[3/4] enablement: FifoPerProducer permits the sharded Mpmc");
let pp_shape = run_morph_arm("FifoPerProducer contract", Some(per_producer(8, 8)), RingShape::Mpmc);
assert_eq!(pp_shape, RingShape::Mpmc,
"FifoPerProducer must permit the sharded Mpmc morph");
println!("\n[4/4] cross-process admission: global producer limit 3, child attempts 6");
let counter_path = std::env::temp_dir()
.join(format!("subetha_contract_admit_{}", std::process::id()));
let counter = SharedAtomicU64::create(&counter_path, 0).expect("create counter");
let self_exe = std::env::current_exe().expect("exe");
let status = std::process::Command::new(&self_exe)
.arg("--admission-child")
.arg(counter_path.display().to_string())
.arg("3")
.arg("6")
.status()
.expect("spawn child");
assert!(status.success());
let final_count = counter.load(Ordering::Acquire);
println!(" shared admission counter settled at {final_count} (== the limit 3)");
assert_eq!(final_count, 3, "global admission must hold exactly the contract's limit");
std::fs::remove_file(&counter_path).ok();
println!("\nall checks passed: the contract unified the attach check, steered the");
println!("auto-morph inside the declared ordering envelope, and enforced a");
println!("cross-process producer admission limit.");
}