github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  	proto "github.com/hyperledger/fabric/protos/gossip"
    27  	"github.com/op/go-logging"
    28  )
    29  
    30  type msgImpl struct {
    31  	msg *proto.GossipMessage
    32  }
    33  
    34  func (mi *msgImpl) SenderID() string {
    35  	return string(mi.msg.GetLeadershipMsg().PkiID)
    36  }
    37  
    38  func (mi *msgImpl) IsProposal() bool {
    39  	return !mi.IsDeclaration()
    40  }
    41  
    42  func (mi *msgImpl) IsDeclaration() bool {
    43  	return mi.msg.GetLeadershipMsg().IsDeclaration
    44  }
    45  
    46  type peerImpl struct {
    47  	member *discovery.NetworkMember
    48  }
    49  
    50  func (pi *peerImpl) ID() string {
    51  	return string(pi.member.PKIid)
    52  }
    53  
    54  type gossip interface {
    55  	// Peers returns the NetworkMembers considered alive
    56  	Peers() []discovery.NetworkMember
    57  
    58  	// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
    59  	// If passThrough is false, the messages are processed by the gossip layer beforehand.
    60  	// If passThrough is true, the gossip layer doesn't intervene and the messages
    61  	// can be used to send a reply back to the sender
    62  	Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
    63  
    64  	// Gossip sends a message to other peers to the network
    65  	Gossip(msg *proto.GossipMessage)
    66  }
    67  
    68  type adapterImpl struct {
    69  	gossip gossip
    70  	self   *discovery.NetworkMember
    71  
    72  	incTime uint64
    73  	seqNum  uint64
    74  
    75  	channel common.ChainID
    76  
    77  	logger *logging.Logger
    78  
    79  	doneCh   chan struct{}
    80  	stopOnce *sync.Once
    81  }
    82  
    83  // NewAdapter creates new leader election adapter
    84  func NewAdapter(gossip gossip, self *discovery.NetworkMember, channel common.ChainID) LeaderElectionAdapter {
    85  	return &adapterImpl{
    86  		gossip: gossip,
    87  		self:   self,
    88  
    89  		incTime: uint64(time.Now().UnixNano()),
    90  		seqNum:  uint64(0),
    91  
    92  		channel: channel,
    93  
    94  		logger: logging.MustGetLogger("LeaderElectionAdapter"),
    95  
    96  		doneCh:   make(chan struct{}),
    97  		stopOnce: &sync.Once{},
    98  	}
    99  }
   100  
   101  func (ai *adapterImpl) Gossip(msg Msg) {
   102  	ai.gossip.Gossip(msg.(*msgImpl).msg)
   103  }
   104  
   105  func (ai *adapterImpl) Accept() <-chan Msg {
   106  	adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool {
   107  		// Get only leadership org and channel messages
   108  		return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG &&
   109  			message.(*proto.GossipMessage).IsLeadershipMsg() &&
   110  			bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel)
   111  	}, false)
   112  
   113  	msgCh := make(chan Msg)
   114  
   115  	go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) {
   116  		for {
   117  			select {
   118  			case <-stopCh:
   119  				return
   120  			case gossipMsg, ok := <-inCh:
   121  				if ok {
   122  					outCh <- &msgImpl{gossipMsg}
   123  				} else {
   124  					return
   125  				}
   126  			}
   127  		}
   128  	}(adapterCh, msgCh, ai.doneCh)
   129  	return msgCh
   130  }
   131  
   132  func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg {
   133  	ai.seqNum++
   134  	seqNum := ai.seqNum
   135  
   136  	leadershipMsg := &proto.LeadershipMessage{
   137  		PkiID:         ai.self.PKIid,
   138  		IsDeclaration: isDeclaration,
   139  		Timestamp: &proto.PeerTime{
   140  			IncNumber: ai.incTime,
   141  			SeqNum:    seqNum,
   142  		},
   143  	}
   144  
   145  	msg := &proto.GossipMessage{
   146  		Nonce:   0,
   147  		Tag:     proto.GossipMessage_CHAN_AND_ORG,
   148  		Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg},
   149  		Channel: ai.channel,
   150  	}
   151  	return &msgImpl{msg}
   152  }
   153  
   154  func (ai *adapterImpl) Peers() []Peer {
   155  	peers := ai.gossip.Peers()
   156  
   157  	var res []Peer
   158  	for _, peer := range peers {
   159  		res = append(res, &peerImpl{&peer})
   160  	}
   161  
   162  	return res
   163  }
   164  
   165  func (ai *adapterImpl) Stop() {
   166  	stopFunc := func() {
   167  		close(ai.doneCh)
   168  	}
   169  	ai.stopOnce.Do(stopFunc)
   170  }