github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/comm/demux.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package comm
     8  
     9  import (
    10  	"sync"
    11  	"sync/atomic"
    12  
    13  	"github.com/hyperledger/fabric/gossip/common"
    14  )
    15  
    16  // ChannelDeMultiplexer is a struct that can receive channel registrations (AddChannel)
    17  // and publications (DeMultiplex) and it broadcasts the publications to registrations
    18  // according to their predicate
    19  type ChannelDeMultiplexer struct {
    20  	channels []*channel
    21  	lock     *sync.RWMutex
    22  	closed   int32
    23  }
    24  
    25  // NewChannelDemultiplexer creates a new ChannelDeMultiplexer
    26  func NewChannelDemultiplexer() *ChannelDeMultiplexer {
    27  	return &ChannelDeMultiplexer{
    28  		channels: make([]*channel, 0),
    29  		lock:     &sync.RWMutex{},
    30  		closed:   int32(0),
    31  	}
    32  }
    33  
    34  type channel struct {
    35  	pred common.MessageAcceptor
    36  	ch   chan interface{}
    37  }
    38  
    39  func (m *ChannelDeMultiplexer) isClosed() bool {
    40  	return atomic.LoadInt32(&m.closed) == int32(1)
    41  }
    42  
    43  // Close closes this channel, which makes all channels registered before
    44  // to close as well.
    45  func (m *ChannelDeMultiplexer) Close() {
    46  	defer func() {
    47  		// recover closing an already closed channel
    48  		recover()
    49  	}()
    50  	atomic.StoreInt32(&m.closed, int32(1))
    51  	m.lock.Lock()
    52  	defer m.lock.Unlock()
    53  	for _, ch := range m.channels {
    54  		close(ch.ch)
    55  	}
    56  }
    57  
    58  // AddChannel registers a channel with a certain predicate
    59  func (m *ChannelDeMultiplexer) AddChannel(predicate common.MessageAcceptor) chan interface{} {
    60  	m.lock.Lock()
    61  	defer m.lock.Unlock()
    62  	ch := &channel{ch: make(chan interface{}, 10), pred: predicate}
    63  	m.channels = append(m.channels, ch)
    64  	return ch.ch
    65  }
    66  
    67  // DeMultiplex broadcasts the message to all channels that were returned
    68  // by AddChannel calls and that hold the respected predicates.
    69  func (m *ChannelDeMultiplexer) DeMultiplex(msg interface{}) {
    70  	defer func() {
    71  		recover()
    72  	}() // recover from sending on a closed channel
    73  
    74  	if m.isClosed() {
    75  		return
    76  	}
    77  
    78  	m.lock.RLock()
    79  	channels := m.channels
    80  	m.lock.RUnlock()
    81  
    82  	for _, ch := range channels {
    83  		if ch.pred(msg) {
    84  			ch.ch <- msg
    85  		}
    86  	}
    87  }