use std::fmt;
use query_planning::correlation::{QueryId, TraceId};
use serde::{Deserialize, Serialize};
use super::attempt_report::{CleanupFailureSummary, QueryAttemptReport, RuntimeTerminalOutcome};
use crate::observability::{RuntimeTaskId, TaskAttemptId};
pub const RUNTIME_OBSERVATION_JSONL_SCHEMA: &str = "query_engine.runtime_observation";
macro_rules! string_id {
($name:ident, $doc:literal) => {
#[doc = $doc]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct $name(String);
impl $name {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<String> for $name {
fn from(value: String) -> Self {
Self::new(value)
}
}
impl From<&str> for $name {
fn from(value: &str) -> Self {
Self::new(value)
}
}
impl fmt::Display for $name {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
};
}
string_id!(PlanExecutionId, "Identity for one invocation of a native plan.");
string_id!(RuntimePlanNodeId, "Plan-node identity scoped to one plan execution.");
string_id!(RuntimeReservationId, "Reservation identity scoped to one plan execution.");
string_id!(RuntimeResourceId, "Resident-resource identity scoped to one plan execution.");
string_id!(RuntimeJobId, "Executor-job identity scoped to one query.");
string_id!(RuntimeWorkerId, "Worker identity scoped to one query.");
string_id!(RuntimePipelineEdgeId, "Compiled-pipeline edge identity scoped to one plan execution.");
string_id!(RuntimeBarrierId, "Compiled pipeline-barrier identity scoped to one plan execution.");
string_id!(RuntimeSinkId, "Compiled pipeline-sink identity scoped to one plan execution.");
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct AdmissionRequestId(u64);
impl AdmissionRequestId {
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn get(self) -> u64 {
self.0
}
}
impl fmt::Display for AdmissionRequestId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(formatter)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RuntimeSourceLocationId(String);
impl RuntimeSourceLocationId {
pub(crate) fn from_keyed_digest(value: String) -> Self {
Self(value)
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for RuntimeSourceLocationId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ObservationSequence(u64);
impl ObservationSequence {
pub(crate) const fn new(value: u64) -> Self {
Self(value)
}
pub const fn get(self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RuntimeSpanId(u64);
impl RuntimeSpanId {
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn get(self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeObservationLimits {
pub max_retained_records: u64,
pub max_retained_bytes: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum RuntimeClockDomain {
HostMonotonic,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeObservationManifest {
pub schema: String,
pub query_id: QueryId,
pub trace_id: Option<TraceId>,
pub unix_epoch_ns: Option<u64>,
pub(crate) clock_domain: RuntimeClockDomain,
pub(crate) limits: RuntimeObservationLimits,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PlanNodeRow {
pub plan_execution_id: PlanExecutionId,
pub node_id: RuntimePlanNodeId,
pub operator_kind: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PlanEdgeRow {
pub plan_execution_id: PlanExecutionId,
pub from_node_id: RuntimePlanNodeId,
pub to_node_id: RuntimePlanNodeId,
pub input_ordinal: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TaskDefinitionRow {
pub plan_execution_id: PlanExecutionId,
pub task_id: RuntimeTaskId,
pub plan_node_id: Option<RuntimePlanNodeId>,
pub task_kind: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct CompiledEdgeRow {
pub plan_execution_id: PlanExecutionId,
pub edge_id: RuntimePipelineEdgeId,
pub from_task_id: RuntimeTaskId,
pub to_task_id: RuntimeTaskId,
pub edge_kind: String,
pub resource_ids: Vec<RuntimeResourceId>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct BarrierDefinitionRow {
pub plan_execution_id: PlanExecutionId,
pub barrier_id: RuntimeBarrierId,
pub barrier_kind: String,
pub upstream_task_ids: Vec<RuntimeTaskId>,
pub downstream_task_ids: Vec<RuntimeTaskId>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SinkDefinitionRow {
pub plan_execution_id: PlanExecutionId,
pub sink_id: RuntimeSinkId,
pub sink_kind: String,
pub input_task_id: RuntimeTaskId,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct JobDefinitionRow {
pub(crate) plan_execution_id: Option<PlanExecutionId>,
pub(crate) job_id: RuntimeJobId,
pub(crate) job_kind: String,
pub(crate) device_ordinal: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct WorkerDefinitionRow {
pub plan_execution_id: Option<PlanExecutionId>,
pub worker_id: RuntimeWorkerId,
pub worker_kind: String,
pub device_ordinal: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeResourceDomain {
Host,
Device {
device_ordinal: u32,
},
Storage,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct RuntimeResourceRow {
pub plan_execution_id: Option<PlanExecutionId>,
pub resource_id: RuntimeResourceId,
pub resource_kind: String,
pub domain: RuntimeResourceDomain,
pub producer_task_id: Option<RuntimeTaskId>,
pub consumer_task_ids: Vec<RuntimeTaskId>,
pub lifetime: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum RuntimeTopologyRecord {
PlanNode(PlanNodeRow),
PlanEdge(PlanEdgeRow),
TaskDefinition(TaskDefinitionRow),
CompiledEdge(CompiledEdgeRow),
BarrierDefinition(BarrierDefinitionRow),
SinkDefinition(SinkDefinitionRow),
JobDefinition(JobDefinitionRow),
WorkerDefinition(WorkerDefinitionRow),
Resource(RuntimeResourceRow),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum QueryBoundaryKind {
Started,
CleanupStarted,
CleanupFinished,
Succeeded,
Failed,
Cancelled,
Dropped,
Panicked,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PlanExecutionBoundaryKind {
Started,
Finished,
Failed,
Cancelled,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum TaskLifecycleState {
Ready,
Started,
Finished,
Failed {
error_code: String,
},
Cancelled,
Dropped,
Panicked,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeReservationAction {
Reserve,
Grow,
Shrink,
Transfer,
Alias,
Relabel,
SourceCachePromote,
SourceCacheEvict,
Release,
Deny,
Rollback,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeReservationDisposition {
Applied,
Granted,
Denied,
ExplicitRelease,
DropRelease,
UnwindRelease,
CleanupRelease,
RollbackRelease,
AliasDeferred,
CancelledRelease,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum AdmissionLifecycleState {
Enqueued,
Admitted,
Rejected { reason: String },
TimedOut,
CancellationRequested,
Cancelled,
Released,
Dropped,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum GpuJobLifecycleState {
Enqueued,
Started,
Finished,
Failed {
error_code: String,
},
CancellationRequested,
Cancelled,
Dropped,
Panicked,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StreamLeaseAcquisition {
Reused,
Created,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum StreamLeaseLifecycleState {
Enqueued,
Acquired {
acquisition: StreamLeaseAcquisition,
host_wait_ns: u64,
},
CancellationRequested,
Cancelled,
Failed {
error_code: String,
},
Released,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeStreamLeaseScope {
pub(crate) plan_execution_id: Option<PlanExecutionId>,
pub task_id: Option<RuntimeTaskId>,
pub source_worker_id: Option<RuntimeWorkerId>,
pub gpu_job_id: Option<RuntimeJobId>,
pub gpu_worker_id: Option<RuntimeWorkerId>,
}
impl RuntimeStreamLeaseScope {
pub fn for_plan(plan_execution_id: PlanExecutionId) -> Self {
Self { plan_execution_id: Some(plan_execution_id), ..Self::default() }
}
pub(crate) fn with_source_worker(mut self, task_id: RuntimeTaskId, worker_id: RuntimeWorkerId) -> Self {
self.task_id = Some(task_id);
self.source_worker_id = Some(worker_id);
self
}
pub(crate) fn with_gpu_worker(mut self, job_id: RuntimeJobId, worker_id: RuntimeWorkerId) -> Self {
self.gpu_job_id = Some(job_id);
self.gpu_worker_id = Some(worker_id);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum SourceReadLifecycleState {
Enqueued,
WorkerStarted {
queue_wait_ns: u64,
},
ReadFinished {
read_duration_ns: u64,
},
ReadFailed {
error_code: String,
read_duration_ns: u64,
},
ConsumerJoinStarted,
ConsumerJoinFinished {
join_duration_ns: u64,
},
Cancelled,
Panicked,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeMeasurementScope {
Query,
Task,
Process,
DeviceGlobal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeMeasurementSource {
ReservationLedger,
FrameResidency,
AllocatorHighWater,
DeviceSampler,
StreamPool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeMeasurementQuality {
Exact,
Observed,
Estimated,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeTaskLifecycleObservation {
pub attempt_id: TaskAttemptId,
pub(crate) task_kind: String,
pub lifecycle: TaskLifecycleState,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeAdmissionObservation {
pub(crate) admission_request_id: AdmissionRequestId,
pub(crate) lifecycle: AdmissionLifecycleState,
pub(crate) queue_depth: usize,
pub(crate) device_ordinal: Option<u32>,
pub grant_bytes: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeGpuJobObservation {
pub(crate) job_id: RuntimeJobId,
pub(crate) job_kind: String,
pub(crate) device_ordinal: u32,
pub(crate) worker_id: Option<RuntimeWorkerId>,
pub lifecycle: GpuJobLifecycleState,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeStreamLeaseObservation {
pub(crate) lease_id: RuntimeResourceId,
pub(crate) device_ordinal: u32,
pub scope: RuntimeStreamLeaseScope,
pub lifecycle: StreamLeaseLifecycleState,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeSourceReadObservation {
pub task_id: RuntimeTaskId,
pub worker_id: RuntimeWorkerId,
pub chunk_index: usize,
pub file_index: usize,
pub lifecycle: SourceReadLifecycleState,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeResourceMeasurementObservation {
pub(crate) resource_id: RuntimeResourceId,
pub(crate) scope: RuntimeMeasurementScope,
pub(crate) source: RuntimeMeasurementSource,
pub(crate) quality: RuntimeMeasurementQuality,
pub(crate) measurement_kind: String,
pub(crate) current_value: u64,
pub(crate) delta: i128,
pub(crate) limit: Option<u64>,
pub(crate) device_ordinal: Option<u32>,
pub(crate) grant_bytes: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeReservationObservation {
pub reservation_id: RuntimeReservationId,
pub lineage_id: RuntimeReservationId,
pub task_attempt_id: Option<TaskAttemptId>,
pub task_kind: Option<String>,
pub action: RuntimeReservationAction,
pub denied_action: Option<RuntimeReservationAction>,
pub disposition: RuntimeReservationDisposition,
pub alias: bool,
pub reservation_kind: String,
pub memory_space: String,
pub memory_boundary: String,
pub requested_bytes: u64,
pub granted_bytes: u64,
pub charged_delta_bytes: i128,
pub current_reserved_bytes: u64,
pub budget_bytes: u64,
pub node_id: Option<String>,
pub stage: Option<String>,
pub chunk_index: Option<usize>,
pub file_index: Option<usize>,
pub source_location_id: Option<RuntimeSourceLocationId>,
pub row_groups: Option<Vec<usize>>,
pub attempt: Option<usize>,
pub max_attempts: Option<usize>,
pub resident_resource_id: Option<String>,
pub source_read_contract_quality: Option<String>,
pub source_read_planning_bytes: Option<u64>,
pub source_read_estimated_bytes: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeCleanupFailureObservation {
pub summary: CleanupFailureSummary,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeOperatorStageKind {
RegexReplacePreflight,
RegexReplaceExecute,
ExactCardinalityProbe,
PreparedGroupbyPrepare,
PreparedGroupbyAggregate,
LibcudfGroupby,
HashPartition,
PartialAggregate,
FinalMerge,
PartitionLocalTopK,
FinalSort,
VectorPack,
VectorNative,
VectorAssemble,
MlPack,
MlNative,
MlAssemble,
}
impl RuntimeOperatorStageKind {
pub const fn as_str(self) -> &'static str {
match self {
Self::RegexReplacePreflight => "regex_replace_preflight",
Self::RegexReplaceExecute => "regex_replace_execute",
Self::ExactCardinalityProbe => "exact_cardinality_probe",
Self::PreparedGroupbyPrepare => "prepared_groupby_prepare",
Self::PreparedGroupbyAggregate => "prepared_groupby_aggregate",
Self::LibcudfGroupby => "libcudf_groupby",
Self::HashPartition => "hash_partition",
Self::PartialAggregate => "partial_aggregate",
Self::FinalMerge => "final_merge",
Self::PartitionLocalTopK => "partition_local_top_k",
Self::FinalSort => "final_sort",
Self::VectorPack => "vector_pack",
Self::VectorNative => "vector_native",
Self::VectorAssemble => "vector_assemble",
Self::MlPack => "ml_pack",
Self::MlNative => "ml_native",
Self::MlAssemble => "ml_assemble",
}
}
}
impl fmt::Display for RuntimeOperatorStageKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum RuntimeOperatorStageState {
Started,
Finished,
Failed {
error_code: String,
},
Cancelled,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeOperatorStageObservation {
pub stage_kind: RuntimeOperatorStageKind,
pub lifecycle: RuntimeOperatorStageState,
pub(crate) node_id: Option<String>,
pub(crate) task_id: Option<RuntimeTaskId>,
pub chunk_index: Option<usize>,
pub(crate) partition_index: Option<usize>,
pub(crate) attempt: Option<u32>,
pub strategy_label: Option<String>,
pub input_rows: Option<u64>,
pub output_rows: Option<u64>,
pub(crate) input_bytes: Option<u64>,
pub(crate) output_bytes: Option<u64>,
pub(crate) reserved_bytes: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) vector_algorithm: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ml_algorithm: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vector_relation_role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vector_dimension: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub matrix_layout: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) execution_binding_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) device_ordinal: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub native_version_major: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub native_version_minor: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub native_version_patch: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) bounded_control_scalar_events: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) bounded_control_scalar_bytes: Option<u64>,
}
impl RuntimeOperatorStageObservation {
pub fn new(stage_kind: RuntimeOperatorStageKind, lifecycle: RuntimeOperatorStageState) -> Self {
Self {
stage_kind,
lifecycle,
node_id: None,
task_id: None,
chunk_index: None,
partition_index: None,
attempt: None,
strategy_label: None,
input_rows: None,
output_rows: None,
input_bytes: None,
output_bytes: None,
reserved_bytes: None,
vector_algorithm: None,
ml_algorithm: None,
vector_relation_role: None,
vector_dimension: None,
matrix_layout: None,
execution_binding_id: None,
device_ordinal: None,
native_version_major: None,
native_version_minor: None,
native_version_patch: None,
bounded_control_scalar_events: None,
bounded_control_scalar_bytes: None,
}
}
pub fn with_node_id(mut self, node_id: impl Into<String>) -> Self {
self.node_id = Some(node_id.into());
self
}
pub fn with_task_id(mut self, task_id: RuntimeTaskId) -> Self {
self.task_id = Some(task_id);
self
}
pub fn with_chunk_index(mut self, chunk_index: usize) -> Self {
self.chunk_index = Some(chunk_index);
self
}
pub fn with_partition_index(mut self, partition_index: usize) -> Self {
self.partition_index = Some(partition_index);
self
}
pub fn with_attempt(mut self, attempt: u32) -> Self {
self.attempt = Some(attempt);
self
}
pub fn with_strategy_label(mut self, strategy_label: impl Into<String>) -> Self {
self.strategy_label = Some(strategy_label.into());
self
}
pub fn with_input_rows(mut self, input_rows: u64) -> Self {
self.input_rows = Some(input_rows);
self
}
pub(crate) fn with_output_rows(mut self, output_rows: u64) -> Self {
self.output_rows = Some(output_rows);
self
}
pub fn with_input_bytes(mut self, input_bytes: u64) -> Self {
self.input_bytes = Some(input_bytes);
self
}
pub(crate) fn with_output_bytes(mut self, output_bytes: u64) -> Self {
self.output_bytes = Some(output_bytes);
self
}
pub fn with_reserved_bytes(mut self, reserved_bytes: u64) -> Self {
self.reserved_bytes = Some(reserved_bytes);
self
}
pub fn with_vector_algorithm(mut self, algorithm: impl Into<String>) -> Self {
self.vector_algorithm = Some(algorithm.into());
self
}
pub fn with_ml_algorithm(mut self, algorithm: impl Into<String>) -> Self {
self.ml_algorithm = Some(algorithm.into());
self
}
pub fn with_vector_relation_role(mut self, role: impl Into<String>) -> Self {
self.vector_relation_role = Some(role.into());
self
}
pub fn with_vector_dimension(mut self, dimension: usize) -> Self {
self.vector_dimension = Some(dimension);
self
}
pub fn with_matrix_layout(mut self, layout: impl Into<String>) -> Self {
self.matrix_layout = Some(layout.into());
self
}
pub fn with_execution_binding_id(mut self, binding_id: u64) -> Self {
self.execution_binding_id = Some(binding_id);
self
}
pub fn with_device_ordinal(mut self, device_ordinal: usize) -> Self {
self.device_ordinal = Some(device_ordinal);
self
}
pub fn with_native_version(mut self, major: u16, minor: u16, patch: u16) -> Self {
self.native_version_major = Some(major);
self.native_version_minor = Some(minor);
self.native_version_patch = Some(patch);
self
}
pub(crate) fn with_bounded_control_scalars(mut self, events: u64, bytes: u64) -> Self {
self.bounded_control_scalar_events = Some(events);
self.bounded_control_scalar_bytes = Some(bytes);
self
}
pub(crate) fn logical_retained_bytes(&self) -> u64 {
string_bytes(self.stage_kind.as_str())
+ match &self.lifecycle {
RuntimeOperatorStageState::Failed { error_code } => string_bytes(error_code),
_ => 1,
}
+ self.node_id.as_ref().map_or(0, |value| string_bytes(value))
+ self.task_id.as_ref().map_or(0, |value| string_bytes(value.as_str()))
+ self.strategy_label.as_ref().map_or(0, |value| string_bytes(value))
+ 48
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeObservationPayload {
QueryBoundary {
boundary: QueryBoundaryKind,
},
PlanExecutionBoundary {
boundary: PlanExecutionBoundaryKind,
},
TaskLifecycle(Box<RuntimeTaskLifecycleObservation>),
Admission(Box<RuntimeAdmissionObservation>),
GpuJob(Box<RuntimeGpuJobObservation>),
StreamLease(Box<RuntimeStreamLeaseObservation>),
SourceRead(Box<RuntimeSourceReadObservation>),
ResourceMeasurement(Box<RuntimeResourceMeasurementObservation>),
Reservation(Box<RuntimeReservationObservation>),
CleanupFailure(Box<RuntimeCleanupFailureObservation>),
OperatorStage(Box<RuntimeOperatorStageObservation>),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeTimelineEvent {
pub sequence: ObservationSequence,
pub monotonic_ns: u64,
pub plan_execution_id: Option<PlanExecutionId>,
pub span_id: Option<RuntimeSpanId>,
pub(crate) parent_span_id: Option<RuntimeSpanId>,
pub payload: RuntimeObservationPayload,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeObservationRecordClass {
PlanNode,
PlanEdge,
TaskDefinition,
CompiledEdge,
BarrierDefinition,
SinkDefinition,
JobDefinition,
WorkerDefinition,
Resource,
TimelineEvent,
SourceReadDetail,
OperatorDetail,
JoinStrategyDetail,
AggregateStrategyDetail,
DynamicFilterDetail,
BudgetDetail,
LakehouseCacheFillDetail,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeObservationLossReason {
RecordLimit,
ByteLimit,
Oversized,
SourceLocationKeyUnavailable,
Unassigned,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct RuntimeObservationClassLoss {
pub(crate) class: RuntimeObservationRecordClass,
pub(crate) count: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeObservationReasonLoss {
pub reason: RuntimeObservationLossReason,
pub count: u64,
}
fn serialize_optional_attempt_report<S>(
report: &Option<std::sync::Arc<QueryAttemptReport>>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match report {
Some(report) => serializer.serialize_some(report.as_ref()),
None => serializer.serialize_none(),
}
}
fn deserialize_optional_attempt_report<'de, D>(
deserializer: D,
) -> Result<Option<std::sync::Arc<QueryAttemptReport>>, D::Error>
where D: serde::Deserializer<'de> {
Option::<QueryAttemptReport>::deserialize(deserializer).map(|report| report.map(std::sync::Arc::new))
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeObservationFooter {
pub complete: bool,
pub terminal: Option<RuntimeTerminalOutcome>,
pub retained_records: u64,
pub retained_bytes: u64,
pub first_dropped_sequence: Option<ObservationSequence>,
pub last_attempted_sequence: Option<ObservationSequence>,
pub(crate) dropped_by_class: Vec<RuntimeObservationClassLoss>,
pub dropped_by_reason: Vec<RuntimeObservationReasonLoss>,
pub truncated: bool,
pub degraded: bool,
pub(crate) poison_recoveries: u64,
#[serde(
default,
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_optional_attempt_report",
deserialize_with = "deserialize_optional_attempt_report"
)]
pub(crate) attempt_report: Option<std::sync::Arc<QueryAttemptReport>>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub counter_overflow: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "record_type", content = "data", rename_all = "snake_case")]
pub enum RuntimeObservationRecord {
Manifest(RuntimeObservationManifest),
PlanNode { sequence: ObservationSequence, row: PlanNodeRow },
PlanEdge { sequence: ObservationSequence, row: PlanEdgeRow },
TaskDefinition { sequence: ObservationSequence, row: TaskDefinitionRow },
CompiledEdge { sequence: ObservationSequence, row: CompiledEdgeRow },
BarrierDefinition { sequence: ObservationSequence, row: BarrierDefinitionRow },
SinkDefinition { sequence: ObservationSequence, row: SinkDefinitionRow },
JobDefinition { sequence: ObservationSequence, row: JobDefinitionRow },
WorkerDefinition { sequence: ObservationSequence, row: WorkerDefinitionRow },
Resource { sequence: ObservationSequence, row: RuntimeResourceRow },
TimelineEvent(RuntimeTimelineEvent),
Footer(RuntimeObservationFooter),
}
fn string_bytes(value: &str) -> u64 {
value.len() as u64
}
impl RuntimeTopologyRecord {
pub(crate) const fn class(&self) -> RuntimeObservationRecordClass {
match self {
Self::PlanNode(_) => RuntimeObservationRecordClass::PlanNode,
Self::PlanEdge(_) => RuntimeObservationRecordClass::PlanEdge,
Self::TaskDefinition(_) => RuntimeObservationRecordClass::TaskDefinition,
Self::CompiledEdge(_) => RuntimeObservationRecordClass::CompiledEdge,
Self::BarrierDefinition(_) => RuntimeObservationRecordClass::BarrierDefinition,
Self::SinkDefinition(_) => RuntimeObservationRecordClass::SinkDefinition,
Self::JobDefinition(_) => RuntimeObservationRecordClass::JobDefinition,
Self::WorkerDefinition(_) => RuntimeObservationRecordClass::WorkerDefinition,
Self::Resource(_) => RuntimeObservationRecordClass::Resource,
}
}
pub(super) fn logical_retained_bytes(&self) -> u64 {
const ENVELOPE: u64 = 24;
ENVELOPE
+ match self {
Self::PlanNode(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.node_id.as_str())
+ string_bytes(&row.operator_kind)
},
Self::PlanEdge(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.from_node_id.as_str())
+ string_bytes(row.to_node_id.as_str())
+ 4
},
Self::TaskDefinition(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.task_id.as_str())
+ row.plan_node_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ string_bytes(&row.task_kind)
+ 1
},
Self::CompiledEdge(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.edge_id.as_str())
+ string_bytes(row.from_task_id.as_str())
+ string_bytes(row.to_task_id.as_str())
+ string_bytes(&row.edge_kind)
+ row.resource_ids.iter().map(|id| string_bytes(id.as_str())).sum::<u64>()
},
Self::BarrierDefinition(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.barrier_id.as_str())
+ string_bytes(&row.barrier_kind)
+ row.upstream_task_ids.iter().map(|id| string_bytes(id.as_str())).sum::<u64>()
+ row.downstream_task_ids.iter().map(|id| string_bytes(id.as_str())).sum::<u64>()
},
Self::SinkDefinition(row) => {
string_bytes(row.plan_execution_id.as_str())
+ string_bytes(row.sink_id.as_str())
+ string_bytes(&row.sink_kind)
+ string_bytes(row.input_task_id.as_str())
},
Self::JobDefinition(row) => {
row.plan_execution_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ string_bytes(row.job_id.as_str())
+ string_bytes(&row.job_kind)
+ 4
},
Self::WorkerDefinition(row) => {
row.plan_execution_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ string_bytes(row.worker_id.as_str())
+ string_bytes(&row.worker_kind)
+ 5
},
Self::Resource(row) => {
row.plan_execution_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ string_bytes(row.resource_id.as_str())
+ string_bytes(&row.resource_kind)
+ row.producer_task_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ row.consumer_task_ids.iter().map(|id| string_bytes(id.as_str())).sum::<u64>()
+ string_bytes(&row.lifetime)
+ match row.domain {
RuntimeResourceDomain::Host | RuntimeResourceDomain::Storage => 1,
RuntimeResourceDomain::Device { .. } => 5,
}
},
}
}
}
impl RuntimeTimelineEvent {
pub(super) fn logical_retained_bytes(&self) -> u64 {
const ENVELOPE: u64 = 42;
let plan_execution_bytes = self.plan_execution_id.as_ref().map_or(0, |id| string_bytes(id.as_str()));
let payload_bytes = match &self.payload {
RuntimeObservationPayload::QueryBoundary { .. } => 2,
RuntimeObservationPayload::PlanExecutionBoundary { .. } => 2,
RuntimeObservationPayload::TaskLifecycle(observation) => {
string_bytes(observation.attempt_id.task_id.as_str())
+ 4
+ string_bytes(&observation.task_kind)
+ match &observation.lifecycle {
TaskLifecycleState::Failed { error_code } => string_bytes(error_code),
_ => 1,
}
},
RuntimeObservationPayload::Admission(observation) => {
(match &observation.lifecycle {
AdmissionLifecycleState::Rejected { reason } => string_bytes(reason),
_ => 1,
}) + 29
},
RuntimeObservationPayload::GpuJob(observation) => {
string_bytes(observation.job_id.as_str())
+ string_bytes(&observation.job_kind)
+ observation.worker_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ match &observation.lifecycle {
GpuJobLifecycleState::Failed { error_code } => string_bytes(error_code),
_ => 1,
}
+ 5
},
RuntimeObservationPayload::StreamLease(observation) => {
string_bytes(observation.lease_id.as_str())
+ observation.scope.plan_execution_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ observation.scope.task_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ observation.scope.source_worker_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ observation.scope.gpu_job_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ observation.scope.gpu_worker_id.as_ref().map_or(0, |id| string_bytes(id.as_str()))
+ match &observation.lifecycle {
StreamLeaseLifecycleState::Failed { error_code } => string_bytes(error_code),
StreamLeaseLifecycleState::Acquired { .. } => 9,
_ => 1,
}
+ 4
},
RuntimeObservationPayload::SourceRead(observation) => {
string_bytes(observation.task_id.as_str())
+ string_bytes(observation.worker_id.as_str())
+ match &observation.lifecycle {
SourceReadLifecycleState::ReadFailed { error_code, .. } => string_bytes(error_code) + 8,
SourceReadLifecycleState::WorkerStarted { .. }
| SourceReadLifecycleState::ReadFinished { .. }
| SourceReadLifecycleState::ConsumerJoinFinished { .. } => 8,
_ => 1,
}
+ 16
},
RuntimeObservationPayload::ResourceMeasurement(observation) => {
string_bytes(observation.resource_id.as_str()) + string_bytes(&observation.measurement_kind) + 47
},
RuntimeObservationPayload::Reservation(observation) => {
let RuntimeReservationObservation {
reservation_id,
lineage_id,
task_attempt_id,
task_kind,
reservation_kind,
memory_space,
memory_boundary,
node_id,
stage,
source_location_id,
row_groups,
resident_resource_id,
source_read_contract_quality,
..
} = observation.as_ref();
string_bytes(reservation_id.as_str())
+ string_bytes(lineage_id.as_str())
+ task_attempt_id.as_ref().map_or(0, |attempt| string_bytes(attempt.task_id.as_str()) + 4)
+ task_kind.as_ref().map_or(0, |value| string_bytes(value))
+ string_bytes(reservation_kind)
+ string_bytes(memory_space)
+ string_bytes(memory_boundary)
+ node_id.as_ref().map_or(0, |value| string_bytes(value))
+ stage.as_ref().map_or(0, |value| string_bytes(value))
+ source_location_id.as_ref().map_or(0, |value| string_bytes(value.as_str()))
+ row_groups.as_ref().map_or(0, |values| values.len() as u64 * 8)
+ resident_resource_id.as_ref().map_or(0, |value| string_bytes(value))
+ source_read_contract_quality.as_ref().map_or(0, |value| string_bytes(value))
+ 66
},
RuntimeObservationPayload::CleanupFailure(observation) => {
let summary = &observation.summary;
let failure = summary.failure();
let text_bytes = failure.text().map_or(0, |text| string_bytes(text.value()));
64 + text_bytes + u64::try_from(failure.facts().len()).unwrap_or(u64::MAX) * 16
},
RuntimeObservationPayload::OperatorStage(observation) => observation.logical_retained_bytes(),
};
ENVELOPE + plan_execution_bytes + payload_bytes
}
}
impl QueryAttemptReport {
pub(crate) fn set_observation_completeness(&mut self, footer: &RuntimeObservationFooter) {
self.observation_lost_records = footer.dropped_by_class.iter().map(|loss| loss.count).sum();
self.observation_retained_records = footer.retained_records;
self.observation_retained_bytes = footer.retained_bytes;
self.observation_truncated = footer.truncated;
self.observation_degraded = footer.degraded;
}
}