github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/gossip/election/adapter.go (about)

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