use std::time::Instant;
use liminal_protocol::wire::{LeaveAttemptToken, LeaveRequest};
use super::super::test_participant_config;
use super::{
AttachAttemptToken, ClientRequest, CredentialAttachRequest, EnrollBound, EnrollmentRequest,
EnrollmentToken, Error, Generation, ParticipantAck, ParticipantRecord, RecordAdmission,
RecordAdmissionAttemptToken, RemoteParticipantInbound, SdkParticipant, SdkSocketFixture,
ServerPush, ServerValue, connect_participant, send_operation,
};
#[path = "e2e_sdk_seat_replay_tests.rs"]
mod replay_tests;
const SAMPLES: usize = 10;
const DEFAULT_LONGEST_HISTORY: u64 = 100;
const LEAVE_OBSERVATION_BUDGET: std::time::Duration = std::time::Duration::from_secs(600);
#[derive(Debug, Default)]
struct Pushes {
ordinary: u64,
total: u64,
through: u64,
}
impl Pushes {
fn absorb(&mut self, value: ServerPush) {
self.total += 1;
if let ServerPush::ParticipantDelivery(delivery) = value {
self.through = self.through.max(delivery.delivery_seq);
if matches!(delivery.record, ParticipantRecord::OrdinaryRecord { .. }) {
self.ordinary += 1;
}
}
}
}
fn exchange(
seat: &SdkParticipant,
request: ClientRequest,
pushes: &mut Pushes,
) -> Result<ServerValue, Box<dyn Error>> {
let observe_long_leave = matches!(&request, ClientRequest::Leave(_));
let started = Instant::now();
send_operation(seat, request)?;
loop {
let inbound = if observe_long_leave {
let remaining = LEAVE_OBSERVATION_BUDGET.saturating_sub(started.elapsed());
seat.receive_within(remaining)?
.ok_or("benchmark Leave observation budget expired")?
} else {
seat.receive()?
};
match inbound {
RemoteParticipantInbound::Applied { value, .. }
| RemoteParticipantInbound::OutcomeUnknown { value, .. } => return Ok(value),
RemoteParticipantInbound::Push { value, .. } => pushes.absorb(value),
other @ RemoteParticipantInbound::Refused { .. } => {
return Err(format!("seat operation was not applied: {other:?}").into());
}
}
}
}
fn enroll(
seat: &SdkParticipant,
conversation: u64,
token: u8,
) -> Result<EnrollBound, Box<dyn Error>> {
let value = exchange(
seat,
ClientRequest::Enrollment(EnrollmentRequest {
conversation_id: conversation,
enrollment_token: EnrollmentToken::new([token; 16]),
}),
&mut Pushes::default(),
)?;
let ServerValue::EnrollBound(bound) = value else {
return Err(format!("fresh seat enrollment refused: {value:?}").into());
};
Ok(bound)
}
#[derive(Debug)]
struct Sample {
connect: u128,
enroll: u128,
attach_reply: u128,
replay_settle: u128,
attach: u128,
leave: u128,
open: u128,
ordinary_replayed: u64,
}
fn sample(
server: &SdkSocketFixture,
conversation: u64,
sample_index: u8,
history: u64,
) -> Result<Sample, Box<dyn Error>> {
let opening = Instant::now();
let seat = connect_participant(server.address()?, conversation)?;
let connect_us = opening.elapsed().as_micros();
let stage = Instant::now();
let bound = enroll(&seat, conversation, 0x30 + sample_index)?;
let enroll_us = stage.elapsed().as_micros();
let stage = Instant::now();
let mut pushes = Pushes::default();
let value = exchange(
&seat,
ClientRequest::CredentialAttach(CredentialAttachRequest {
conversation_id: conversation,
participant_id: bound.participant_id(),
capability_generation: bound.capability_generation(),
attach_secret: bound.attach_secret(),
attach_attempt_token: AttachAttemptToken::new([0x60 + sample_index; 16]),
accept_marker_delivery_seq: None,
}),
&mut pushes,
)?;
let ServerValue::AttachBound(attached) = value else {
return Err(format!("fresh credential attach refused: {value:?}").into());
};
let attach_reply_us = stage.elapsed().as_micros();
while let Some(inbound) = seat.try_receive()? {
match inbound {
RemoteParticipantInbound::Push { value, .. } => pushes.absorb(value),
other => return Err(format!("unexpected replay inbound: {other:?}").into()),
}
}
if pushes.through > attached.persisted_cursor() {
let value = exchange(
&seat,
ClientRequest::ParticipantAck(ParticipantAck {
conversation_id: conversation,
participant_id: bound.participant_id(),
capability_generation: attached.capability_generation(),
through_seq: pushes.through,
}),
&mut pushes,
)?;
assert!(
matches!(
value,
ServerValue::AckCommitted(_) | ServerValue::AckNoOp(_)
),
"replay acknowledgement refused: {value:?}"
);
}
let attach_us = stage.elapsed().as_micros();
let open_us = opening.elapsed().as_micros();
let ordinary_at_open = pushes.ordinary;
println!(
"SEAT_OPEN history={history} sample={sample_index} connect_us={connect_us} enrol_us={enroll_us} attach_reply_us={attach_reply_us} attach_us={attach_us} open_us={open_us} ordinary_at_open={ordinary_at_open}"
);
let stage = Instant::now();
let value = match exchange(
&seat,
ClientRequest::Leave(LeaveRequest {
conversation_id: conversation,
participant_id: bound.participant_id(),
capability_generation: attached.capability_generation(),
attach_secret: attached.attach_secret(),
leave_attempt_token: LeaveAttemptToken::new([0x90 + sample_index; 16]),
}),
&mut pushes,
) {
Ok(value) => value,
Err(error) => {
eprintln!(
"SEAT_LEAVE_FAILED history={history} sample={sample_index} elapsed_us={} error={error}",
stage.elapsed().as_micros()
);
return Err(error);
}
};
let leave_us = stage.elapsed().as_micros();
assert!(
matches!(value, ServerValue::LeaveCommitted(_)),
"leave refused: {value:?}"
);
println!(
"SEAT_SAMPLE history={history} sample={sample_index} connect_us={connect_us} enrol_us={enroll_us} attach_reply_us={attach_reply_us} replay_settle_us={} attach_us={attach_us} leave_us={leave_us} open_us={open_us} ordinary_at_open={ordinary_at_open} ordinary_after_leave={} pushes={} through={} persisted_cursor={} client_store=memory broker_store=disk",
attach_us.saturating_sub(attach_reply_us),
pushes.ordinary,
pushes.total,
pushes.through,
attached.persisted_cursor()
);
Ok(Sample {
connect: connect_us,
enroll: enroll_us,
attach_reply: attach_reply_us,
replay_settle: attach_us.saturating_sub(attach_reply_us),
attach: attach_us,
leave: leave_us,
open: open_us,
ordinary_replayed: pushes.ordinary,
})
}
fn median(samples: &[Sample], value: impl Fn(&Sample) -> u128) -> u128 {
let mut values: Vec<_> = samples.iter().map(value).collect();
values.sort_unstable();
u128::midpoint(values[SAMPLES / 2 - 1], values[SAMPLES / 2])
}
#[test]
fn sdk_fresh_seat_stage_latency_matrix() -> Result<(), Box<dyn Error>> {
let longest_history: u64 = match std::env::var("LIMINAL_SEAT_MATRIX_HISTORY") {
Ok(value) => value.parse()?,
Err(std::env::VarError::NotPresent) => DEFAULT_LONGEST_HISTORY,
Err(error) => return Err(error.into()),
};
println!(
"SEAT_OBSERVATION leave_budget_s={} normal_sdk_reply_deadline_s=60 client_store=memory broker_store=disk",
LEAVE_OBSERVATION_BUDGET.as_secs()
);
let home = tempfile::tempdir()?;
let mut config = test_participant_config();
let retained = longest_history + 2_000;
config.max_retained_record_rows = retained;
config.retained_capacity_entries = retained * 2;
config.identity_slots = 12;
let server = SdkSocketFixture::start_with_config(&home.path().join("seat-matrix"), config)?;
let mut longest = Vec::new();
for history in [0, longest_history / 10, longest_history] {
let conversation = 0x53_00 + history;
let producer = connect_participant(server.address()?, conversation)?;
let bound = enroll(&producer, conversation, 0x11)?;
let seeded = Instant::now();
for record in 0..history {
let mut token = [0xA1; 16];
token[..8].copy_from_slice(&record.to_be_bytes());
let value = exchange(
&producer,
ClientRequest::RecordAdmission(RecordAdmission {
conversation_id: conversation,
participant_id: bound.participant_id(),
capability_generation: Generation::ONE,
record_admission_attempt_token: RecordAdmissionAttemptToken::new(token),
payload: record.to_be_bytes().to_vec(),
}),
&mut Pushes::default(),
)?;
assert!(
matches!(value, ServerValue::RecordCommitted(_)),
"seed refused: {value:?}"
);
if (record + 1) % 1_000 == 0 {
println!(
"SEAT_SEED history={history} committed={} elapsed_ms={}",
record + 1,
seeded.elapsed().as_millis()
);
}
}
println!(
"SEAT_SEEDED history={history} elapsed_ms={}",
seeded.elapsed().as_millis()
);
let mut samples = Vec::new();
for index in 0..SAMPLES {
let index = u8::try_from(index)?;
samples.push(sample(&server, conversation, index, history)?);
}
println!(
"SEAT_MEDIAN history={history} n={SAMPLES} connect_us={} enrol_us={} attach_reply_us={} replay_settle_us={} attach_us={} leave_us={} open_us={} ordinary_replayed_max={}",
median(&samples, |s| s.connect),
median(&samples, |s| s.enroll),
median(&samples, |s| s.attach_reply),
median(&samples, |s| s.replay_settle),
median(&samples, |s| s.attach),
median(&samples, |s| s.leave),
median(&samples, |s| s.open),
samples
.iter()
.map(|s| s.ordinary_replayed)
.max()
.unwrap_or(0)
);
if history == longest_history {
longest = samples;
}
drop(producer);
}
server.stop()?;
assert!(
longest.iter().all(|s| s.leave < 60_000_000),
"Leave at {longest_history} records exceeded the unchanged SDK reply deadline: \
{longest:?}"
);
assert!(
longest.iter().all(|s| s.ordinary_replayed == 0),
"a fresh default seat replayed history without requesting it: {longest:?}"
);
Ok(())
}