1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! The trait users implement to plug their application logic into a
//! [`crate::Node`].
//!
//! Three operations:
//! - [`StateMachine::apply`] — run a committed command against state,
//! return the response. Synchronous, infallible, deterministic.
//! - [`StateMachine::snapshot`] — produce a snapshot of state. Default
//! is "no snapshot" (returns empty bytes). The runtime calls this
//! automatically when the engine emits a snapshot hint, unless the
//! user disables that path via
//! [`crate::Config::snapshot_hint_threshold_entries`].
//! - [`StateMachine::restore`] — rebuild state from snapshot bytes.
//! Default panics; only override if you also override `snapshot`.
//!
//! ## Why apply is synchronous and infallible
//!
//! Replication makes apply effects observable on every node. To stay
//! deterministic across replicas the apply must:
//! - return the same value for the same command on every node (no
//! clocks, randomness, or network calls — those go through Command),
//! - never panic on data the cluster has accepted (a panic on one
//! replica is a non-deterministic state divergence on the others).
//!
//! If your apply needs async work (e.g., write-through to a downstream
//! store), do it after the apply returns. The runtime has already
//! committed; durability is the engine's problem, not yours.
/// The application logic the runtime feeds committed entries to.
///
/// `Command` is what callers submit via [`crate::Node::propose`]. The
/// engine treats it as opaque bytes; you decide how to serialise it
/// via [`Self::encode_command`] and [`Self::decode_command`]. Pick
/// whatever you like — serde + bincode, prost, hand-rolled bytes,
/// anything stable. The runtime never inspects the contents.
///
/// `Response` is what the propose call returns once the entry commits
/// and applies on the local node.
/// Returned from [`StateMachine::decode_command`] when the bytes off
/// the wire / disk can't be parsed back into a `Command`. The runtime
/// treats this as a corrupt-storage signal and shuts down rather than
/// silently dropping commits.
/// Returned from [`StateMachine::snapshot`] when the state machine
/// can't produce a snapshot right now. The runtime reacts by skipping
/// this hint and waiting for the next one — subsequent threshold
/// crossings will re-trigger snapshot attempts.