use std::{
fmt,
future::Future,
mem,
ops::{Deref, DerefMut},
panic,
panic::AssertUnwindSafe,
pin::Pin,
sync,
sync::{Arc, Condvar, Mutex, MutexGuard, atomic::Ordering},
task::{Context, Poll, Waker},
thread,
time::{Duration, Instant},
};
use query_planning::{
correlation::{QueryId, TraceId},
error::QueryError,
};
use super::{
AttemptBackendCounters, AttemptCancellation, AttemptCompletionQueue, AttemptLifecycle, AttemptLifecycleError,
observation::AttemptObservation,
};
#[cfg(test)]
use crate::observability::{
CleanupFailurePhase, CleanupFailureSummary, RuntimeCleanupFailureObservation, RuntimeObservationDeliveryGate,
RuntimeObservationPayload,
};
#[cfg(any(test, feature = "test-hooks"))]
use crate::runtime::BackendLifecycle;
use crate::{
observability::{
AttemptAdmissionFact, AttemptAdmissionWaitFact, AttemptAlternateDeviceEligibility, AttemptCapacityDisposition,
AttemptCleanupDisposition, AttemptComposedScheduleProjection, AttemptDisposition, AttemptFailureOperation,
AttemptFailureSummary, AttemptId, AttemptQueryId, AttemptReportSealProvider, AttemptRetryAdvice,
AttemptTerminalCommit, AttemptTraceContext, CleanupFailureTally, QUERY_ATTEMPT_REPORT_SCHEMA,
QueryAttemptReport, QueryCleanupSealDelivery, RuntimeObservationClock, RuntimeObservationConfig,
RuntimeObservationFooter, RuntimeObservationHandle, RuntimeTerminalOutcome, SealedRuntimeObservationSnapshot,
SystemRuntimeObservationClock,
},
runtime::ObservationPermit,
};
pub struct BeginAttemptRequest {
pub query_id: Option<AttemptQueryId>,
pub trace_context: Option<AttemptTraceContext>,
pub deadline: Option<Instant>,
pub observation: RuntimeObservationConfig,
}
impl Default for BeginAttemptRequest {
fn default() -> Self {
Self {
query_id: None,
trace_context: None,
deadline: None,
observation: RuntimeObservationConfig::native_execution(),
}
}
}
impl fmt::Debug for BeginAttemptRequest {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("BeginAttemptRequest")
.field("query_id", &self.query_id)
.field("trace_context", &self.trace_context)
.field("deadline", &self.deadline)
.finish_non_exhaustive()
}
}
pub struct AttemptBegin {
pub owner: AttemptOwner,
pub completion: AttemptCompletionFactory,
}
impl fmt::Debug for AttemptBegin {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptBegin").field("attempt_id", &self.owner.attempt_id()).finish_non_exhaustive()
}
}
pub struct AttemptOwner(Arc<AttemptInner>);
pub struct AttemptHandle(Arc<AttemptCore>);
pub struct AttemptAdmissionRejection {
core: Arc<AttemptCore>,
finalizer_slot: AttemptFinalizerSlot,
}
#[derive(Clone)]
pub struct AttemptAdmissionBinding {
core: Arc<AttemptCore>,
finalizer_slot: AttemptFinalizerSlot,
}
pub(crate) struct AttemptFinalizer(Arc<AttemptCore>);
pub(crate) struct AttemptAdmission(AttemptFinalizer);
pub(crate) struct AttemptReportPublisher(Arc<AttemptCore>);
impl AttemptReportPublisher {
pub(crate) fn begin_cleanup(&self) {
self.0.observation.begin_cleanup();
}
pub(crate) fn seal(&self, fallback: RuntimeTerminalOutcome) -> QueryCleanupSealDelivery {
self.0.seal_observation(fallback)
}
pub(crate) fn attempt(&self) -> AttemptHandle {
AttemptHandle(Arc::clone(&self.0))
}
}
impl fmt::Debug for AttemptReportPublisher {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptReportPublisher").field("attempt_id", &self.0.attempt_id).finish_non_exhaustive()
}
}
#[derive(Clone)]
pub(crate) struct AttemptFinalizerSlot(Arc<Mutex<Option<AttemptFinalizer>>>);
impl Clone for AttemptHandle {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl Clone for AttemptAdmissionRejection {
fn clone(&self) -> Self {
Self { core: Arc::clone(&self.core), finalizer_slot: self.finalizer_slot.clone() }
}
}
pub struct AttemptCompletion {
shared: Arc<AttemptShared>,
}
impl Clone for AttemptCompletion {
fn clone(&self) -> Self {
let mut state = self.shared.lock();
state.completion.receivers = state.completion.receivers.saturating_add(1);
Self { shared: Arc::clone(&self.shared) }
}
}
pub struct AttemptCompletionFactory {
shared: Arc<AttemptShared>,
}
impl Clone for AttemptCompletionFactory {
fn clone(&self) -> Self {
Self { shared: Arc::clone(&self.shared) }
}
}
impl AttemptCompletionFactory {
pub fn completion(&self) -> AttemptCompletion {
let mut state = self.shared.lock();
state.completion.receivers = state.completion.receivers.saturating_add(1);
AttemptCompletion { shared: Arc::clone(&self.shared) }
}
pub fn try_report(&self) -> Option<Arc<QueryAttemptReport>> {
self.shared.lock().completion.visible_report()
}
}
struct SealedAttemptReportSink {
notify: Box<dyn Fn(Arc<QueryAttemptReport>) + Send + Sync>,
}
impl SealedAttemptReportSink {
fn invoke(&self, report: Arc<QueryAttemptReport>) {
let _ = panic::catch_unwind(AssertUnwindSafe(|| (self.notify)(report)));
}
}
struct CompletionState {
report: Option<Arc<QueryAttemptReport>>,
report_visible: bool,
sealed_report_sinks: Vec<SealedAttemptReportSink>,
wakers: Vec<Waker>,
receivers: u64,
}
impl CompletionState {
fn visible_report(&self) -> Option<Arc<QueryAttemptReport>> {
self.report_visible.then(|| self.report.as_ref().map(Arc::clone)).flatten()
}
}
pub(crate) trait AdmittedGrantRelease: Send + Sync {
fn request_release(&self);
}
struct AttemptState {
lifecycle: AttemptLifecycle,
completion: CompletionState,
admitted_release: Option<Arc<dyn AdmittedGrantRelease>>,
}
struct AttemptShared {
state: Mutex<AttemptState>,
changed: Condvar,
}
impl AttemptShared {
fn lock(&self) -> MutexGuard<'_, AttemptState> {
self.state.lock().unwrap_or_else(sync::PoisonError::into_inner)
}
}
struct LifecycleGuard<'a>(MutexGuard<'a, AttemptState>);
impl Deref for LifecycleGuard<'_> {
type Target = AttemptLifecycle;
fn deref(&self) -> &AttemptLifecycle {
&self.0.lifecycle
}
}
impl DerefMut for LifecycleGuard<'_> {
fn deref_mut(&mut self) -> &mut AttemptLifecycle {
&mut self.0.lifecycle
}
}
struct AttemptCore {
attempt_id: AttemptId,
query_id: Option<AttemptQueryId>,
trace_context: Option<AttemptTraceContext>,
shared: Arc<AttemptShared>,
clock: Arc<dyn RuntimeObservationClock>,
cancellation: AttemptCancellation,
observation: AttemptObservation,
counters: Arc<AttemptBackendCounters>,
completion_queue: Option<Arc<AttemptCompletionQueue>>,
observation_permit: Mutex<Option<ObservationPermit>>,
}
struct AttemptInner {
core: Arc<AttemptCore>,
finalizer_slot: AttemptFinalizerSlot,
}
impl fmt::Debug for AttemptCore {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptCore").field("attempt_id", &self.attempt_id).finish_non_exhaustive()
}
}
impl AttemptCore {
fn lock_lifecycle(&self) -> LifecycleGuard<'_> {
LifecycleGuard(self.shared.lock())
}
fn monotonic_ns(&self) -> u64 {
self.clock.monotonic_ns()
}
fn release_admitted_grant(&self) {
let release = self.shared.lock().admitted_release.take();
if let Some(release) = release {
release.request_release();
}
}
fn register_sealed_report_sink<F>(&self, sink: F)
where F: Fn(Arc<QueryAttemptReport>) + Send + Sync + 'static {
let mut sink = Some(SealedAttemptReportSink { notify: Box::new(sink) });
let published = {
let mut state = self.shared.lock();
let completion = &mut state.completion;
match &completion.report {
Some(report) if completion.report_visible => Some(Arc::clone(report)),
Some(_) => {
completion.sealed_report_sinks.push(sink.take().expect("sink exists"));
None
},
None => {
completion.sealed_report_sinks.push(sink.take().expect("sink exists"));
None
},
}
};
if let Some(report) = published {
sink.expect("unregistered sink exists").invoke(report);
}
}
fn report(&self, lifecycle: &AttemptLifecycle, cleanup_failures: &CleanupFailureTally) -> QueryAttemptReport {
let terminal_commit = lifecycle.cleanup_commit();
let cleanup_failure_count = cleanup_failures.count();
let outcome = lifecycle.terminal_outcome().cloned().unwrap_or(RuntimeTerminalOutcome::Dropped);
let primary_failure = lifecycle.primary_failure_summary().cloned();
let capacity_disposition = terminal_commit
.map(AttemptTerminalCommit::capacity_disposition)
.unwrap_or(AttemptCapacityDisposition::NotAdmitted);
let health_transition = terminal_commit.map(AttemptTerminalCommit::health_transition);
let native_fault_evidence = terminal_commit.and_then(AttemptTerminalCommit::native_fault_evidence);
let resource_evidence = terminal_commit.and_then(AttemptTerminalCommit::resource_evidence);
let alternate_device_eligibility = terminal_commit
.map(AttemptTerminalCommit::alternate_device_eligibility)
.unwrap_or(AttemptAlternateDeviceEligibility::Unavailable);
let retry_advice = AttemptRetryAdvice::from_sealed_attempt(
&outcome,
primary_failure.as_ref(),
capacity_disposition,
health_transition,
native_fault_evidence,
resource_evidence,
alternate_device_eligibility,
);
QueryAttemptReport {
schema: QUERY_ATTEMPT_REPORT_SCHEMA.to_string(),
attempt_id: self.attempt_id,
query_id: self.query_id.clone(),
trace_context: self.trace_context.clone(),
disposition: lifecycle.recorded_disposition().unwrap_or(AttemptDisposition::Unplanned),
outcome,
primary_failure,
retry_advice,
device_ordinal: lifecycle.admission_fact().map(|fact| fact.device_ordinal),
admission: lifecycle.admission_fact().cloned(),
admission_wait: lifecycle.admission_wait_fact(),
composed_schedule: lifecycle.composed_schedule_projection().cloned(),
timestamps: lifecycle.timestamps(),
cleanup_disposition: if lifecycle.admission_fact().is_some() {
if cleanup_failure_count == 0 {
AttemptCleanupDisposition::Completed
} else {
AttemptCleanupDisposition::CompletedWithFailures
}
} else {
AttemptCleanupDisposition::NotRequired
},
cleanup_failure_count,
cleanup_failure_count_complete: cleanup_failures.complete(),
first_cleanup_failure: cleanup_failures.first().cloned(),
capacity_disposition,
final_domain_usage: terminal_commit.and_then(AttemptTerminalCommit::final_domain_usage),
health_transition,
native_fault_evidence,
resource_evidence,
observation_lost_records: 0,
observation_retained_records: 0,
observation_retained_bytes: 0,
observation_truncated: false,
observation_degraded: false,
unix_epoch_ns: self.clock.unix_epoch_ns(),
}
}
fn terminalize_for_release(
&self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
let mut lifecycle = self.lock_lifecycle();
if lifecycle.terminal_outcome().is_some() {
return Err(AttemptLifecycleError::DoubleTerminalization);
}
lifecycle.terminalize(fallback, self.monotonic_ns())?;
Ok(lifecycle.terminal_outcome().cloned().expect("terminal outcome was recorded"))
}
fn terminalize_for_release_with_primary_failure(
&self,
outcome: RuntimeTerminalOutcome,
summary: AttemptFailureSummary,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
let mut lifecycle = self.lock_lifecycle();
if lifecycle.terminal_outcome().is_some() {
return Err(AttemptLifecycleError::DoubleTerminalization);
}
lifecycle.primary_failure(summary);
lifecycle.terminalize(outcome, self.monotonic_ns())?;
Ok(lifecycle.terminal_outcome().cloned().expect("terminal outcome was recorded"))
}
fn canonical_terminal_outcome(&self, fallback: RuntimeTerminalOutcome) -> RuntimeTerminalOutcome {
let mut lifecycle = self.lock_lifecycle();
if let Some(outcome) = lifecycle.terminal_outcome() {
return outcome.clone();
}
let fallback =
lifecycle.primary_failure_summary().map(RuntimeTerminalOutcome::from_primary_failure).unwrap_or(fallback);
let at = self.monotonic_ns();
lifecycle.terminalize(fallback.clone(), at).unwrap_or(());
lifecycle.terminal_outcome().cloned().unwrap_or(fallback)
}
fn seal_observation(self: &Arc<Self>, fallback: RuntimeTerminalOutcome) -> QueryCleanupSealDelivery {
let outcome = self.canonical_terminal_outcome(fallback);
self.observation.seal(outcome, &self.report_seal_provider())
}
fn report_seal_provider(self: &Arc<Self>) -> AttemptReportSealProvider {
let core = Arc::clone(self);
Arc::new(move |footer, cleanup_failures| {
core.finish_with_footer(footer, cleanup_failures)
.expect("attempt lifecycle must complete while sealing its sole immutable report")
})
}
fn finish_with_footer(
&self,
footer: &RuntimeObservationFooter,
cleanup_failures: &CleanupFailureTally,
) -> Result<Arc<QueryAttemptReport>, AttemptLifecycleError> {
let report = {
let mut state = self.shared.lock();
loop {
match &state.completion.report {
Some(existing) if state.completion.report_visible => return Ok(Arc::clone(existing)),
Some(_) => state = self.shared.changed.wait(state).unwrap_or_else(sync::PoisonError::into_inner),
None => break,
}
}
if !state.lifecycle.is_ready() {
state.lifecycle.ready(self.monotonic_ns())?;
}
let mut report = self.report(&state.lifecycle, cleanup_failures);
report.set_observation_completeness(footer);
let report = Arc::new(report);
state.completion.report = Some(Arc::clone(&report));
report
};
let (wakers, abandoned) = loop {
let sinks = mem::take(&mut self.shared.lock().completion.sealed_report_sinks);
for sink in sinks {
sink.invoke(Arc::clone(&report));
}
let mut state = self.shared.lock();
let completion = &mut state.completion;
if !completion.sealed_report_sinks.is_empty() {
continue;
}
debug_assert!(completion.report.as_ref().is_some_and(|existing| Arc::ptr_eq(existing, &report)));
completion.report_visible = true;
break (mem::take(&mut completion.wakers), completion.receivers == 0);
};
self.counters.reports_ready.fetch_add(1, Ordering::AcqRel);
self.shared.changed.notify_all();
for waker in wakers {
waker.wake();
}
if abandoned && let Some(queue) = &self.completion_queue {
if queue.try_push(Arc::clone(&report)) {
self.counters.completion_queue_pushed.fetch_add(1, Ordering::AcqRel);
} else {
self.counters.completion_queue_overflowed.fetch_add(1, Ordering::AcqRel);
}
}
self.observation_permit.lock().unwrap_or_else(sync::PoisonError::into_inner).take();
Ok(report)
}
}
impl AttemptOwner {
pub(crate) fn begin(
request: BeginAttemptRequest,
permit: ObservationPermit,
counters: Arc<AttemptBackendCounters>,
queue: Option<Arc<AttemptCompletionQueue>>,
) -> AttemptBegin {
Self::begin_with_clock(request, permit, counters, queue, Arc::new(SystemRuntimeObservationClock::new()))
}
pub(crate) fn begin_with_clock(
request: BeginAttemptRequest,
permit: ObservationPermit,
counters: Arc<AttemptBackendCounters>,
queue: Option<Arc<AttemptCompletionQueue>>,
clock: Arc<dyn RuntimeObservationClock>,
) -> AttemptBegin {
let observation = if request.observation.is_enabled() {
request.observation
} else {
RuntimeObservationConfig::bounded(0, 0)
};
let shared = Arc::new(AttemptShared {
state: Mutex::new(AttemptState {
lifecycle: AttemptLifecycle::new(clock.monotonic_ns()),
completion: CompletionState {
report: None,
report_visible: false,
sealed_report_sinks: Vec::new(),
wakers: Vec::new(),
receivers: 0,
},
admitted_release: None,
}),
changed: Condvar::new(),
});
let observation_query_id = request
.query_id
.as_ref()
.map(|query_id| QueryId::new(query_id.as_str()))
.unwrap_or_else(|| QueryId::new(""));
let trace_id = request.trace_context.as_ref().map(|trace| TraceId::new(trace.as_str()));
let core = Arc::new(AttemptCore {
attempt_id: AttemptId::mint(),
query_id: request.query_id,
trace_context: request.trace_context,
shared: Arc::clone(&shared),
clock: Arc::clone(&clock),
cancellation: AttemptCancellation::new(request.deadline),
observation: AttemptObservation::new(observation_query_id, trace_id, observation, clock),
counters,
completion_queue: queue,
observation_permit: Mutex::new(Some(permit)),
});
let finalizer_slot = AttemptFinalizerSlot::new(AttemptFinalizer(Arc::clone(&core)));
AttemptBegin {
owner: Self(Arc::new(AttemptInner { core, finalizer_slot })),
completion: AttemptCompletionFactory { shared },
}
}
#[cfg(any(test, feature = "test-hooks"))]
#[doc(hidden)]
pub fn begin_for_test(request: BeginAttemptRequest) -> AttemptBegin {
Self::begin(
request,
BackendLifecycle::new().try_begin_observation().expect("a new backend lifecycle admits observation"),
Arc::new(AttemptBackendCounters::default()),
None,
)
}
#[cfg(any(test, feature = "test-hooks"))]
pub(crate) fn native_for_test() -> Self {
let begin = Self::begin_for_test(BeginAttemptRequest::default());
begin.owner.handle().set_disposition(AttemptDisposition::Native).expect("a new attempt accepts a disposition");
begin.owner
}
pub fn attempt_id(&self) -> AttemptId {
self.0.core.attempt_id
}
pub fn handle(&self) -> AttemptHandle {
AttemptHandle(Arc::clone(&self.0.core))
}
pub fn register_sealed_report_sink<F>(&self, sink: F)
where F: Fn(Arc<QueryAttemptReport>) + Send + Sync + 'static {
self.0.core.register_sealed_report_sink(sink);
}
pub fn admission_rejection(&self) -> AttemptAdmissionRejection {
AttemptAdmissionRejection { core: Arc::clone(&self.0.core), finalizer_slot: self.0.finalizer_slot.clone() }
}
pub fn admission_binding(&self) -> AttemptAdmissionBinding {
AttemptAdmissionBinding { core: Arc::clone(&self.0.core), finalizer_slot: self.0.finalizer_slot.clone() }
}
pub fn completion(&self) -> AttemptCompletion {
self.0.core.shared.lock().completion.receivers += 1;
AttemptCompletion { shared: Arc::clone(&self.0.core.shared) }
}
pub fn cancellation(&self) -> AttemptCancellation {
self.0.core.cancellation.clone()
}
#[cfg(test)]
pub(crate) fn sealed_snapshot_for_test(&self) -> Option<SealedRuntimeObservationSnapshot> {
self.0.core.observation.sealed_snapshot()
}
#[cfg(test)]
pub(crate) fn observation_for_test(&self) -> RuntimeObservationHandle {
self.0.core.observation.handle()
}
#[cfg(test)]
pub(crate) fn arm_delivery_gate_for_test(&self) -> Arc<RuntimeObservationDeliveryGate> {
self.0.core.observation.arm_delivery_gate()
}
pub fn commit_terminal(&self, outcome: RuntimeTerminalOutcome) -> Result<(), AttemptLifecycleError> {
let terminal = self.0.core.terminalize_for_release(outcome)?;
self.commit_resolved_terminal(terminal)
}
fn commit_resolved_terminal(&self, terminal: RuntimeTerminalOutcome) -> Result<(), AttemptLifecycleError> {
match self.0.finalizer_slot.finalize_not_admitted(terminal) {
Ok(terminal) => {
let _ = self.0.core.seal_observation(terminal).deliver();
Ok(())
},
Err(AttemptLifecycleError::FinalizationUnavailable) => {
self.0.core.release_admitted_grant();
Ok(())
},
Err(error) => Err(error),
}
}
pub fn commit_query_error(&self, error: &QueryError) -> Result<(), AttemptLifecycleError> {
let operation = self.0.core.lock_lifecycle().failure_operation();
let outcome = RuntimeTerminalOutcome::from_query_error(error);
let terminal = match RuntimeTerminalOutcome::primary_failure_from_query_error(error, operation) {
Some(summary) => self.0.core.terminalize_for_release_with_primary_failure(outcome, summary)?,
None => self.0.core.terminalize_for_release(outcome)?,
};
self.commit_resolved_terminal(terminal)
}
pub fn commit_failure_summary(&self, summary: AttemptFailureSummary) -> Result<(), AttemptLifecycleError> {
let terminal = self
.0
.core
.terminalize_for_release_with_primary_failure(RuntimeTerminalOutcome::failed(&summary), summary)?;
self.commit_resolved_terminal(terminal)
}
}
impl Drop for AttemptOwner {
fn drop(&mut self) {
let report_ready = self.0.core.lock_lifecycle().is_ready();
if report_ready {
return;
}
if thread::panicking() {
let _ = self.commit_terminal(RuntimeTerminalOutcome::Panicked);
return;
}
let _ = match self.0.core.cancellation.check("query_engine.attempt.owner_drop") {
Err(cancellation) => self.commit_query_error(&cancellation),
Ok(()) => self.commit_terminal(RuntimeTerminalOutcome::Dropped),
};
}
}
impl fmt::Debug for AttemptOwner {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptOwner").field("attempt_id", &self.attempt_id()).finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptHandle {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptHandle").field("attempt_id", &self.attempt_id()).finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptAdmissionRejection {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("AttemptAdmissionRejection")
.field("attempt_id", &self.core.attempt_id)
.finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptFinalizer {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptFinalizer").field("attempt_id", &self.0.attempt_id).finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptAdmission {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptAdmission").field("attempt_id", &self.0.0.attempt_id).finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptFinalizerSlot {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptFinalizerSlot").finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptAdmissionBinding {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptAdmissionBinding").finish_non_exhaustive()
}
}
impl AttemptAdmissionBinding {
pub(crate) fn attempt_id(&self) -> AttemptId {
self.core.attempt_id
}
pub fn observation_handle(&self) -> RuntimeObservationHandle {
self.core.observation.handle()
}
pub fn register_seal_observer<F>(&self, observer: F)
where F: Fn(SealedRuntimeObservationSnapshot) + Send + Sync + 'static {
self.core.observation.register_seal_observer(observer);
}
pub(crate) fn claim(&self) -> Result<AttemptAdmission, AttemptLifecycleError> {
self.finalizer_slot.claim()
}
}
impl AttemptAdmissionRejection {
pub fn reject(&self, error: &QueryError) -> Result<(), AttemptLifecycleError> {
let cancellation_error = self.core.cancellation.is_cancelled().then(|| {
self.core
.cancellation
.check("query_engine.attempt.admission_rejection")
.expect_err("an effective cancellation must produce a terminal error")
});
let (outcome, summary) = if let Some(cancellation_error) = cancellation_error {
(
RuntimeTerminalOutcome::Cancelled,
RuntimeTerminalOutcome::primary_failure_from_query_error(
&cancellation_error,
AttemptFailureOperation::Admission,
),
)
} else {
let summary = if error.fact_value("reason") == Some("backend_closing") {
Some(AttemptFailureSummary::backend_closing())
} else {
RuntimeTerminalOutcome::primary_failure_from_query_error(error, AttemptFailureOperation::Admission)
};
(RuntimeTerminalOutcome::from_query_error(error), summary)
};
{
let mut lifecycle = self.core.lock_lifecycle();
if lifecycle.is_claimed() {
return Ok(());
}
lifecycle.terminalize_admission_rejection(outcome.clone(), summary, self.core.monotonic_ns())?;
}
let outcome = self.finalizer_slot.finalize_not_admitted(outcome)?;
let _ = self.core.seal_observation(outcome).deliver();
Ok(())
}
}
impl AttemptFinalizerSlot {
fn new(finalizer: AttemptFinalizer) -> Self {
Self(Arc::new(Mutex::new(Some(finalizer))))
}
fn take(&self) -> Result<AttemptFinalizer, AttemptLifecycleError> {
self.0
.lock()
.unwrap_or_else(sync::PoisonError::into_inner)
.take()
.ok_or(AttemptLifecycleError::FinalizationUnavailable)
}
fn claim(&self) -> Result<AttemptAdmission, AttemptLifecycleError> {
let mut slot = self.0.lock().unwrap_or_else(sync::PoisonError::into_inner);
let core = &slot.as_ref().ok_or(AttemptLifecycleError::AdmissionAlreadyClaimed)?.0;
core.lock_lifecycle().admission_requested(core.monotonic_ns())?;
Ok(AttemptAdmission(slot.take().expect("the claimed finalizer is present")))
}
pub(crate) fn finalize_not_admitted(
&self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
self.take()?.finalize_not_admitted(fallback)
}
}
impl AttemptFinalizer {
pub(crate) fn monotonic_ns(&self) -> u64 {
self.0.monotonic_ns()
}
pub(crate) fn record_primary_failure(&self, summary: AttemptFailureSummary) {
self.0.lock_lifecycle().primary_failure(summary);
}
pub(crate) fn terminalize_for_release(
&self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
Ok(self.0.canonical_terminal_outcome(fallback))
}
fn finalize_not_admitted(
self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
let mut lifecycle = self.0.lock_lifecycle();
let outcome = match lifecycle.terminal_outcome() {
Some(outcome) => outcome.clone(),
None => {
lifecycle.terminalize(fallback, self.0.monotonic_ns())?;
lifecycle.terminal_outcome().cloned().expect("terminal outcome was recorded")
},
};
lifecycle.finalize_not_admitted(self.0.monotonic_ns())?;
Ok(outcome)
}
pub(crate) fn finalize_admitted(self, commit: AttemptTerminalCommit) -> Result<(), AttemptLifecycleError> {
let mut lifecycle = self.0.lock_lifecycle();
lifecycle.terminal_commit(commit, self.0.monotonic_ns())?;
Ok(())
}
}
impl AttemptAdmission {
pub(crate) fn monotonic_ns(&self) -> u64 {
self.0.monotonic_ns()
}
pub(crate) fn report_publisher(&self) -> AttemptReportPublisher {
AttemptReportPublisher(Arc::clone(&self.0.0))
}
pub(crate) fn record_primary_failure(&self, summary: AttemptFailureSummary) {
self.0.record_primary_failure(summary);
}
pub(crate) fn record_admitted(
&self,
fact: AttemptAdmissionFact,
wait: Option<AttemptAdmissionWaitFact>,
) -> Result<(), AttemptLifecycleError> {
let mut lifecycle = self.0.0.lock_lifecycle();
lifecycle.admitted(fact, self.0.monotonic_ns())?;
match wait {
Some(wait) => lifecycle.admission_wait(wait),
None => Ok(()),
}
}
pub(crate) fn is_admitted(&self) -> bool {
self.0.0.lock_lifecycle().admission_fact().is_some()
}
pub(crate) fn bind_grant_release(&self, release: Arc<dyn AdmittedGrantRelease>) -> bool {
let mut state = self.0.0.shared.lock();
if state.lifecycle.terminal_outcome().is_some() {
return true;
}
state.admitted_release = Some(release);
false
}
pub(crate) fn terminalize_for_release(
&self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
self.0.terminalize_for_release(fallback)
}
pub(crate) fn finish_not_admitted(
self,
fallback: RuntimeTerminalOutcome,
) -> Result<RuntimeTerminalOutcome, AttemptLifecycleError> {
self.0.finalize_not_admitted(fallback)
}
pub(crate) fn finish_admitted(self, commit: AttemptTerminalCommit) -> Result<(), AttemptLifecycleError> {
self.0.finalize_admitted(commit)
}
}
impl AttemptHandle {
pub fn attempt_id(&self) -> AttemptId {
self.0.attempt_id
}
pub(crate) fn observation(&self) -> RuntimeObservationHandle {
self.0.observation.handle()
}
pub fn cancellation(&self) -> AttemptCancellation {
self.0.cancellation.clone()
}
pub fn is_terminal(&self) -> bool {
self.0.lock_lifecycle().terminal_outcome().is_some()
}
pub fn disposition(&self) -> Option<AttemptDisposition> {
self.0.lock_lifecycle().recorded_disposition()
}
pub fn record_planning_started(&self) -> Result<(), AttemptLifecycleError> {
self.0.lock_lifecycle().planning_started(self.0.monotonic_ns())
}
pub fn record_planning_finished(&self) -> Result<(), AttemptLifecycleError> {
self.0.lock_lifecycle().planning_finished(self.0.monotonic_ns())
}
pub fn set_disposition(&self, disposition: AttemptDisposition) -> Result<(), AttemptLifecycleError> {
self.0.lock_lifecycle().disposition(disposition)
}
pub fn record_composed_schedule_projection(
&self,
projection: AttemptComposedScheduleProjection,
) -> Result<(), AttemptLifecycleError> {
if projection.attempt_id != self.0.attempt_id {
return Err(AttemptLifecycleError::InvalidOrder {
boundary: "composed_schedule",
reason: "attempt_id_mismatch",
});
}
self.0.lock_lifecycle().composed_schedule(projection)
}
pub fn record_physical_execution_started(&self) -> Result<(), AttemptLifecycleError> {
self.0.lock_lifecycle().physical(self.0.monotonic_ns())
}
pub fn record_gpu_execution_started(&self) -> Result<(), AttemptLifecycleError> {
self.0.lock_lifecycle().gpu(self.0.monotonic_ns())
}
pub fn record_native_failure(&self, error: &QueryError) {
let operation = self.0.lock_lifecycle().failure_operation();
if let Some(summary) = RuntimeTerminalOutcome::primary_failure_from_query_error(error, operation) {
self.0.lock_lifecycle().primary_failure(summary);
}
}
#[cfg(test)]
pub(crate) fn record_cleanup_failure(&self, phase: CleanupFailurePhase, cleanup_error: &QueryError) {
let summary = CleanupFailureSummary::from_native_error(phase, cleanup_error);
let observation = self.0.observation.handle();
observation.record_attempt_cleanup_failure(summary.clone());
observation.record(|| {
RuntimeObservationPayload::CleanupFailure(Box::new(RuntimeCleanupFailureObservation { summary }))
});
}
}
impl AttemptCompletion {
pub fn is_ready(&self) -> bool {
self.shared.lock().completion.report_visible
}
pub fn try_report(&self) -> Option<Arc<QueryAttemptReport>> {
self.shared.lock().completion.visible_report()
}
pub fn wait_timeout(&self, timeout: Duration) -> Option<Arc<QueryAttemptReport>> {
let state = self.shared.lock();
let (state, _) = self
.shared
.changed
.wait_timeout_while(state, timeout, |state| !state.completion.report_visible)
.unwrap_or_else(sync::PoisonError::into_inner);
state.completion.visible_report()
}
}
impl Future for AttemptCompletion {
type Output = Arc<QueryAttemptReport>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut state = self.shared.lock();
let completion = &mut state.completion;
if let Some(report) = completion.visible_report() {
return Poll::Ready(report);
}
if !completion.wakers.iter().any(|waker| waker.will_wake(cx.waker())) {
completion.wakers.push(cx.waker().clone());
}
Poll::Pending
}
}
impl Drop for AttemptCompletion {
fn drop(&mut self) {
let mut state = self.shared.lock();
state.completion.receivers = state.completion.receivers.saturating_sub(1);
}
}
impl fmt::Debug for AttemptCompletion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptCompletion").field("ready", &self.is_ready()).finish_non_exhaustive()
}
}
impl fmt::Debug for AttemptCompletionFactory {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.debug_struct("AttemptCompletionFactory").finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use std::sync::mpsc;
use query_planning::error::{AttemptFailureCode, QueryError, QueryErrorCode};
use super::*;
use crate::{
observability::{
AttemptDeviceHealth, AttemptDeviceHealthStatus, AttemptFailureFactKey, AttemptFailureFactValue,
AttemptFailureOrigin, AttemptFailureStatus, AttemptFaultIsolation, AttemptFinalDomainUsage,
AttemptHealthTransition, AttemptNativeFault, AttemptNativeFaultEvidence, AttemptNativeFaultKind,
AttemptNativeStatus, AttemptTeardownHealth, DeterministicRuntimeObservationClock, PlanExecutionId,
QueryBoundaryKind, RuntimeObservationConfig, RuntimeObservationRecord, SourceReadFact,
write_runtime_observation_jsonl,
},
runtime::BackendLifecycle,
};
fn test_begin(
observation: RuntimeObservationConfig,
queue: Option<Arc<AttemptCompletionQueue>>,
) -> (AttemptBegin, Arc<DeterministicRuntimeObservationClock>, Arc<AttemptBackendCounters>) {
let lifecycle = BackendLifecycle::new();
let permit = lifecycle.try_begin_observation().expect("test permit");
let counters = Arc::new(AttemptBackendCounters::default());
let clock = Arc::new(DeterministicRuntimeObservationClock::new(Some(42)));
let begin = AttemptOwner::begin_with_clock(
BeginAttemptRequest { observation, ..BeginAttemptRequest::default() },
permit,
Arc::clone(&counters),
queue,
Arc::clone(&clock) as _,
);
(begin, clock, counters)
}
fn native_disposition(begin: &AttemptBegin) {
let handle = begin.owner.handle();
handle.record_planning_started().unwrap();
handle.record_planning_finished().unwrap();
handle.set_disposition(AttemptDisposition::Native).unwrap();
}
fn seal_after_cleanup(begin: &AttemptBegin, publisher: &AttemptReportPublisher, fallback: RuntimeTerminalOutcome) {
let outcome = begin.owner.0.core.canonical_terminal_outcome(fallback);
let _ = publisher.seal(outcome).deliver();
}
fn claim_admitted(begin: &AttemptBegin, fact: AttemptAdmissionFact) -> AttemptAdmission {
let admission = begin.owner.admission_binding().claim().unwrap();
admission.record_admitted(fact, None).unwrap();
admission
}
#[test]
fn non_admitted_commit_publishes_immediately_in_order() {
let (begin, clock, counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
native_disposition(&begin);
clock.set_monotonic_ns(10);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
let report = completion.wait_timeout(Duration::from_secs(1)).expect("report published");
assert!(matches!(report.outcome, RuntimeTerminalOutcome::Succeeded));
assert_eq!(report.disposition, AttemptDisposition::Native);
assert_eq!(report.cleanup_disposition, AttemptCleanupDisposition::NotRequired);
assert_eq!(report.capacity_disposition, AttemptCapacityDisposition::NotAdmitted);
assert_eq!(report.final_domain_usage, None, "unadmitted attempts have no final domain sample");
assert_eq!(report.health_transition, None, "unadmitted attempts have no release health transition");
assert_eq!(report.timestamps.cleanup_complete_ns, None);
assert_eq!(report.timestamps.report_ready_ns, Some(10));
assert_eq!(report.timestamps.outcome_terminal_ns, 10);
assert_eq!(counters.snapshot().reports_ready, 1);
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
let embedded = snapshot.attempt_report().expect("attempt report embedded");
assert_eq!(embedded, report.as_ref());
assert!(Arc::ptr_eq(
snapshot.footer().attempt_report.as_ref().expect("attempt report allocation embedded"),
&report
));
let mut jsonl = Vec::new();
write_runtime_observation_jsonl(&snapshot, &mut jsonl).expect("attempt JSONL exports");
let exported_report = std::str::from_utf8(&jsonl)
.expect("attempt JSONL is UTF-8")
.lines()
.map(|line| serde_json::from_str::<RuntimeObservationRecord>(line).expect("attempt JSONL record parses"))
.find_map(|record| match record {
RuntimeObservationRecord::Footer(footer) => footer.attempt_report,
_ => None,
})
.expect("JSONL footer retains the attempt report");
assert_eq!(exported_report.as_ref(), report.as_ref());
}
#[test]
fn sealed_report_sink_receives_the_exact_report_before_completion_visibility() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let factory = begin.completion.clone();
let completion_for_sink = factory.clone();
let completion = factory.completion();
let delivered = Arc::new(Mutex::new(Vec::new()));
let delivered_for_sink = Arc::clone(&delivered);
let observed_before_completion = Arc::new(std::sync::atomic::AtomicBool::new(false));
let observed_before_completion_for_sink = Arc::clone(&observed_before_completion);
begin.owner.register_sealed_report_sink(move |report| {
observed_before_completion_for_sink
.store(completion_for_sink.try_report().is_none(), std::sync::atomic::Ordering::Release);
delivered_for_sink.lock().unwrap().push(report);
});
native_disposition(&begin);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
let report = completion.try_report().expect("completion is published after sink delivery");
let delivered = delivered.lock().unwrap();
assert_eq!(delivered.len(), 1);
assert!(Arc::ptr_eq(&delivered[0], &report));
assert!(observed_before_completion.load(std::sync::atomic::Ordering::Acquire));
}
#[test]
fn sealed_report_sink_can_write_back_to_its_attempt_observation() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
let observation = begin.owner.observation_for_test();
begin.owner.register_sealed_report_sink(move |_report| {
observation.record_source_read(&PlanExecutionId::new("late-plan"), SourceReadFact::InputBatch { rows: 1 });
});
native_disposition(&begin);
let (sealed, seal_finished) = mpsc::channel();
let owner = begin.owner;
thread::spawn(move || sealed.send(owner.commit_terminal(RuntimeTerminalOutcome::Succeeded)));
seal_finished
.recv_timeout(Duration::from_secs(5))
.expect("the seal finishes while its report sink writes to the same observation")
.unwrap();
assert!(completion.try_report().is_some());
}
#[test]
fn seal_uses_the_attempt_terminal_outcome_for_footer_report_and_boundary() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
native_disposition(&begin);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Cancelled).unwrap();
let report = completion.wait_timeout(Duration::from_secs(1)).expect("report published");
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
assert_eq!(report.outcome, RuntimeTerminalOutcome::Cancelled);
assert_eq!(snapshot.footer().terminal, Some(RuntimeTerminalOutcome::Cancelled));
assert_eq!(snapshot.attempt_report().expect("attempt report embedded"), report.as_ref());
assert!(snapshot.events().iter().any(|event| {
matches!(event.payload, RuntimeObservationPayload::QueryBoundary { boundary: QueryBoundaryKind::Cancelled })
}));
}
#[test]
fn admitted_commit_defers_until_post_cleanup_seal() {
let (begin, clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
native_disposition(&begin);
let handle = begin.owner.handle();
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 3, admission_wait_ns: 1, device_ordinal: 1, grant_bytes: 1024 },
);
let publisher = admission.report_publisher();
handle.record_physical_execution_started().unwrap();
handle.record_gpu_execution_started().unwrap();
clock.set_monotonic_ns(20);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
assert!(!completion.is_ready(), "admitted attempt must wait for the post-cleanup seal");
clock.set_monotonic_ns(30);
let final_domain_usage = AttemptFinalDomainUsage::from(cudf::QueryMemoryDomainUsage {
domain_id: 101,
active: false,
active_members: 0,
ceiling_bytes: 1024,
allocation_limit_bytes: 768,
current_bytes: 0,
peak_bytes: 512,
total_bytes: 1024,
current_aligned_bytes: 0,
peak_aligned_bytes: 640,
total_allocations: 9,
current_allocations: 0,
peak_allocations: 4,
failed_allocation_count: 2,
largest_failed_allocation_bytes: 64,
});
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::Released,
Some(final_domain_usage),
AttemptHealthTransition::HealthyReuse,
))
.unwrap();
seal_after_cleanup(&begin, &publisher, RuntimeTerminalOutcome::Succeeded);
let report = completion.wait_timeout(Duration::from_secs(1)).expect("report published after seal");
assert_eq!(report.timestamps.outcome_terminal_ns, 20);
assert_eq!(report.timestamps.cleanup_complete_ns, Some(30));
assert_eq!(report.timestamps.report_ready_ns, Some(30));
assert_eq!(report.device_ordinal, Some(1));
assert_eq!(report.cleanup_disposition, AttemptCleanupDisposition::Completed);
assert_eq!(report.capacity_disposition, AttemptCapacityDisposition::Released);
assert_eq!(report.final_domain_usage, Some(final_domain_usage), "report preserves every final sample scalar");
assert_eq!(report.health_transition, Some(AttemptHealthTransition::HealthyReuse));
assert_eq!(report.admission.as_ref().map(|fact| fact.grant_bytes), Some(1024));
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
assert_eq!(snapshot.attempt_report().expect("attempt report embedded"), report.as_ref());
}
#[test]
fn admitted_terminal_commit_projects_typed_native_fault_evidence() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
native_disposition(&begin);
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 3, admission_wait_ns: 1, device_ordinal: 1, grant_bytes: 1024 },
);
let publisher = admission.report_publisher();
let native_fault_evidence = AttemptNativeFaultEvidence {
isolation: AttemptFaultIsolation::DeviceLocal,
teardown_health: AttemptTeardownHealth::Completed,
device_health: Some(AttemptDeviceHealth {
status: AttemptDeviceHealthStatus::Unhealthy,
fault_count: 1,
rejected_operation_count: 0,
quarantined_teardown_count: 0,
}),
first_fault: Some(AttemptNativeFault {
kind: AttemptNativeFaultKind::FatalDeviceOperation,
status: Some(AttemptNativeStatus::Cudf(u32::MAX)),
}),
};
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
admission
.finish_admitted(
AttemptTerminalCommit::new(
AttemptCapacityDisposition::RetainedQuarantine,
None,
AttemptHealthTransition::DeviceQuarantined,
)
.with_native_fault_evidence(native_fault_evidence),
)
.unwrap();
seal_after_cleanup(&begin, &publisher, RuntimeTerminalOutcome::Succeeded);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.capacity_disposition, AttemptCapacityDisposition::RetainedQuarantine);
assert_eq!(report.health_transition, Some(AttemptHealthTransition::DeviceQuarantined));
assert_eq!(report.native_fault_evidence, Some(native_fault_evidence));
}
#[test]
fn terminal_commit_projects_actual_cleanup_and_capacity_before_seal() {
let (begin, clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
native_disposition(&begin);
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 3, admission_wait_ns: 1, device_ordinal: 1, grant_bytes: 1024 },
);
let publisher = admission.report_publisher();
clock.set_monotonic_ns(20);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
clock.set_monotonic_ns(30);
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::RetainedQuarantine,
None,
AttemptHealthTransition::BackendUnhealthy,
))
.unwrap();
assert!(
matches!(begin.owner.admission_binding().claim(), Err(AttemptLifecycleError::AdmissionAlreadyClaimed)),
"the admission right is linear and cannot be claimed a second time"
);
seal_after_cleanup(&begin, &publisher, RuntimeTerminalOutcome::Succeeded);
let report = completion.wait_timeout(Duration::from_secs(1)).expect("report");
assert!(matches!(report.outcome, RuntimeTerminalOutcome::Succeeded));
assert_eq!(report.cleanup_disposition, AttemptCleanupDisposition::Completed);
assert_eq!(report.cleanup_failure_count, 0);
assert!(report.cleanup_failure_count_complete);
assert!(report.first_cleanup_failure.is_none());
assert_eq!(report.capacity_disposition, AttemptCapacityDisposition::RetainedQuarantine);
assert_eq!(report.final_domain_usage, None, "unavailable sample is never replaced with all-zero usage");
assert_eq!(report.health_transition, Some(AttemptHealthTransition::BackendUnhealthy));
assert_eq!(report.timestamps.cleanup_complete_ns, Some(30));
assert_eq!(report.timestamps.report_ready_ns, Some(30));
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
assert_eq!(snapshot.attempt_report().expect("attempt report embedded"), report.as_ref());
}
#[test]
fn double_terminalization_is_exactly_once() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
begin.owner.commit_terminal(RuntimeTerminalOutcome::Dropped).unwrap();
assert_eq!(
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded),
Err(AttemptLifecycleError::DoubleTerminalization)
);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert!(matches!(report.outcome, RuntimeTerminalOutcome::Dropped));
}
#[test]
fn dropping_a_cancelled_owner_commits_the_cancellation() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
begin.owner.cancellation().cancel();
drop(begin.owner);
let report = completion.wait_timeout(Duration::from_secs(1)).expect("drop publishes the report");
assert_eq!(report.outcome, RuntimeTerminalOutcome::Cancelled);
}
#[test]
fn owner_drop_backstop_never_loses_the_report() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let completion = begin.completion.completion();
drop(begin.owner);
let report = completion.wait_timeout(Duration::from_secs(1)).expect("drop publishes the report");
assert!(matches!(report.outcome, RuntimeTerminalOutcome::Dropped));
}
#[test]
fn fixed_summary_survives_disabled_and_zero_limit_diagnostics() {
for observation in [RuntimeObservationConfig::disabled(), RuntimeObservationConfig::bounded(0, 0)] {
let (begin, _clock, _counters) = test_begin(observation, None);
let completion = begin.completion.completion();
native_disposition(&begin);
begin
.owner
.commit_terminal(RuntimeTerminalOutcome::Failed {
error_code: AttemptFailureCode::Query(QueryErrorCode::Internal),
error_status: AttemptFailureStatus::Permanent,
})
.unwrap();
let report = completion.wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.disposition, AttemptDisposition::Native);
assert!(matches!(report.outcome, RuntimeTerminalOutcome::Failed { .. }));
assert!(report.timestamps.report_ready_ns.is_some());
assert_eq!(report.cleanup_disposition, AttemptCleanupDisposition::NotRequired);
}
}
#[test]
fn receiver_abandonment_still_publishes_and_overflow_is_counted() {
let queue = Arc::new(AttemptCompletionQueue::new(1).expect("queue"));
let (begin, _clock, counters) =
test_begin(RuntimeObservationConfig::native_execution(), Some(Arc::clone(&queue)));
drop(begin.completion.completion());
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
assert_eq!(counters.snapshot().reports_ready, 1);
assert_eq!(counters.snapshot().completion_queue_pushed, 1);
assert_eq!(counters.snapshot().completion_queue_overflowed, 0);
let drained = queue.drain(8);
assert_eq!(drained.len(), 1);
assert!(matches!(drained[0].outcome, RuntimeTerminalOutcome::Succeeded));
let (begin2, _clock2, counters2) =
test_begin(RuntimeObservationConfig::native_execution(), Some(Arc::clone(&queue)));
drop(begin2.completion.completion());
begin2.owner.commit_terminal(RuntimeTerminalOutcome::Dropped).unwrap();
assert_eq!(counters2.snapshot().completion_queue_pushed, 1);
let (begin3, _clock3, counters3) =
test_begin(RuntimeObservationConfig::native_execution(), Some(Arc::clone(&queue)));
drop(begin3.completion.completion());
begin3.owner.commit_terminal(RuntimeTerminalOutcome::Dropped).unwrap();
assert_eq!(counters3.snapshot().completion_queue_overflowed, 1);
assert_eq!(queue.drain(8).len(), 1);
}
#[test]
fn contended_completion_push_blocks_for_capacity_instead_of_reporting_overflow() {
let queue = Arc::new(AttemptCompletionQueue::new(4).expect("queue"));
let (begin, _clock, _counters) =
test_begin(RuntimeObservationConfig::native_execution(), Some(Arc::clone(&queue)));
drop(begin.completion.completion());
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
let report = queue.drain(8).pop().expect("abandoned report");
let guard = queue.hold_lock_for_test();
let barrier = sync::Barrier::new(2);
let (pushed_tx, pushed_rx) = sync::mpsc::channel();
std::thread::scope(|scope| {
scope.spawn(|| {
barrier.wait();
pushed_tx.send(queue.try_push(Arc::clone(&report))).expect("push result");
});
barrier.wait();
std::thread::sleep(Duration::from_millis(20));
assert!(pushed_rx.try_recv().is_err(), "contended push must block, not fail fast");
drop(guard);
assert!(pushed_rx.recv().expect("push result after release"));
});
assert_eq!(queue.drain(8).len(), 1);
}
#[test]
fn held_receivers_do_not_route_to_the_abandoned_queue() {
let queue = Arc::new(AttemptCompletionQueue::new(4).expect("queue"));
let (begin, _clock, counters) =
test_begin(RuntimeObservationConfig::native_execution(), Some(Arc::clone(&queue)));
let _held = begin.completion.completion();
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
assert_eq!(counters.snapshot().completion_queue_pushed, 0);
assert!(queue.drain(4).is_empty());
assert!(_held.is_ready());
}
#[test]
fn cleanup_failures_are_counted_exactly_without_replacing_the_primary_outcome() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
native_disposition(&begin);
let handle = begin.owner.handle();
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 1, admission_wait_ns: 0, device_ordinal: 0, grant_bytes: 1 },
);
let publisher = admission.report_publisher();
let primary_error =
QueryError::new(QueryErrorCode::CudfTemporaryFailure, "test.primary", "primary native failure");
begin.owner.commit_query_error(&primary_error).unwrap();
let cleanup_error = QueryError::new(QueryErrorCode::Internal, "test.cleanup", "injected cleanup failure");
handle.record_cleanup_failure(CleanupFailurePhase::QueryServiceCleanup, &cleanup_error);
handle.record_cleanup_failure(CleanupFailurePhase::QueryServiceCleanup, &cleanup_error);
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::Released,
None,
AttemptHealthTransition::HealthyReuse,
))
.unwrap();
seal_after_cleanup(
&begin,
&publisher,
RuntimeTerminalOutcome::Failed {
error_code: AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure),
error_status: AttemptFailureStatus::Temporary,
},
);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.cleanup_failure_count, 2);
assert!(report.cleanup_failure_count_complete);
assert_eq!(report.cleanup_disposition, AttemptCleanupDisposition::CompletedWithFailures);
assert!(matches!(
report.outcome,
RuntimeTerminalOutcome::Failed { ref error_code, .. }
if *error_code == AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure)
));
let primary = report.primary_failure.as_ref().expect("primary failure summary");
assert_eq!(primary.code(), AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure));
assert!(primary.text().is_none(), "native error text must not enter the stable report");
let first_cleanup = report.first_cleanup_failure.as_ref().expect("first cleanup failure summary");
assert_eq!(first_cleanup.phase(), CleanupFailurePhase::QueryServiceCleanup);
assert_eq!(first_cleanup.failure().code(), AttemptFailureCode::Query(QueryErrorCode::Internal));
assert!(!first_cleanup.complete(), "the first retained summary is incomplete after a later cleanup failure");
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
let cleanup_events = snapshot
.events()
.iter()
.filter(|event| matches!(event.payload, RuntimeObservationPayload::CleanupFailure(_)))
.count();
assert_eq!(cleanup_events, 2);
}
#[test]
fn borrowed_primary_capture_preserves_the_returned_error_source_chain() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
native_disposition(&begin);
let error = QueryError::new(QueryErrorCode::CudfTemporaryFailure, "test.primary", "native failure")
.with_source(std::io::Error::other("original source cause"));
assert_eq!(error.source_error().map(ToString::to_string).as_deref(), Some("original source cause"));
begin.owner.commit_query_error(&error).unwrap();
assert_eq!(error.source_error().map(ToString::to_string).as_deref(), Some("original source cause"));
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
let summary = report.primary_failure.as_ref().expect("borrowed native summary");
assert_eq!(summary.code(), AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure));
assert_eq!(summary.status(), AttemptFailureStatus::Temporary);
assert!(summary.text().is_none(), "the returned error, not the report, retains native message text");
}
#[test]
fn borrowed_primary_capture_wins_when_admitted_cleanup_finalizes_before_outer_error_handling() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
native_disposition(&begin);
let handle = begin.owner.handle();
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 1, admission_wait_ns: 0, device_ordinal: 0, grant_bytes: 1 },
);
let publisher = admission.report_publisher();
let error = QueryError::new(
QueryErrorCode::CudfTemporaryFailure,
"test.native_admission_execute",
"application-specific native failure text must remain on the returned error",
)
.with_fact("reason", "deadline_expired")
.with_source(std::io::Error::other("original source cause"));
handle.record_native_failure(&error);
let terminal = admission.terminalize_for_release(RuntimeTerminalOutcome::Dropped).unwrap();
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::Released,
None,
AttemptHealthTransition::HealthyReuse,
))
.unwrap();
seal_after_cleanup(&begin, &publisher, terminal);
assert_eq!(error.source_error().map(ToString::to_string).as_deref(), Some("original source cause"));
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert!(matches!(
report.outcome,
RuntimeTerminalOutcome::Failed {
error_code: AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure),
error_status: AttemptFailureStatus::Temporary,
}
));
let summary = report.primary_failure.as_ref().expect("captured native primary summary");
assert_eq!(summary.code(), AttemptFailureCode::Query(QueryErrorCode::CudfTemporaryFailure));
assert_eq!(summary.status(), AttemptFailureStatus::Temporary);
assert_eq!(summary.operation(), AttemptFailureOperation::Execution);
assert_eq!(summary.facts().len(), 1);
assert_eq!(summary.facts()[0].key(), AttemptFailureFactKey::Reason);
assert_eq!(summary.facts()[0].value(), AttemptFailureFactValue::DeadlineExpired);
assert!(summary.text().is_none());
}
#[test]
fn execution_failure_with_plan_in_operation_seals_as_execution() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
native_disposition(&begin);
let handle = begin.owner.handle();
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 1, admission_wait_ns: 0, device_ordinal: 0, grant_bytes: 1 },
);
let publisher = admission.report_publisher();
let error = QueryError::new(
QueryErrorCode::CudfTemporaryFailure,
"query_engine.exec.execute_query_plan",
"execution failure",
);
handle.record_native_failure(&error);
let terminal = admission.terminalize_for_release(RuntimeTerminalOutcome::Dropped).unwrap();
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::Released,
None,
AttemptHealthTransition::HealthyReuse,
))
.unwrap();
seal_after_cleanup(&begin, &publisher, terminal);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
let summary = report.primary_failure.as_ref().expect("captured native primary summary");
assert_eq!(summary.operation(), AttemptFailureOperation::Execution);
}
#[test]
fn cleanup_facts_survive_a_full_timeline_ring() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::bounded(0, 0), None);
native_disposition(&begin);
let handle = begin.owner.handle();
let admission = claim_admitted(
&begin,
AttemptAdmissionFact { admission_sequence: 1, admission_wait_ns: 0, device_ordinal: 0, grant_bytes: 1 },
);
let publisher = admission.report_publisher();
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
let cleanup_error = QueryError::new(QueryErrorCode::Internal, "test.cleanup", "ring-full cleanup failure");
handle.record_cleanup_failure(CleanupFailurePhase::QueryServiceCleanup, &cleanup_error);
admission
.finish_admitted(AttemptTerminalCommit::new(
AttemptCapacityDisposition::Released,
None,
AttemptHealthTransition::HealthyReuse,
))
.unwrap();
seal_after_cleanup(&begin, &publisher, RuntimeTerminalOutcome::Succeeded);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.cleanup_failure_count, 1);
assert!(report.cleanup_failure_count_complete);
assert_eq!(
report.first_cleanup_failure.as_ref().map(CleanupFailureSummary::phase),
Some(CleanupFailurePhase::QueryServiceCleanup)
);
let snapshot = begin.owner.sealed_snapshot_for_test().expect("sealed");
assert!(
snapshot
.events()
.iter()
.all(|event| !matches!(event.payload, RuntimeObservationPayload::CleanupFailure(_)))
);
}
#[test]
fn deadline_expired_cancelled_error_retains_its_bounded_reason() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let error = QueryError::new(QueryErrorCode::Cancelled, "test.deadline", "deadline elapsed")
.with_fact("reason", "deadline_expired")
.with_fact("cancellation_requested", true);
begin.owner.commit_query_error(&error).unwrap();
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.outcome, RuntimeTerminalOutcome::Cancelled);
let summary = report.primary_failure.as_ref().expect("deadline summary");
assert_eq!(summary.code(), AttemptFailureCode::Query(QueryErrorCode::Cancelled));
assert_eq!(summary.origin(), AttemptFailureOrigin::Native);
assert_eq!(summary.facts().len(), 1);
assert_eq!(summary.facts()[0].value(), AttemptFailureFactValue::DeadlineExpired);
}
#[test]
fn caller_and_generic_cancellation_keep_the_control_summary() {
for error in [
QueryError::new(QueryErrorCode::Cancelled, "test.caller_cancelled", "caller cancelled")
.with_fact("reason", "caller_cancelled"),
QueryError::new(QueryErrorCode::Cancelled, "test.generic_cancelled", "cancelled"),
] {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
begin.owner.commit_query_error(&error).unwrap();
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert_eq!(report.outcome, RuntimeTerminalOutcome::Cancelled);
let summary = report.primary_failure.as_ref().expect("control cancellation summary");
assert_eq!(summary.code(), AttemptFailureCode::Query(QueryErrorCode::Cancelled));
assert_eq!(summary.origin(), AttemptFailureOrigin::AttemptControl);
assert!(summary.facts().is_empty());
}
}
#[test]
fn control_terminal_paths_publish_text_free_primary_summaries() {
for (outcome, code) in [
(RuntimeTerminalOutcome::Cancelled, AttemptFailureCode::Query(QueryErrorCode::Cancelled)),
(RuntimeTerminalOutcome::Dropped, AttemptFailureCode::Dropped),
(RuntimeTerminalOutcome::Panicked, AttemptFailureCode::Panicked),
] {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
begin.owner.commit_terminal(outcome).unwrap();
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
let summary = report.primary_failure.as_ref().expect("control summary");
assert_eq!(summary.code(), code);
assert_eq!(summary.origin(), AttemptFailureOrigin::AttemptControl);
assert_eq!(summary.status(), AttemptFailureStatus::NotApplicable);
assert!(summary.text().is_none());
}
}
#[test]
fn cancellation_projects_into_the_engine_execution_signal() {
let (begin, _clock, _counters) = test_begin(RuntimeObservationConfig::native_execution(), None);
let cancellation = begin.owner.cancellation();
assert!(!cancellation.is_cancelled());
cancellation.cancel();
assert!(cancellation.is_cancelled());
assert!(cancellation.execution_cancellation().is_cancelled());
assert!(cancellation.check("test.operation").is_err());
}
}
#[cfg(test)]
mod terminalize_race_tests {
use query_planning::error::{AttemptFailureCode, QueryErrorCode};
use super::*;
use crate::{
observability::{AttemptFailureStatus, DeterministicRuntimeObservationClock},
runtime::BackendLifecycle,
};
#[test]
fn admission_rejection_terminalized_at_the_binding_wins_over_the_wrapper_commit() {
let lifecycle = BackendLifecycle::new();
let permit = lifecycle.try_begin_observation().expect("test permit");
let counters = Arc::new(AttemptBackendCounters::default());
let clock = Arc::new(DeterministicRuntimeObservationClock::new(Some(1)));
let begin = AttemptOwner::begin_with_clock(BeginAttemptRequest::default(), permit, counters, None, clock);
let handle = begin.owner.handle();
let admission_rejection = begin.owner.admission_rejection();
handle.record_planning_started().unwrap();
handle.record_planning_finished().unwrap();
handle.set_disposition(AttemptDisposition::Native).unwrap();
admission_rejection
.reject(&QueryError::new(
QueryErrorCode::ServiceOverloaded,
"test.admission_rejection",
"injected admission rejection",
))
.unwrap();
assert_eq!(
begin.owner.commit_terminal(RuntimeTerminalOutcome::Failed {
error_code: AttemptFailureCode::DatafusionError,
error_status: AttemptFailureStatus::Permanent,
}),
Err(AttemptLifecycleError::DoubleTerminalization)
);
let report = begin.completion.completion().wait_timeout(Duration::from_secs(1)).expect("report");
assert!(matches!(
report.outcome,
RuntimeTerminalOutcome::Failed { ref error_code, .. }
if *error_code == AttemptFailureCode::Query(QueryErrorCode::ServiceOverloaded)
));
assert_eq!(report.disposition, AttemptDisposition::Native);
assert_eq!(report.timestamps.admission_requested_ns, None);
assert_eq!(report.timestamps.admitted_ns, None);
assert_eq!(report.timestamps.physical_execution_started_ns, None);
}
}
#[cfg(test)]
mod abandonment_race_tests {
use super::*;
use crate::{
observability::{DeterministicRuntimeObservationClock, RuntimeObservationConfig},
runtime::BackendLifecycle,
};
fn begin(queue: Option<Arc<AttemptCompletionQueue>>) -> AttemptBegin {
let lifecycle = BackendLifecycle::new();
let permit = lifecycle.try_begin_observation().expect("test permit");
AttemptOwner::begin_with_clock(
BeginAttemptRequest::default(),
permit,
Arc::new(AttemptBackendCounters::default()),
queue,
Arc::new(DeterministicRuntimeObservationClock::new(Some(1))),
)
}
#[test]
fn last_receiver_drop_and_publish_have_one_coherent_linearization() {
for _ in 0..64 {
let queue = Arc::new(AttemptCompletionQueue::new(4).expect("queue"));
let begin = begin(Some(Arc::clone(&queue)));
let completion = begin.completion.completion();
let (dropped_tx, dropped_rx) = std::sync::mpsc::channel::<()>();
let publisher = std::thread::spawn(move || {
dropped_rx.recv().expect("drop signal");
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
begin.owner
});
drop(completion);
dropped_tx.send(()).expect("publish signal");
let owner = publisher.join().expect("publisher joins");
assert_eq!(queue.drain(4).len(), 1);
drop(owner);
}
}
#[test]
fn clone_during_publication_is_delivery_loss_never_report_loss() {
for _ in 0..64 {
let queue = Arc::new(AttemptCompletionQueue::new(4).expect("queue"));
let begin = begin(Some(Arc::clone(&queue)));
let factory = begin.completion.clone();
let (go_tx, go_rx) = std::sync::mpsc::channel::<()>();
let cloner_factory = factory.clone();
let cloner = std::thread::spawn(move || {
go_rx.recv().expect("go");
cloner_factory.completion()
});
go_tx.send(()).expect("go");
begin.owner.commit_terminal(RuntimeTerminalOutcome::Succeeded).unwrap();
let receiver = cloner.join().expect("cloner joins");
assert!(matches!(
receiver.wait_timeout(Duration::from_secs(1)).map(|report| report.outcome.clone()),
Some(RuntimeTerminalOutcome::Succeeded)
));
drop(receiver);
}
}
#[test]
fn deadline_expiry_is_a_distinct_typed_cancellation() {
let lifecycle = BackendLifecycle::new();
let permit = lifecycle.try_begin_observation().expect("test permit");
let begin = AttemptOwner::begin_with_clock(
BeginAttemptRequest {
deadline: Some(Instant::now() - Duration::from_millis(1)),
observation: RuntimeObservationConfig::native_execution(),
..BeginAttemptRequest::default()
},
permit,
Arc::new(AttemptBackendCounters::default()),
None,
Arc::new(DeterministicRuntimeObservationClock::new(Some(1))),
);
let cancellation = begin.owner.cancellation();
assert!(cancellation.is_expired());
let execution_cancellation = cancellation.execution_cancellation();
assert!(execution_cancellation.is_expired(), "native execution must retain the attempt deadline");
assert_eq!(execution_cancellation.deadline(), cancellation.deadline());
let error = cancellation.check("test.deadline").unwrap_err();
assert_eq!(error.fact_value("reason"), Some("deadline_expired"));
assert_eq!(error.fact_value("cancellation_requested"), Some("true"));
let execution_error = execution_cancellation.check("test.native_deadline").unwrap_err();
assert_eq!(execution_error.fact_value("reason"), Some("deadline_expired"));
assert!(cancellation.is_cancelled(), "expiry is an effective cancellation at native safe boundaries");
}
}