@@ -23,6 +23,7 @@ use crate::raft::AddLearnerResponse;
23
23
use crate :: raft:: ClientWriteResponse ;
24
24
use crate :: raft:: RaftRespTx ;
25
25
use crate :: raft_types:: LogIdOptionExt ;
26
+ use crate :: raft_types:: RaftLogId ;
26
27
use crate :: runtime:: RaftRuntime ;
27
28
use crate :: versioned:: Updatable ;
28
29
use crate :: ChangeMembers ;
@@ -40,15 +41,15 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
40
41
& mut self ,
41
42
target : C :: NodeId ,
42
43
node : Option < Node > ,
43
- ) -> Result < ( ) , AddLearnerError < C :: NodeId > > {
44
+ ) -> Result < LogId < C :: NodeId > , AddLearnerError < C :: NodeId > > {
44
45
let curr = & self . core . engine . state . membership_state . effective . membership ;
45
46
let new_membership = curr. add_learner ( target, node) ?;
46
47
47
48
tracing:: debug!( ?new_membership, "new_config" ) ;
48
49
49
- self . write_entry ( EntryPayload :: Membership ( new_membership) , None ) . await ?;
50
+ let log_id = self . write_entry ( EntryPayload :: Membership ( new_membership) , None ) . await ?;
50
51
51
- Ok ( ( ) )
52
+ Ok ( log_id )
52
53
}
53
54
54
55
/// Add a new node to the cluster as a learner, bringing it up-to-speed, and then responding
@@ -60,24 +61,26 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
60
61
///
61
62
/// If `blocking` is `true`, the result is sent to `tx` as the target node log has caught up. Otherwise, result is
62
63
/// sent at once, no matter whether the target node log is lagging or not.
63
- #[ tracing:: instrument( level = "debug" , skip( self , tx ) ) ]
64
+ #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
64
65
pub ( super ) async fn add_learner (
65
66
& mut self ,
66
67
target : C :: NodeId ,
67
68
node : Option < Node > ,
68
69
tx : RaftRespTx < AddLearnerResponse < C :: NodeId > , AddLearnerError < C :: NodeId > > ,
69
- blocking : bool ,
70
- ) {
70
+ ) -> Result < ( ) , Fatal < C :: NodeId > > {
71
71
tracing:: debug!( "add target node {} as learner {:?}" , target, self . nodes. keys( ) ) ;
72
72
73
73
// Ensure the node doesn't already exist in the current
74
74
// config, in the set of new nodes already being synced, or in the nodes being removed.
75
+ // TODO: remove this
75
76
if target == self . core . id {
76
77
tracing:: debug!( "target node is this node" ) ;
78
+
77
79
let _ = tx. send ( Ok ( AddLearnerResponse {
80
+ membership_log_id : self . core . engine . state . membership_state . effective . log_id ,
78
81
matched : self . core . engine . state . last_log_id ( ) ,
79
82
} ) ) ;
80
- return ;
83
+ return Ok ( ( ) ) ;
81
84
}
82
85
83
86
let curr = & self . core . engine . state . membership_state . effective ;
@@ -86,8 +89,11 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
86
89
87
90
if let Some ( t) = self . nodes . get ( & target) {
88
91
tracing:: debug!( "target node is already a cluster member or is being synced" ) ;
89
- let _ = tx. send ( Ok ( AddLearnerResponse { matched : t. matched } ) ) ;
90
- return ;
92
+ let _ = tx. send ( Ok ( AddLearnerResponse {
93
+ membership_log_id : self . core . engine . state . membership_state . effective . log_id ,
94
+ matched : t. matched ,
95
+ } ) ) ;
96
+ return Ok ( ( ) ) ;
91
97
} else {
92
98
unreachable ! (
93
99
"node {} in membership but there is no replication stream for it" ,
@@ -99,29 +105,31 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
99
105
// TODO(xp): when new membership log is appended, write_entry() should be responsible to setup new replication
100
106
// stream.
101
107
let res = self . write_add_learner_entry ( target, node) . await ;
102
- if let Err ( e) = res {
103
- let _ = tx. send ( Err ( e) ) ;
104
- return ;
105
- }
106
-
107
- if blocking {
108
- let state = self . spawn_replication_stream ( target, Some ( tx) ) . await ;
109
- // TODO(xp): nodes, i.e., replication streams, should also be a property of follower or candidate, for
110
- // sending vote requests etc?
111
- self . nodes . insert ( target, state) ;
112
- } else {
113
- let state = self . spawn_replication_stream ( target, None ) . await ;
114
- self . nodes . insert ( target, state) ;
108
+ let log_id = match res {
109
+ Ok ( x) => x,
110
+ Err ( e) => {
111
+ let _ = tx. send ( Err ( e) ) ;
112
+ return Ok ( ( ) ) ;
113
+ }
114
+ } ;
115
115
116
- // non-blocking mode, do not know about the replication stat.
117
- let _ = tx. send ( Ok ( AddLearnerResponse { matched : None } ) ) ;
118
- }
116
+ // TODO(xp): nodes, i.e., replication streams, should also be a property of follower or candidate, for
117
+ // sending vote requests etc?
118
+ let state = self . spawn_replication_stream ( target) . await ;
119
+ self . nodes . insert ( target, state) ;
119
120
120
121
tracing:: debug!(
121
122
"after add target node {} as learner {:?}" ,
122
123
target,
123
124
self . core. engine. state. last_log_id( )
124
125
) ;
126
+
127
+ let _ = tx. send ( Ok ( AddLearnerResponse {
128
+ membership_log_id : Some ( log_id) ,
129
+ matched : None ,
130
+ } ) ) ;
131
+
132
+ Ok ( ( ) )
125
133
}
126
134
127
135
/// return true if there is pending uncommitted config change
@@ -250,7 +258,7 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
250
258
& mut self ,
251
259
payload : EntryPayload < C > ,
252
260
resp_tx : Option < RaftRespTx < ClientWriteResponse < C > , ClientWriteError < C :: NodeId > > > ,
253
- ) -> Result < ( ) , Fatal < C :: NodeId > > {
261
+ ) -> Result < LogId < C :: NodeId > , Fatal < C :: NodeId > > {
254
262
let mut entry_refs = [ EntryRef :: new ( & payload) ] ;
255
263
// TODO: it should returns membership config error etc. currently this is done by the caller.
256
264
self . core . engine . leader_append_entries ( & mut entry_refs) ;
@@ -262,7 +270,7 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
262
270
263
271
self . run_engine_commands ( & entry_refs) . await ?;
264
272
265
- Ok ( ( ) )
273
+ Ok ( * entry_refs [ 0 ] . get_log_id ( ) )
266
274
}
267
275
268
276
#[ tracing:: instrument( level = "debug" , skip_all) ]
0 commit comments