@@ -4,9 +4,7 @@ use std::option::Option::None;
4
4
5
5
use tracing:: Level ;
6
6
7
- use crate :: config:: RemoveReplicationPolicy ;
8
7
use crate :: core:: replication_state:: replication_lag;
9
- use crate :: core:: replication_state:: ReplicationState ;
10
8
use crate :: core:: Expectation ;
11
9
use crate :: core:: LeaderState ;
12
10
use crate :: core:: ServerState ;
@@ -20,10 +18,10 @@ use crate::error::InProgress;
20
18
use crate :: error:: LearnerIsLagging ;
21
19
use crate :: error:: LearnerNotFound ;
22
20
use crate :: metrics:: RemoveTarget ;
21
+ use crate :: progress:: Progress ;
23
22
use crate :: raft:: AddLearnerResponse ;
24
23
use crate :: raft:: ClientWriteResponse ;
25
24
use crate :: raft:: RaftRespTx ;
26
- use crate :: raft_types:: LogIdOptionExt ;
27
25
use crate :: raft_types:: RaftLogId ;
28
26
use crate :: runtime:: RaftRuntime ;
29
27
use crate :: summary:: MessageSummary ;
@@ -38,23 +36,6 @@ use crate::RaftTypeConfig;
38
36
use crate :: StorageError ;
39
37
40
38
impl < ' a , C : RaftTypeConfig , N : RaftNetworkFactory < C > , S : RaftStorage < C > > LeaderState < ' a , C , N , S > {
41
- // add node into learner,return true if the node is already a member or learner
42
- #[ tracing:: instrument( level = "debug" , skip( self ) ) ]
43
- async fn write_add_learner_entry (
44
- & mut self ,
45
- target : C :: NodeId ,
46
- node : Option < Node > ,
47
- ) -> Result < LogId < C :: NodeId > , AddLearnerError < C :: NodeId > > {
48
- let curr = & self . core . engine . state . membership_state . effective . membership ;
49
- let new_membership = curr. add_learner ( target, node) ?;
50
-
51
- tracing:: debug!( ?new_membership, "new_config" ) ;
52
-
53
- let log_id = self . write_entry ( EntryPayload :: Membership ( new_membership) , None ) . await ?;
54
-
55
- Ok ( log_id)
56
- }
57
-
58
39
/// Add a new node to the cluster as a learner, bringing it up-to-speed, and then responding
59
40
/// on the given channel.
60
41
///
@@ -79,51 +60,41 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
79
60
80
61
// Ensure the node doesn't already exist in the current
81
62
// config, in the set of new nodes already being synced, or in the nodes being removed.
82
- // TODO: remove this
83
- if target == self . core . id {
84
- tracing:: debug!( "target node is this node" ) ;
63
+
64
+ let curr = & self . core . engine . state . membership_state . effective ;
65
+ if curr. contains ( & target) {
66
+ let matched = if let Some ( l) = & self . core . engine . state . leader {
67
+ * l. progress . get ( & target)
68
+ } else {
69
+ unreachable ! ( "it has to be a leader!!!" ) ;
70
+ } ;
71
+
72
+ tracing:: debug!(
73
+ "target {:?} already member or learner, can't add; matched:{:?}" ,
74
+ target,
75
+ matched
76
+ ) ;
85
77
86
78
let _ = tx. send ( Ok ( AddLearnerResponse {
87
79
membership_log_id : self . core . engine . state . membership_state . effective . log_id ,
88
- matched : self . core . engine . state . last_log_id ( ) ,
80
+ matched,
89
81
} ) ) ;
90
82
return Ok ( ( ) ) ;
91
83
}
92
84
93
- let curr = & self . core . engine . state . membership_state . effective ;
94
- if curr. contains ( & target) {
95
- tracing:: debug!( "target {:?} already member or learner, can't add" , target) ;
96
-
97
- if let Some ( t) = self . nodes . get ( & target) {
98
- tracing:: debug!( "target node is already a cluster member or is being synced" ) ;
99
- let _ = tx. send ( Ok ( AddLearnerResponse {
100
- membership_log_id : self . core . engine . state . membership_state . effective . log_id ,
101
- matched : t. matched ,
102
- } ) ) ;
103
- return Ok ( ( ) ) ;
104
- } else {
105
- unreachable ! (
106
- "node {} in membership but there is no replication stream for it" ,
107
- target
108
- )
109
- }
110
- }
111
-
112
- // TODO(xp): when new membership log is appended, write_entry() should be responsible to setup new replication
113
- // stream.
114
- let res = self . write_add_learner_entry ( target, node) . await ;
115
- let log_id = match res {
85
+ let curr = & self . core . engine . state . membership_state . effective . membership ;
86
+ let res = curr. add_learner ( target, node) ;
87
+ let new_membership = match res {
116
88
Ok ( x) => x,
117
89
Err ( e) => {
118
- let _ = tx. send ( Err ( e ) ) ;
90
+ let _ = tx. send ( Err ( AddLearnerError :: MissingNodeInfo ( e ) ) ) ;
119
91
return Ok ( ( ) ) ;
120
92
}
121
93
} ;
122
94
123
- // TODO(xp): nodes, i.e., replication streams, should also be a property of follower or candidate, for
124
- // sending vote requests etc?
125
- let state = self . spawn_replication_stream ( target) . await ;
126
- self . nodes . insert ( target, state) ;
95
+ tracing:: debug!( ?new_membership, "new_membership with added learner: {}" , target) ;
96
+
97
+ let log_id = self . write_entry ( EntryPayload :: Membership ( new_membership) , None ) . await ?;
127
98
128
99
tracing:: debug!(
129
100
"after add target node {} as learner {:?}" ,
@@ -238,7 +209,12 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
238
209
Expectation :: AtLineRate => {
239
210
// Expect to be at line rate but not.
240
211
241
- let matched = self . nodes . get ( node_id) . map ( |x| x. matched ) . unwrap ( ) ;
212
+ let matched = if let Some ( l) = & self . core . engine . state . leader {
213
+ * l. progress . get ( node_id)
214
+ } else {
215
+ unreachable ! ( "it has to be a leader!!!" ) ;
216
+ } ;
217
+
242
218
let distance = replication_lag ( & matched, & last_log_id) ;
243
219
244
220
if distance <= self . core . config . replication_lag_threshold {
@@ -317,64 +293,28 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
317
293
/// This is ony called by leader.
318
294
#[ tracing:: instrument( level = "debug" , skip( self ) ) ]
319
295
pub ( super ) async fn handle_uniform_consensus_committed ( & mut self , log_id : & LogId < C :: NodeId > ) {
320
- let index = log_id. index ;
321
-
322
296
// Step down if needed.
323
- if !self . core . engine . state . membership_state . effective . membership . is_voter ( & self . core . id ) {
297
+
298
+ let _ = log_id;
299
+
300
+ // TODO: Leader does not need to step down. It can keep working.
301
+ // This requires to separate Leader(Proposer) and Acceptors.
302
+ if !self . core . engine . state . membership_state . effective . is_voter ( & self . core . id ) {
324
303
tracing:: debug!( "raft node is stepping down" ) ;
325
304
326
305
// TODO(xp): transfer leadership
327
306
self . core . set_target_state ( ServerState :: Learner ) ;
328
- return ;
307
+ self . core . engine . metrics_flags . set_cluster_changed ( ) ;
329
308
}
330
-
331
- let membership = & self . core . engine . state . membership_state . effective . membership ;
332
-
333
- // remove nodes which not included in nodes and learners
334
- for ( id, state) in self . nodes . iter_mut ( ) {
335
- if membership. contains ( id) {
336
- continue ;
337
- }
338
-
339
- tracing:: info!(
340
- "set remove_after_commit for {} = {}, membership: {:?}" ,
341
- id,
342
- index,
343
- self . core. engine. state. membership_state. effective
344
- ) ;
345
-
346
- state. remove_since = Some ( index)
347
- }
348
-
349
- let targets = self . nodes . keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
350
- for target in targets {
351
- self . try_remove_replication ( target) . await ;
352
- }
353
-
354
- self . core . engine . metrics_flags . set_replication_changed ( ) ;
355
309
}
356
310
357
311
/// Remove a replication if the membership that does not include it has committed.
358
312
///
359
313
/// Return true if removed.
360
314
#[ tracing:: instrument( level = "trace" , skip( self ) ) ]
361
- pub async fn try_remove_replication ( & mut self , target : C :: NodeId ) -> bool {
362
- tracing:: debug! ( target = display ( target ) , "try_remove_replication" ) ;
315
+ pub async fn remove_replication ( & mut self , target : C :: NodeId ) -> bool {
316
+ tracing:: info! ( "removed_replication to: {}" , target ) ;
363
317
364
- {
365
- let n = self . nodes . get ( & target) ;
366
-
367
- if let Some ( n) = n {
368
- if !self . need_to_remove_replication ( n) {
369
- return false ;
370
- }
371
- } else {
372
- tracing:: warn!( "trying to remove absent replication to {}" , target) ;
373
- return false ;
374
- }
375
- }
376
-
377
- tracing:: info!( "removed replication to: {}" , target) ;
378
318
let repl_state = self . nodes . remove ( & target) ;
379
319
if let Some ( s) = repl_state {
380
320
let handle = s. repl_stream . handle ;
@@ -385,6 +325,8 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
385
325
tracing:: debug!( "joining removed replication: {}" , target) ;
386
326
let _x = handle. await ;
387
327
tracing:: info!( "Done joining removed replication : {}" , target) ;
328
+ } else {
329
+ unreachable ! ( "try to nonexistent replication to {}" , target) ;
388
330
}
389
331
390
332
self . replication_metrics . update ( RemoveTarget { target } ) ;
@@ -394,53 +336,4 @@ impl<'a, C: RaftTypeConfig, N: RaftNetworkFactory<C>, S: RaftStorage<C>> LeaderS
394
336
395
337
true
396
338
}
397
-
398
- fn need_to_remove_replication ( & self , node : & ReplicationState < C :: NodeId > ) -> bool {
399
- tracing:: debug!( node=?node, "check if to remove a replication" ) ;
400
-
401
- let cfg = & self . core . config ;
402
- let policy = & cfg. remove_replication ;
403
-
404
- let st = & self . core . engine . state ;
405
- let committed = st. committed ;
406
-
407
- // `remove_since` is set only when the uniform membership log is committed.
408
- // Do not remove replication if it is not committed.
409
- let since = if let Some ( since) = node. remove_since {
410
- since
411
- } else {
412
- return false ;
413
- } ;
414
-
415
- if node. matched . index ( ) >= Some ( since) {
416
- tracing:: debug!(
417
- node = debug( node) ,
418
- committed = debug( committed) ,
419
- "remove replication: uniform membership log committed and replicated to target"
420
- ) ;
421
- return true ;
422
- }
423
-
424
- match policy {
425
- RemoveReplicationPolicy :: CommittedAdvance ( n) => {
426
- // TODO(xp): test this. but not for now. It is meaningless without blank-log heartbeat.
427
- if committed. next_index ( ) - since > * n {
428
- tracing:: debug!(
429
- node = debug( node) ,
430
- committed = debug( committed) ,
431
- "remove replication: committed index is head of remove_since too much"
432
- ) ;
433
- return true ;
434
- }
435
- }
436
- RemoveReplicationPolicy :: MaxNetworkFailures ( n) => {
437
- if node. failures >= * n {
438
- tracing:: debug!( node = debug( node) , "remove replication: too many replication failure" ) ;
439
- return true ;
440
- }
441
- }
442
- }
443
-
444
- false
445
- }
446
339
}
0 commit comments