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
146
147
148
149
//! The message-delivery seam and an in-memory implementation.
//!
//! The protocol core does not send anything itself — it emits
//! [`Action::Send`](crate::Action::Send), and a driver delivers the message.
//! [`RaftTransport`] is the trait that driver implements. Splitting "decide to
//! send" from "actually send" is what keeps the core deterministic and free of
//! networking: the same election can be replayed in a unit test with a transport
//! that just records messages, then run in production over TCP, with no change
//! to the protocol.
//!
//! [`MemoryTransport`] is the recording implementation used by the test harness
//! and examples.
use crateResult;
use crateMessage;
use crateNodeId;
/// Delivers protocol messages to peers.
///
/// A driver loop takes each [`Action::Send`](crate::Action::Send) a node emits
/// and calls [`send`](RaftTransport::send). How delivery happens — an in-process
/// queue, a channel, a socket — is entirely the implementor's concern; the
/// protocol only requires that a message handed to `send` is eventually
/// delivered to the target node's [`step`](crate::RaftNode::step) (Raft already
/// tolerates loss, reordering, and duplication, so "eventually, maybe" is a
/// sufficient contract).
///
/// # Examples
///
/// ```
/// use raft_io::{MemoryTransport, RaftTransport, Message, RequestVote};
///
/// let mut tx = MemoryTransport::new();
/// tx.send(2, Message::RequestVote(RequestVote {
/// term: 1, candidate: 1, last_log_index: 0, last_log_term: 0,
/// })).unwrap();
/// assert_eq!(tx.take().len(), 1);
/// ```
/// An in-memory [`RaftTransport`] that records outgoing messages.
///
/// Instead of delivering anywhere, it appends each message to an outbox that a
/// test harness drains with [`take`](MemoryTransport::take) and routes to the
/// destination node by hand. This makes message ordering, loss, and partitions
/// something the test controls precisely.
///
/// # Examples
///
/// ```
/// use raft_io::{MemoryTransport, RaftTransport, Message, AppendEntries};
///
/// let mut tx = MemoryTransport::new();
/// tx.send(2, Message::AppendEntries(AppendEntries {
/// term: 1, leader: 1, prev_log_index: 0, prev_log_term: 0,
/// entries: Vec::new(), leader_commit: 0,
/// })).unwrap();
///
/// let pending = tx.take();
/// assert_eq!(pending[0].0, 2); // destination
/// assert!(tx.take().is_empty()); // draining leaves it empty
/// ```