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 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 Readiness(ReadinessWitness),
428 Cancellation(CancellationWitness),
430 Timeout(TimeoutWitness),
432}
433
434#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
436pub enum AuthorityAuditEvent {
437 Issued,
439 Consumed,
441 Rejected,
443}
444
445#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
447pub struct AuthorityAuditRecord {
448 pub tick: Option<u64>,
450 pub artifact: AuthorityArtifact,
452 pub event: AuthorityAuditEvent,
454 pub reason: Option<String>,
456}
457
458#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
460pub enum OwnershipTerminalReason {
461 OwnerDied {
463 owner_id: FragmentOwnerId,
465 },
466 TransferAbandoned {
468 owner_id: FragmentOwnerId,
470 claim_id: OwnershipClaimId,
472 },
473 TransferCommitFailed {
475 owner_id: FragmentOwnerId,
477 claim_id: OwnershipClaimId,
479 reason: String,
481 },
482}
483
484#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
486pub enum OwnershipError {
487 SessionNotFound {
489 session_id: SessionId,
491 },
492 AlreadyClaimed {
494 session_id: SessionId,
496 current_owner_id: FragmentOwnerId,
498 },
499 Unclaimed {
501 session_id: SessionId,
503 },
504 StaleCapability {
506 session_id: SessionId,
508 owner_id: FragmentOwnerId,
510 expected_generation: OwnershipEpoch,
512 actual_generation: OwnershipEpoch,
514 },
515 ScopeViolation {
517 session_id: SessionId,
519 owner_id: FragmentOwnerId,
521 required: OwnershipScope,
523 actual: OwnershipScope,
525 },
526 TransferPending {
528 session_id: SessionId,
530 claim_id: OwnershipClaimId,
532 },
533 TransferNotPending {
535 session_id: SessionId,
537 },
538 ReceiptMismatch {
540 session_id: SessionId,
542 claim_id: OwnershipClaimId,
544 },
545 InvalidWitness {
547 session_id: SessionId,
549 witness_id: AuthorityWitnessId,
551 reason: String,
553 },
554 WitnessConsumed {
556 session_id: SessionId,
558 witness_id: AuthorityWitnessId,
560 },
561 Terminal {
563 session_id: SessionId,
565 reason: OwnershipTerminalReason,
567 },
568}
569
570#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
572pub enum SessionHostMutation {
573 SetDefaultHandler {
575 handler: HandlerId,
577 },
578 UpdateEdgeHandler {
580 edge: Edge,
582 handler: HandlerId,
584 },
585 UpdateTrace {
587 edge: Edge,
589 trace: Vec<ValType>,
591 },
592}
593
594#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
595pub(crate) struct PendingOwnershipTransfer {
596 pub(crate) receipt: OwnershipReceipt,
597}
598
599#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
600pub(crate) struct SessionOwnershipState {
601 pub(crate) current: Option<OwnershipCapability>,
602 pub(crate) pending_transfer: Option<PendingOwnershipTransfer>,
603 pub(crate) terminal_reason: Option<OwnershipTerminalReason>,
604 pub(crate) next_claim_id: OwnershipClaimId,
605 pub(crate) next_witness_id: AuthorityWitnessId,
606 pub(crate) issued_readiness: BTreeMap<AuthorityWitnessId, ReadinessWitness>,
607 pub(crate) consumed_witnesses: BTreeSet<AuthorityWitnessId>,
608 pub(crate) audit_log: Vec<AuthorityAuditRecord>,
609}
610
611impl Default for SessionOwnershipState {
612 fn default() -> Self {
613 Self {
614 current: None,
615 pending_transfer: None,
616 terminal_reason: None,
617 next_claim_id: 1,
618 next_witness_id: 1,
619 issued_readiness: BTreeMap::new(),
620 consumed_witnesses: BTreeSet::new(),
621 audit_log: Vec::new(),
622 }
623 }
624}
625
626#[derive(Debug, Clone, Serialize, Deserialize)]
628pub struct TypeEntry {
629 pub current: LocalTypeR,
631 pub original: LocalTypeR,
633}