From 6e9ca32ef5d1bf139dfddc4687f830329a23a312 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 2 Aug 2026 19:37:06 +0000 Subject: [PATCH] perf(scheduler): eliminate HashSet allocation in emit_sla_alerts Replaces the `HashSet` used for deduplicating SLA alerts during the scheduler execution hot path with a zero-allocation sorted `Vec` and `binary_search`. This avoids both heap allocation for bucket arrays and hashing overhead when checking bounds, streamlining the loop. Derived PartialOrd and Ord on `InstanceId` to support sorting by tuple. Co-authored-by: ovasylenko <3797513+ovasylenko@users.noreply.github.com> --- orch8-engine/src/scheduler.rs | 16 +++++++++++----- orch8-types/src/ids.rs | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/orch8-engine/src/scheduler.rs b/orch8-engine/src/scheduler.rs index 837c0e4c..5878a0d0 100644 --- a/orch8-engine/src/scheduler.rs +++ b/orch8-engine/src/scheduler.rs @@ -1522,13 +1522,19 @@ async fn emit_sla_alerts( .map(|c| (c.instance_id, &c.block_id)) .collect(); let existing = ctx.storage.get_block_outputs_batch(&keys).await?; - let mut existing_ref = std::collections::HashSet::with_capacity(existing.len()); - for k in existing.keys() { - existing_ref.insert((&k.0, &k.1)); - } + + // Performance: Sorting keys and using binary search avoids + // the allocation and hashing overhead of building a HashSet for + // exclusion checking on the execution hot path. + let mut existing_keys: Vec<(&InstanceId, &BlockId)> = + existing.keys().map(|(iid, bid)| (iid, bid)).collect(); + existing_keys.sort_unstable(); for c in candidates { - if existing_ref.contains(&(&c.instance_id, &c.block_id)) { + if existing_keys + .binary_search(&(&c.instance_id, &c.block_id)) + .is_ok() + { continue; } // Persist the sentinel BEFORE emitting so a crash mid-emit cannot diff --git a/orch8-types/src/ids.rs b/orch8-types/src/ids.rs index 5463e8ea..c325d76f 100644 --- a/orch8-types/src/ids.rs +++ b/orch8-types/src/ids.rs @@ -5,7 +5,20 @@ use uuid::Uuid; /// Newtype wrappers prevent mixing up UUIDs at compile time. /// Zero cost at runtime (transparent newtypes). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, sqlx::Type, ToSchema)] +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + sqlx::Type, + ToSchema, +)] #[sqlx(transparent)] pub struct InstanceId(Uuid);