github.com/yimialmonte/fabric@v2.1.1+incompatible/gossip/election/adapter.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package election
     8  
     9  import (
    10  	"bytes"
    11  	"sync"
    12  	"time"
    13  
    14  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    15  	"github.com/hyperledger/fabric/gossip/common"
    16  	"github.com/hyperledger/fabric/gossip/discovery"
    17  	"github.com/hyperledger/fabric/gossip/metrics"
    18  	"github.com/hyperledger/fabric/gossip/protoext"
    19  	"github.com/hyperledger/fabric/gossip/util"
    20  )
    21  
    22  type msgImpl struct {
    23  	msg *proto.GossipMessage
    24  }
    25  
    26  func (mi *msgImpl) SenderID() peerID {
    27  	return mi.msg.GetLeadershipMsg().PkiId
    28  }
    29  
    30  func (mi *msgImpl) IsProposal() bool {
    31  	return !mi.IsDeclaration()
    32  }
    33  
    34  func (mi *msgImpl) IsDeclaration() bool {
    35  	return mi.msg.GetLeadershipMsg().IsDeclaration
    36  }
    37  
    38  type peerImpl struct {
    39  	member discovery.NetworkMember
    40  }
    41  
    42  func (pi *peerImpl) ID() peerID {
    43  	return peerID(pi.member.PKIid)
    44  }
    45  
    46  type gossip interface {
    47  	// PeersOfChannel returns the NetworkMembers considered alive in a channel
    48  	PeersOfChannel(channel common.ChannelID) []discovery.NetworkMember
    49  
    50  	// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
    51  	// If passThrough is false, the messages are processed by the gossip layer beforehand.
    52  	// If passThrough is true, the gossip layer doesn't intervene and the messages
    53  	// can be used to send a reply back to the sender
    54  	Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan protoext.ReceivedMessage)
    55  
    56  	// Gossip sends a message to other peers to the network
    57  	Gossip(msg *proto.GossipMessage)
    58  
    59  	// IsInMyOrg checks whether a network member is in this peer's org
    60  	IsInMyOrg(member discovery.NetworkMember) bool
    61  }
    62  
    63  type adapterImpl struct {
    64  	gossip    gossip
    65  	selfPKIid common.PKIidType
    66  
    67  	incTime uint64
    68  	seqNum  uint64
    69  
    70  	channel common.ChannelID
    71  
    72  	logger util.Logger
    73  
    74  	doneCh   chan struct{}
    75  	stopOnce *sync.Once
    76  	metrics  *metrics.ElectionMetrics
    77  }
    78  
    79  // NewAdapter creates new leader election adapter
    80  func NewAdapter(gossip gossip, pkiid common.PKIidType, channel common.ChannelID,
    81  	metrics *metrics.ElectionMetrics) LeaderElectionAdapter {
    82  	return &adapterImpl{
    83  		gossip:    gossip,
    84  		selfPKIid: pkiid,
    85  
    86  		incTime: uint64(time.Now().UnixNano()),
    87  		seqNum:  uint64(0),
    88  
    89  		channel: channel,
    90  
    91  		logger: util.GetLogger(util.ElectionLogger, ""),
    92  
    93  		doneCh:   make(chan struct{}),
    94  		stopOnce: &sync.Once{},
    95  		metrics:  metrics,
    96  	}
    97  }
    98  
    99  func (ai *adapterImpl) Gossip(msg Msg) {
   100  	ai.gossip.Gossip(msg.(*msgImpl).msg)
   101  }
   102  
   103  func (ai *adapterImpl) Accept() <-chan Msg {
   104  	adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool {
   105  		// Get only leadership org and channel messages
   106  		return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG &&
   107  			protoext.IsLeadershipMsg(message.(*proto.GossipMessage)) &&
   108  			bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel)
   109  	}, false)
   110  
   111  	msgCh := make(chan Msg)
   112  
   113  	go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) {
   114  		for {
   115  			select {
   116  			case <-stopCh:
   117  				return
   118  			case gossipMsg, ok := <-inCh:
   119  				if ok {
   120  					outCh <- &msgImpl{gossipMsg}
   121  				} else {
   122  					return
   123  				}
   124  			}
   125  		}
   126  	}(adapterCh, msgCh, ai.doneCh)
   127  	return msgCh
   128  }
   129  
   130  func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg {
   131  	ai.seqNum++
   132  	seqNum := ai.seqNum
   133  
   134  	leadershipMsg := &proto.LeadershipMessage{
   135  		PkiId:         ai.selfPKIid,
   136  		IsDeclaration: isDeclaration,
   137  		Timestamp: &proto.PeerTime{
   138  			IncNum: ai.incTime,
   139  			SeqNum: seqNum,
   140  		},
   141  	}
   142  
   143  	msg := &proto.GossipMessage{
   144  		Nonce:   0,
   145  		Tag:     proto.GossipMessage_CHAN_AND_ORG,
   146  		Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg},
   147  		Channel: ai.channel,
   148  	}
   149  	return &msgImpl{msg}
   150  }
   151  
   152  func (ai *adapterImpl) Peers() []Peer {
   153  	peers := ai.gossip.PeersOfChannel(ai.channel)
   154  
   155  	var res []Peer
   156  	for _, peer := range peers {
   157  		if ai.gossip.IsInMyOrg(peer) {
   158  			res = append(res, &peerImpl{peer})
   159  		}
   160  	}
   161  
   162  	return res
   163  }
   164  
   165  func (ai *adapterImpl) ReportMetrics(isLeader bool) {
   166  	var leadershipBit float64
   167  	if isLeader {
   168  		leadershipBit = 1
   169  	}
   170  	ai.metrics.Declaration.With("channel", string(ai.channel)).Set(leadershipBit)
   171  }
   172  
   173  func (ai *adapterImpl) Stop() {
   174  	stopFunc := func() {
   175  		close(ai.doneCh)
   176  	}
   177  	ai.stopOnce.Do(stopFunc)
   178  }