Reduce protocol packet-flow allocations

Replace vector-backed endpoint outcomes with single-action results, skip payload deserialization on forwarded data and faults, and route local call and data emissions without encode/decode roundtrips.
This commit is contained in:
Michael Mikovsky
2026-04-25 11:46:45 -06:00
parent 792eb28457
commit 7b5b148ef3
10 changed files with 266 additions and 228 deletions
+3 -3
View File
@@ -190,9 +190,9 @@ impl Simulation {
.cloned()
.ok_or(SimError::UnknownHook(hook_id))?;
let frame = self.nodes[self.root_id.0]
let outcome = self.nodes[self.root_id.0]
.endpoint
.make_data(
.send_data(
snapshot.peer_path.clone(),
hook_id,
snapshot.procedure_id.clone(),
@@ -208,7 +208,7 @@ impl Simulation {
format_hook_ref(self.node(self.root_id).path.as_slice(), hook_id)
),
);
self.process_local_frame(self.root_id, frame)?;
self.process_outcome(self.root_id, outcome)?;
Ok(ActionResult {
label: format!("Send hook data {hook_id}"),
hook_id: Some(hook_id),
+5 -5
View File
@@ -23,9 +23,9 @@ impl Simulation {
// Hook allocation happens on the root host because the root is the hook
// owner for every user-driven action in the demo.
let hook_id = self.nodes[self.root_id.0].endpoint.allocate_hook_id();
let frame = self.nodes[self.root_id.0]
let outcome = self.nodes[self.root_id.0]
.endpoint
.make_call(
.send_call(
dst_path.clone(),
dst_leaf.clone(),
procedure_id.to_owned(),
@@ -65,7 +65,7 @@ impl Simulation {
.unwrap_or_default()
),
);
self.process_local_frame(self.root_id, frame)
self.process_outcome(self.root_id, outcome)
}
/// Delivers a frame into one endpoint as locally-originated traffic.
@@ -91,7 +91,7 @@ impl Simulation {
self.record_trace(node_id, "packet dropped".to_owned());
}
for (route, frame) in outcome.forwards {
if let Some((route, frame)) = outcome.forward {
match route {
RouteDecision::Child(index) => {
let child_id = self.nodes[node_id.0]
@@ -150,7 +150,7 @@ impl Simulation {
}
}
for event in outcome.events {
if let Some(event) = outcome.event {
self.handle_local_event(node_id, event)?;
}
+12 -12
View File
@@ -28,7 +28,7 @@ impl Simulation {
let leaf = self.require_leaf(node_id, leaf_name)?.clone();
match leaf.kind {
LeafKind::Echo => {
let frame = self.make_endpoint_data_frame(
let outcome = self.send_endpoint_data(
node_id,
hook.return_path.clone(),
hook.hook_id,
@@ -37,7 +37,7 @@ impl Simulation {
true,
)?;
self.record_trace(node_id, format!("leaf {leaf_name} echoed {} bytes", message.data.len()));
self.process_local_frame(node_id, frame)?;
self.process_outcome(node_id, outcome)?;
}
}
return Ok(());
@@ -51,7 +51,7 @@ impl Simulation {
match procedure.kind {
EndpointProcedureKind::Ping => {
let reply = format!("pong from {}", self.node(node_id).display_path());
let frame = self.make_endpoint_data_frame(
let outcome = self.send_endpoint_data(
node_id,
hook.return_path.clone(),
hook.hook_id,
@@ -60,7 +60,7 @@ impl Simulation {
true,
)?;
self.record_trace(node_id, format!("endpoint sent ping reply: {reply}"));
self.process_local_frame(node_id, frame)?;
self.process_outcome(node_id, outcome)?;
}
EndpointProcedureKind::ChunkedGreeting => {
for (index, text) in [
@@ -71,7 +71,7 @@ impl Simulation {
.iter()
.enumerate()
{
let frame = self.make_endpoint_data_frame(
let outcome = self.send_endpoint_data(
node_id,
hook.return_path.clone(),
hook.hook_id,
@@ -80,7 +80,7 @@ impl Simulation {
index == 2,
)?;
self.record_trace(node_id, format!("endpoint sent chunk {}", index + 1));
self.process_local_frame(node_id, frame)?;
self.process_outcome(node_id, outcome)?;
}
}
EndpointProcedureKind::Chat => {
@@ -95,7 +95,7 @@ impl Simulation {
procedure_id: procedure.procedure_id.clone(),
},
);
let frame = self.make_endpoint_data_frame(
let outcome = self.send_endpoint_data(
node_id,
hook.return_path.clone(),
hook.hook_id,
@@ -104,15 +104,15 @@ impl Simulation {
false,
)?;
self.record_trace(node_id, "chat handler opened session".to_owned());
self.process_local_frame(node_id, frame)?;
self.process_outcome(node_id, outcome)?;
}
}
Ok(())
}
/// Builds one endpoint-originated data frame after application logic decides
/// Routes one endpoint-originated data packet after application logic decides
/// what to send back on an already-validated hook.
fn make_endpoint_data_frame(
fn send_endpoint_data(
&mut self,
node_id: NodeId,
return_path: Vec<String>,
@@ -120,10 +120,10 @@ impl Simulation {
procedure_id: String,
data: Vec<u8>,
end_hook: bool,
) -> Result<unshell::protocol::FrameBytes, SimError> {
) -> Result<unshell::protocol::tree::EndpointOutcome, SimError> {
self.nodes[node_id.0]
.endpoint
.make_data(return_path, hook_id, procedure_id, data, end_hook)
.send_data(return_path, hook_id, procedure_id, data, end_hook)
.map_err(|error| SimError::Protocol(error.to_string()))
}
+3 -3
View File
@@ -40,9 +40,9 @@ impl Simulation {
let reply = chat_reply_for_text(&text);
if let Some((reply, end_hook)) = reply {
let frame = self.nodes[session.node_id.0]
let outcome = self.nodes[session.node_id.0]
.endpoint
.make_data(
.send_data(
session.host_path.clone(),
session.hook_id,
session.procedure_id.clone(),
@@ -51,7 +51,7 @@ impl Simulation {
)
.map_err(|error| SimError::Protocol(error.to_string()))?;
self.record_trace(session.node_id, format!("chat handler sent: {reply}"));
self.process_local_frame(session.node_id, frame)?;
self.process_outcome(session.node_id, outcome)?;
if end_hook {
self.chat_sessions.remove(&session.hook_id);
}