github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/gossip/comm/demux.go (about)

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