1
- use super :: super :: { Address , Event , Index , Instruction , Message , Request , Status } ;
1
+ use super :: super :: { Address , Event , Index , Instruction , Message , Request , RequestID , Status } ;
2
2
use super :: { Follower , Node , NodeID , RawNode , Role , Term , Ticks , HEARTBEAT_INTERVAL } ;
3
- use crate :: error:: Result ;
3
+ use crate :: error:: { Error , Result } ;
4
4
5
5
use :: log:: { debug, info} ;
6
6
use std:: collections:: { HashMap , HashSet } ;
@@ -19,6 +19,16 @@ struct Progress {
19
19
pub struct Leader {
20
20
/// Peer replication progress.
21
21
progress : HashMap < NodeID , Progress > ,
22
+ /// Keeps track of pending write requests. These are added when the write is
23
+ /// appended to the leader's log (keyed by log index), and removed when the
24
+ /// command is applied to the state machine, sending the command result to
25
+ /// the waiting client.
26
+ ///
27
+ /// If we lose leadership before the command is processed, all pending write
28
+ /// requests are aborted by returning Error::Abort.
29
+ ///
30
+ /// TODO: Actually return responses when applied.
31
+ writes : HashMap < Index , ( Address , RequestID ) > ,
22
32
/// Number of ticks since last periodic heartbeat.
23
33
since_heartbeat : Ticks ,
24
34
}
@@ -28,7 +38,7 @@ impl Leader {
28
38
pub fn new ( peers : HashSet < NodeID > , last_index : Index ) -> Self {
29
39
let next = last_index + 1 ;
30
40
let progress = peers. into_iter ( ) . map ( |p| ( p, Progress { next, last : 0 } ) ) . collect ( ) ;
31
- Self { progress, since_heartbeat : 0 }
41
+ Self { progress, writes : HashMap :: new ( ) , since_heartbeat : 0 }
32
42
}
33
43
}
34
44
@@ -53,9 +63,15 @@ impl RawNode<Leader> {
53
63
assert ! ( term > self . term, "Can only become follower in later term" ) ;
54
64
55
65
info ! ( "Discovered new term {}" , term) ;
66
+
67
+ // Cancel in-flight requests.
68
+ self . state_tx . send ( Instruction :: Abort ) ?;
69
+ for ( address, id) in std:: mem:: take ( & mut self . role . writes ) . into_values ( ) {
70
+ self . send ( address, Event :: ClientResponse { id, response : Err ( Error :: Abort ) } ) ?;
71
+ }
72
+
56
73
self . term = term;
57
74
self . log . set_term ( term, None ) ?;
58
- self . state_tx . send ( Instruction :: Abort ) ?;
59
75
Ok ( self . into_role ( Follower :: new ( None , None ) ) )
60
76
}
61
77
@@ -148,8 +164,11 @@ impl RawNode<Leader> {
148
164
self . heartbeat ( ) ?;
149
165
}
150
166
167
+ // A client submitted a write command. Propose it, and track it
168
+ // until it's applied and the response is returned to the client.
151
169
Event :: ClientRequest { id, request : Request :: Mutate ( command) } => {
152
170
let index = self . propose ( Some ( command) ) ?;
171
+ self . role . writes . insert ( index, ( msg. from , id. clone ( ) ) ) ;
153
172
self . state_tx . send ( Instruction :: Notify { id, address : msg. from , index } ) ?;
154
173
if self . peers . is_empty ( ) {
155
174
self . maybe_commit ( ) ?;
@@ -264,6 +283,8 @@ impl RawNode<Leader> {
264
283
// TODO: Move application elsewhere, but needs access to applied index.
265
284
let mut scan = self . log . scan ( ( prev_commit_index + 1 ) ..=commit_index) ?;
266
285
while let Some ( entry) = scan. next ( ) . transpose ( ) ? {
286
+ // TODO: Send response.
287
+ self . role . writes . remove ( & entry. index ) ;
267
288
self . state_tx . send ( Instruction :: Apply { entry } ) ?;
268
289
}
269
290
}
0 commit comments