v0.3.13-pre.011

This commit is contained in:
2026-09-10 21:27:18 +02:00
parent f636169783
commit 06319655b0
15 changed files with 778 additions and 69 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
// version: 25
// version: 26
use sha2::Digest; // rust-rules: trait-import
@@ -156,14 +156,18 @@ impl RawTransactionIngestLiveSource {
} else {
crate::RawTransactionIngestSourceState::Failed
};
inventory_publisher.publish(source_projection_with_state(latest, terminal_state));
if let std::result::Result::Err(error) = inventory_publisher.publish(source_projection_with_state(latest, terminal_state)) {
return std::result::Result::Err(error);
}
return result;
}
changed = source_frontier_receiver.changed() => {
if changed.is_err() {
return std::result::Result::Err(crate::runtime_error("source.frontier_channel_closed"));
}
inventory_publisher.publish(*source_frontier_receiver.borrow_and_update());
if let std::result::Result::Err(error) = inventory_publisher.publish(*source_frontier_receiver.borrow_and_update()) {
return std::result::Result::Err(error);
}
}
}
}
@@ -171,7 +175,7 @@ impl RawTransactionIngestLiveSource {
}
impl RawTransactionIngestSourceInventory {
fn aggregate(&self) -> crate::RawTransactionIngestProcessingFrontierProjection {
fn aggregate(&self) -> ksp_core_lib::Result<crate::RawTransactionIngestProcessingFrontierProjection> {
let mut hydration_pending = 0_usize;
let mut oldest_pending_slot = std::option::Option::None;
let mut processing_frontier_slot = std::option::Option::None;
@@ -189,7 +193,10 @@ impl RawTransactionIngestSourceInventory {
let mut any_reconnecting = false;
let mut all_closed = !self.source_projections.is_empty();
for projection in &self.source_projections {
hydration_pending = hydration_pending.saturating_add(projection.hydration_pending());
hydration_pending = match hydration_pending.checked_add(projection.hydration_pending()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(crate::counter_exhausted_error("hydration_pending")),
};
oldest_pending_slot = minimum_optional_slot(oldest_pending_slot, projection.oldest_pending_slot());
match projection.processing_frontier_slot() {
std::option::Option::Some(slot) => {
@@ -199,9 +206,18 @@ impl RawTransactionIngestSourceInventory {
all_frontiers_present = false;
},
}
source_continuity_gap_total = source_continuity_gap_total.saturating_add(projection.source_continuity_gap_total());
source_reconnect_total = source_reconnect_total.saturating_add(projection.source_reconnect_total());
source_replay_attempt_total = source_replay_attempt_total.saturating_add(projection.source_replay_attempt_total());
source_continuity_gap_total = match source_continuity_gap_total.checked_add(projection.source_continuity_gap_total()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(crate::counter_exhausted_error("source_continuity_gap_total")),
};
source_reconnect_total = match source_reconnect_total.checked_add(projection.source_reconnect_total()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(crate::counter_exhausted_error("source_reconnect_total")),
};
source_replay_attempt_total = match source_replay_attempt_total.checked_add(projection.source_replay_attempt_total()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(crate::counter_exhausted_error("source_replay_attempt_total")),
};
match projection.source_state() {
std::option::Option::Some(crate::RawTransactionIngestSourceState::Active) => {
source_active += 1;
@@ -244,9 +260,11 @@ impl RawTransactionIngestSourceInventory {
} else {
std::option::Option::None
};
return crate::RawTransactionIngestProcessingFrontierProjection::new(hydration_pending, processing_frontier_slot, oldest_pending_slot)
.with_source_continuity(source_state, source_reconnect_total, source_replay_attempt_total, source_continuity_gap_total)
.with_source_counts(source_total, source_active, source_reconnecting, source_failed);
return std::result::Result::Ok(
crate::RawTransactionIngestProcessingFrontierProjection::new(hydration_pending, processing_frontier_slot, oldest_pending_slot)
.with_source_continuity(source_state, source_reconnect_total, source_replay_attempt_total, source_continuity_gap_total)
.with_source_counts(source_total, source_active, source_reconnecting, source_failed),
);
}
fn new(source_keys: std::vec::Vec<[u8; 32]>) -> Self {
@@ -254,35 +272,45 @@ impl RawTransactionIngestSourceInventory {
return Self { source_keys, source_projections };
}
fn update(&mut self, entry_index: usize, source_key: [u8; 32], projection: crate::RawTransactionIngestProcessingFrontierProjection) {
fn update(
&mut self,
entry_index: usize,
source_key: [u8; 32],
projection: crate::RawTransactionIngestProcessingFrontierProjection,
) -> ksp_core_lib::Result<()> {
let expected_key = match self.source_keys.get(entry_index) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
std::option::Option::None => return std::result::Result::Err(crate::runtime_error("source.inventory_entry_missing")),
};
if expected_key != &source_key {
return;
return std::result::Result::Err(crate::runtime_error("source.inventory_key_mismatch"));
}
let current = match self.source_projections.get_mut(entry_index) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
std::option::Option::None => return std::result::Result::Err(crate::runtime_error("source.inventory_projection_missing")),
};
*current = projection;
return;
return std::result::Result::Ok(());
}
}
impl RawTransactionIngestSourceInventoryPublisher {
fn publish(&self, projection: crate::RawTransactionIngestProcessingFrontierProjection) {
fn publish(&self, projection: crate::RawTransactionIngestProcessingFrontierProjection) -> ksp_core_lib::Result<()> {
let aggregate = {
let mut inventory = match self.inventory.lock() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(poisoned) => poisoned.into_inner(),
};
inventory.update(self.entry_index, self.source_key, projection);
inventory.aggregate()
if let std::result::Result::Err(error) = inventory.update(self.entry_index, self.source_key, projection) {
return std::result::Result::Err(error);
}
match inventory.aggregate() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
};
self.aggregate_sender.send_replace(aggregate);
return;
return std::result::Result::Ok(());
}
}
@@ -3502,15 +3530,19 @@ impl RawTransactionIngestGlobalHydrationRegistry {
}
fn publish_and_remove(&self, key: &RawTransactionIngestHydrationKey, result: RawTransactionIngestSharedHydrationResult) {
let sender = {
let mut pending = match self.pending.lock() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(poisoned) => poisoned.into_inner(),
};
pending.remove(key)
let mut pending = match self.pending.lock() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(poisoned) => poisoned.into_inner(),
};
if let std::option::Option::Some(sender) = sender {
sender.send_replace(std::option::Option::Some(result));
let published = match pending.get(key) {
std::option::Option::Some(sender) => {
sender.send_replace(std::option::Option::Some(result));
true
},
std::option::Option::None => false,
};
if published {
let _removed = pending.remove(key);
}
return;
}