github.com/true-sqn/fabric@v2.1.1+incompatible/orderer/consensus/etcdraft/tracker.go (about)

     1  /*
     2   Copyright IBM Corp All Rights Reserved.
     3  
     4   SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package etcdraft
     8  
     9  import (
    10  	"sync/atomic"
    11  
    12  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    13  	"github.com/hyperledger/fabric/common/flogging"
    14  	"github.com/hyperledger/fabric/common/metrics"
    15  	"github.com/hyperledger/fabric/protoutil"
    16  	"go.etcd.io/etcd/raft"
    17  )
    18  
    19  // Tracker periodically poll Raft Status, and update disseminator
    20  // so that status is populated to followers.
    21  type Tracker struct {
    22  	id     uint64
    23  	sender *Disseminator
    24  	gauge  metrics.Gauge
    25  	active *atomic.Value
    26  
    27  	counter int
    28  
    29  	logger *flogging.FabricLogger
    30  }
    31  
    32  func (t *Tracker) Check(status *raft.Status) {
    33  	// leaderless
    34  	if status.Lead == raft.None {
    35  		t.gauge.Set(0)
    36  		t.active.Store([]uint64{})
    37  		return
    38  	}
    39  
    40  	// follower
    41  	if status.RaftState == raft.StateFollower {
    42  		return
    43  	}
    44  
    45  	// leader
    46  	current := []uint64{t.id}
    47  	for id, progress := range status.Progress {
    48  
    49  		if id == t.id {
    50  			// `RecentActive` for leader's Progress is expected to be false in current implementation of etcd/raft,
    51  			// but because not marking the leader recently active might be considered a bug and fixed in the future,
    52  			// we explicitly defend against adding the leader, to avoid potential duplicate
    53  			continue
    54  		}
    55  
    56  		if progress.RecentActive {
    57  			current = append(current, id)
    58  		}
    59  	}
    60  
    61  	last := t.active.Load().([]uint64)
    62  	t.active.Store(current)
    63  
    64  	if len(current) != len(last) {
    65  		t.counter = 0
    66  		return
    67  	}
    68  
    69  	// consider active nodes to be stable if it holds for 3 iterations, to avoid glitch
    70  	// in this value when the recent status is reset on leader election intervals
    71  	if t.counter < 3 {
    72  		t.counter++
    73  		return
    74  	}
    75  
    76  	t.counter = 0
    77  	t.logger.Debugf("Current active nodes in cluster are: %+v", current)
    78  
    79  	t.gauge.Set(float64(len(current)))
    80  	metadata := protoutil.MarshalOrPanic(&etcdraft.ClusterMetadata{ActiveNodes: current})
    81  	t.sender.UpdateMetadata(metadata)
    82  }