1#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct ClosedSessionSummary {
10 pub sid: SessionId,
12 pub status: SessionStatus,
14 pub role_count: usize,
16 pub local_type_entries: usize,
18 pub edge_count: usize,
20 pub edge_handler_count: usize,
22 pub auth_leaf_count: usize,
24 pub auth_tree_count: usize,
26 pub auth_root_count: usize,
28 pub epoch: usize,
30}
31
32impl ClosedSessionSummary {
33 fn from_session(session: &SessionState) -> Self {
34 Self {
35 sid: session.sid,
36 status: session.status.clone(),
37 role_count: session.roles.len(),
38 local_type_entries: session.local_types.len(),
39 edge_count: session.buffers.len(),
40 edge_handler_count: session.edge_handlers.len(),
41 auth_leaf_count: session.auth_leaves.values().map(Vec::len).sum(),
42 auth_tree_count: session.auth_trees.len(),
43 auth_root_count: session.auth_roots.len(),
44 epoch: session.epoch,
45 }
46 }
47
48 fn retained_bytes_estimate(&self) -> usize {
49 std::mem::size_of::<Self>().saturating_add(serialized_bytes(self))
50 }
51}
52
53#[derive(Debug, Clone)]
55pub struct SessionOpenPlan {
56 pub(crate) roles: Vec<String>,
57 pub(crate) role_ids: BTreeMap<String, u16>,
58 pub(crate) initial_types: Vec<(String, LocalTypeR, LocalTypeR)>,
59 pub(crate) edge_blueprint: Vec<((u16, u16), String, String)>,
60 pub(crate) active_branch_roles: Vec<String>,
61}
62
63impl SessionOpenPlan {
64 fn collect_protocol_edges(
65 role: &str,
66 local_type: &LocalTypeR,
67 role_ids: &BTreeMap<String, u16>,
68 edges: &mut BTreeSet<(u16, u16)>,
69 ) {
70 match local_type {
71 LocalTypeR::End | LocalTypeR::Var(_) => {}
72 LocalTypeR::Mu { body, .. } => {
73 Self::collect_protocol_edges(role, body, role_ids, edges);
74 }
75 LocalTypeR::Send { partner, branches } => {
76 if let (Some(from_id), Some(to_id)) = (role_ids.get(role), role_ids.get(partner)) {
77 if from_id != to_id {
78 edges.insert((*from_id, *to_id));
79 }
80 }
81 for (_, _, continuation) in branches {
82 Self::collect_protocol_edges(role, continuation, role_ids, edges);
83 }
84 }
85 LocalTypeR::Recv { partner, branches } => {
86 if let (Some(from_id), Some(to_id)) = (role_ids.get(partner), role_ids.get(role)) {
87 if from_id != to_id {
88 edges.insert((*from_id, *to_id));
89 }
90 }
91 for (_, _, continuation) in branches {
92 Self::collect_protocol_edges(role, continuation, role_ids, edges);
93 }
94 }
95 }
96 }
97
98 #[must_use]
105 pub fn new(roles: &[String], initial_types: &BTreeMap<String, LocalTypeR>) -> Self {
106 let role_ids = SessionState::build_role_ids(roles);
107 let mut planned_types = Vec::with_capacity(roles.len());
108 let mut active_branch_roles = Vec::new();
109 for role in roles {
110 if let Some(original) = initial_types.get(role) {
111 let current = unfold_mu(original);
112 if SessionState::branch_shape(¤t).is_some() {
113 active_branch_roles.push(role.clone());
114 }
115 planned_types.push((role.clone(), current, original.clone()));
116 }
117 }
118
119 let mut protocol_edges = BTreeSet::new();
120 for role in roles {
121 if let Some(original) = initial_types.get(role) {
122 Self::collect_protocol_edges(role, original, &role_ids, &mut protocol_edges);
123 }
124 }
125 let mut edge_blueprint = Vec::with_capacity(protocol_edges.len());
126 for (from_id, to_id) in protocol_edges {
127 let from = roles
128 .get(usize::from(from_id))
129 .expect("sender role id must index the session-open role set")
130 .clone();
131 let to = roles
132 .get(usize::from(to_id))
133 .expect("receiver role id must index the session-open role set")
134 .clone();
135 edge_blueprint.push(((from_id, to_id), from, to));
136 }
137
138 Self {
139 roles: roles.to_vec(),
140 role_ids,
141 initial_types: planned_types,
142 edge_blueprint,
143 active_branch_roles,
144 }
145 }
146
147 #[must_use]
149 pub fn roles(&self) -> &[String] {
150 &self.roles
151 }
152
153 #[must_use]
155 pub fn edge_blueprint(&self) -> &[((u16, u16), String, String)] {
156 &self.edge_blueprint
157 }
158}
159
160#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
162pub struct SessionStoreMemoryUsage {
163 pub live_sessions: usize,
165 pub live_closed_sessions: usize,
167 pub archived_closed_sessions: usize,
169 pub live_local_type_entries: usize,
171 pub live_buffer_count: usize,
173 pub live_buffered_messages: usize,
175 pub live_edge_handler_count: usize,
177 pub live_auth_leaf_count: usize,
179 pub live_auth_tree_count: usize,
181 pub live_auth_root_count: usize,
183 pub retained_bytes: SessionStoreRetainedBytes,
185}
186
187#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
189pub struct SessionStoreRetainedBytes {
190 pub live_sessions: usize,
192 pub archived_closed: usize,
194 pub local_types: usize,
196 pub buffers: usize,
198 pub traces: usize,
200 pub auth: usize,
202 pub handlers: usize,
204 pub total: usize,
206}
207
208pub type SessionId = usize;
210
211pub type FragmentOwnerId = String;
213
214pub type OwnershipEpoch = u64;
216
217pub type OwnershipClaimId = u64;
219
220pub type AuthorityWitnessId = u64;
222
223pub type HandlerId = String;
225type HandlerNumericId = u16;
226type LabelNumericId = u16;
227type EdgeKey = (u16, u16);
228type LocalBranches<'a> = &'a [(Label, Option<ValType>, LocalTypeR)];
229type HandlerIndexBuild = (
230 BTreeMap<HandlerId, HandlerNumericId>,
231 Vec<HandlerId>,
232 BTreeMap<EdgeKey, HandlerNumericId>,
233 Option<HandlerNumericId>,
234);
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
237pub(crate) enum BranchDirection {
238 Send,
239 Recv,
240}
241
242#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
243pub(crate) struct CachedBranch {
244 pub(crate) direction: BranchDirection,
245 pub(crate) partner: String,
246 pub(crate) expected_type: Option<ValType>,
247 pub(crate) continuation: LocalTypeR,
248}
249
250pub(crate) const DEFAULT_HANDLER_ID: &str = "default_handler";
252
253fn default_handler_id() -> HandlerId {
254 DEFAULT_HANDLER_ID.to_string()
255}
256
257fn serialized_bytes<T: Serialize>(value: &T) -> usize {
258 crate::serialization::binary_size(value)
259}
260
261#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
263pub struct Edge {
264 pub sid: SessionId,
266 pub sender: String,
268 pub receiver: String,
270}
271
272impl Edge {
273 #[must_use]
275 pub fn new(sid: SessionId, sender: impl Into<String>, receiver: impl Into<String>) -> Self {
276 Self {
277 sid,
278 sender: sender.into(),
279 receiver: receiver.into(),
280 }
281 }
282}
283
284#[derive(Debug, Deserialize)]
285struct EdgeJson {
286 sid: Option<SessionId>,
287 sender: String,
288 receiver: String,
289}
290
291pub fn decode_edge_json(
297 value: &JsonValue,
298 session_hint: Option<SessionId>,
299) -> Result<Edge, String> {
300 let raw: EdgeJson =
301 serde_json::from_value(value.clone()).map_err(|e| format!("invalid edge json: {e}"))?;
302
303 let sid = raw
304 .sid
305 .or(session_hint)
306 .ok_or_else(|| "missing sid in edge json".to_string())?;
307 Ok(Edge::new(sid, raw.sender, raw.receiver))
308}
309
310#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
312pub enum SessionStatus {
313 Active,
315 Draining,
317 Closed,
319 Cancelled,
321 Faulted {
323 reason: String,
325 },
326}
327
328#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
330pub enum OwnershipScope {
331 Session,
333 Fragments(BTreeSet<String>),
335}
336
337impl OwnershipScope {
338 #[must_use]
340 pub fn allows_session_mutation(&self) -> bool {
341 matches!(self, Self::Session)
342 }
343}
344
345#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
347pub struct OwnershipCapability {
348 pub session_id: SessionId,
350 pub owner_id: FragmentOwnerId,
352 pub generation: OwnershipEpoch,
354 pub scope: OwnershipScope,
356}
357
358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
360pub struct OwnershipReceipt {
361 pub session_id: SessionId,
363 pub claim_id: OwnershipClaimId,
365 pub from_owner_id: FragmentOwnerId,
367 pub from_generation: OwnershipEpoch,
369 pub to_owner_id: FragmentOwnerId,
371 pub to_generation: OwnershipEpoch,
373 pub scope: OwnershipScope,
375}
376
377#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
380pub struct ReadinessWitness {
381 pub witness_id: AuthorityWitnessId,
383 pub session_id: SessionId,
385 pub owner_id: FragmentOwnerId,
387 pub generation: OwnershipEpoch,
389 pub scope: OwnershipScope,
391 pub predicate_ref: String,
393}
394
395#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
397pub struct CancellationWitness {
398 pub witness_id: AuthorityWitnessId,
400 pub session_id: SessionId,
402 pub owner_id: FragmentOwnerId,
404 pub generation: OwnershipEpoch,
406 pub reason: OwnershipTerminalReason,
408}
409
410#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
412pub struct TimeoutWitness {
413 pub witness_id: AuthorityWitnessId,
415 pub site: String,
417 pub issued_at_tick: u64,
419 pub until_tick: u64,
421}
422
423#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
425pub enum AuthorityArtifact {
426 OwnershipCapability(OwnershipCapability),
428 OwnershipReceipt(OwnershipReceipt),
430 Readiness(ReadinessWitness),
432 Cancellation(CancellationWitness),
434 Timeout(TimeoutWitness),
436}
437
438#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
440pub enum AuthorityAuditEvent {
441 Issued,
443 Consumed,
445 Invalidated,
447 Committed,
449 RolledBack,
451 Rejected,
453 Expired,
455}
456
457impl From<AuthorityAuditEvent> for crate::capabilities::ProtocolCriticalCapabilityLifecycleState {
458 fn from(event: AuthorityAuditEvent) -> Self {
459 match event {
460 AuthorityAuditEvent::Issued => Self::Issued,
461 AuthorityAuditEvent::Consumed => Self::Consumed,
462 AuthorityAuditEvent::Invalidated => Self::Invalidated,
463 AuthorityAuditEvent::Committed => Self::Committed,
464 AuthorityAuditEvent::RolledBack => Self::RolledBack,
465 AuthorityAuditEvent::Rejected => Self::Rejected,
466 AuthorityAuditEvent::Expired => Self::Expired,
467 }
468 }
469}
470
471#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
473pub struct AuthorityAuditRecord {
474 pub tick: Option<u64>,
476 pub artifact: AuthorityArtifact,
478 pub event: AuthorityAuditEvent,
480 pub reason: Option<String>,
482}
483
484#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
486pub enum OwnershipTerminalReason {
487 OwnerDied {
489 owner_id: FragmentOwnerId,
491 },
492 TransferAbandoned {
494 owner_id: FragmentOwnerId,
496 claim_id: OwnershipClaimId,
498 },
499 TransferCommitFailed {
501 owner_id: FragmentOwnerId,
503 claim_id: OwnershipClaimId,
505 reason: String,
507 },
508}
509
510#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
512pub enum OwnershipError {
513 SessionNotFound {
515 session_id: SessionId,
517 },
518 AlreadyClaimed {
520 session_id: SessionId,
522 current_owner_id: FragmentOwnerId,
524 },
525 Unclaimed {
527 session_id: SessionId,
529 },
530 StaleCapability {
532 session_id: SessionId,
534 owner_id: FragmentOwnerId,
536 expected_generation: OwnershipEpoch,
538 actual_generation: OwnershipEpoch,
540 },
541 ScopeViolation {
543 session_id: SessionId,
545 owner_id: FragmentOwnerId,
547 required: OwnershipScope,
549 actual: OwnershipScope,
551 },
552 TransferPending {
554 session_id: SessionId,
556 claim_id: OwnershipClaimId,
558 },
559 TransferNotPending {
561 session_id: SessionId,
563 },
564 ReceiptMismatch {
566 session_id: SessionId,
568 claim_id: OwnershipClaimId,
570 },
571 InvalidWitness {
573 session_id: SessionId,
575 witness_id: AuthorityWitnessId,
577 reason: String,
579 },
580 WitnessConsumed {
582 session_id: SessionId,
584 witness_id: AuthorityWitnessId,
586 },
587 Terminal {
589 session_id: SessionId,
591 reason: OwnershipTerminalReason,
593 },
594}
595
596#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
598pub enum SessionHostMutation {
599 SetDefaultHandler {
601 handler: HandlerId,
603 },
604 UpdateEdgeHandler {
606 edge: Edge,
608 handler: HandlerId,
610 },
611 UpdateTrace {
613 edge: Edge,
615 trace: Vec<ValType>,
617 },
618}
619
620#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
621pub(crate) struct PendingOwnershipTransfer {
622 pub(crate) receipt: OwnershipReceipt,
623}
624
625#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
626pub(crate) struct SessionOwnershipState {
627 pub(crate) current: Option<OwnershipCapability>,
628 pub(crate) pending_transfer: Option<PendingOwnershipTransfer>,
629 pub(crate) terminal_reason: Option<OwnershipTerminalReason>,
630 pub(crate) next_claim_id: OwnershipClaimId,
631 pub(crate) next_witness_id: AuthorityWitnessId,
632 pub(crate) issued_readiness: BTreeMap<AuthorityWitnessId, ReadinessWitness>,
633 pub(crate) consumed_witnesses: BTreeSet<AuthorityWitnessId>,
634 pub(crate) audit_log: Vec<AuthorityAuditRecord>,
635}
636
637impl Default for SessionOwnershipState {
638 fn default() -> Self {
639 Self {
640 current: None,
641 pending_transfer: None,
642 terminal_reason: None,
643 next_claim_id: 1,
644 next_witness_id: 1,
645 issued_readiness: BTreeMap::new(),
646 consumed_witnesses: BTreeSet::new(),
647 audit_log: Vec::new(),
648 }
649 }
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct TypeEntry {
655 pub current: LocalTypeR,
657 pub original: LocalTypeR,
659}