github.com/theQRL/go-zond@v0.1.1/event/feedof.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package event
    18  
    19  import (
    20  	"reflect"
    21  	"sync"
    22  )
    23  
    24  // FeedOf implements one-to-many subscriptions where the carrier of events is a channel.
    25  // Values sent to a Feed are delivered to all subscribed channels simultaneously.
    26  //
    27  // The zero value is ready to use.
    28  type FeedOf[T any] struct {
    29  	once      sync.Once     // ensures that init only runs once
    30  	sendLock  chan struct{} // sendLock has a one-element buffer and is empty when held.It protects sendCases.
    31  	removeSub chan chan<- T // interrupts Send
    32  	sendCases caseList      // the active set of select cases used by Send
    33  
    34  	// The inbox holds newly subscribed channels until they are added to sendCases.
    35  	mu    sync.Mutex
    36  	inbox caseList
    37  }
    38  
    39  func (f *FeedOf[T]) init() {
    40  	f.removeSub = make(chan chan<- T)
    41  	f.sendLock = make(chan struct{}, 1)
    42  	f.sendLock <- struct{}{}
    43  	f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}}
    44  }
    45  
    46  // Subscribe adds a channel to the feed. Future sends will be delivered on the channel
    47  // until the subscription is canceled.
    48  //
    49  // The channel should have ample buffer space to avoid blocking other subscribers. Slow
    50  // subscribers are not dropped.
    51  func (f *FeedOf[T]) Subscribe(channel chan<- T) Subscription {
    52  	f.once.Do(f.init)
    53  
    54  	chanval := reflect.ValueOf(channel)
    55  	sub := &feedOfSub[T]{feed: f, channel: channel, err: make(chan error, 1)}
    56  
    57  	// Add the select case to the inbox.
    58  	// The next Send will add it to f.sendCases.
    59  	f.mu.Lock()
    60  	defer f.mu.Unlock()
    61  	cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval}
    62  	f.inbox = append(f.inbox, cas)
    63  	return sub
    64  }
    65  
    66  func (f *FeedOf[T]) remove(sub *feedOfSub[T]) {
    67  	// Delete from inbox first, which covers channels
    68  	// that have not been added to f.sendCases yet.
    69  	f.mu.Lock()
    70  	index := f.inbox.find(sub.channel)
    71  	if index != -1 {
    72  		f.inbox = f.inbox.delete(index)
    73  		f.mu.Unlock()
    74  		return
    75  	}
    76  	f.mu.Unlock()
    77  
    78  	select {
    79  	case f.removeSub <- sub.channel:
    80  		// Send will remove the channel from f.sendCases.
    81  	case <-f.sendLock:
    82  		// No Send is in progress, delete the channel now that we have the send lock.
    83  		f.sendCases = f.sendCases.delete(f.sendCases.find(sub.channel))
    84  		f.sendLock <- struct{}{}
    85  	}
    86  }
    87  
    88  // Send delivers to all subscribed channels simultaneously.
    89  // It returns the number of subscribers that the value was sent to.
    90  func (f *FeedOf[T]) Send(value T) (nsent int) {
    91  	rvalue := reflect.ValueOf(value)
    92  
    93  	f.once.Do(f.init)
    94  	<-f.sendLock
    95  
    96  	// Add new cases from the inbox after taking the send lock.
    97  	f.mu.Lock()
    98  	f.sendCases = append(f.sendCases, f.inbox...)
    99  	f.inbox = nil
   100  	f.mu.Unlock()
   101  
   102  	// Set the sent value on all channels.
   103  	for i := firstSubSendCase; i < len(f.sendCases); i++ {
   104  		f.sendCases[i].Send = rvalue
   105  	}
   106  
   107  	// Send until all channels except removeSub have been chosen. 'cases' tracks a prefix
   108  	// of sendCases. When a send succeeds, the corresponding case moves to the end of
   109  	// 'cases' and it shrinks by one element.
   110  	cases := f.sendCases
   111  	for {
   112  		// Fast path: try sending without blocking before adding to the select set.
   113  		// This should usually succeed if subscribers are fast enough and have free
   114  		// buffer space.
   115  		for i := firstSubSendCase; i < len(cases); i++ {
   116  			if cases[i].Chan.TrySend(rvalue) {
   117  				nsent++
   118  				cases = cases.deactivate(i)
   119  				i--
   120  			}
   121  		}
   122  		if len(cases) == firstSubSendCase {
   123  			break
   124  		}
   125  		// Select on all the receivers, waiting for them to unblock.
   126  		chosen, recv, _ := reflect.Select(cases)
   127  		if chosen == 0 /* <-f.removeSub */ {
   128  			index := f.sendCases.find(recv.Interface())
   129  			f.sendCases = f.sendCases.delete(index)
   130  			if index >= 0 && index < len(cases) {
   131  				// Shrink 'cases' too because the removed case was still active.
   132  				cases = f.sendCases[:len(cases)-1]
   133  			}
   134  		} else {
   135  			cases = cases.deactivate(chosen)
   136  			nsent++
   137  		}
   138  	}
   139  
   140  	// Forget about the sent value and hand off the send lock.
   141  	for i := firstSubSendCase; i < len(f.sendCases); i++ {
   142  		f.sendCases[i].Send = reflect.Value{}
   143  	}
   144  	f.sendLock <- struct{}{}
   145  	return nsent
   146  }
   147  
   148  type feedOfSub[T any] struct {
   149  	feed    *FeedOf[T]
   150  	channel chan<- T
   151  	errOnce sync.Once
   152  	err     chan error
   153  }
   154  
   155  func (sub *feedOfSub[T]) Unsubscribe() {
   156  	sub.errOnce.Do(func() {
   157  		sub.feed.remove(sub)
   158  		close(sub.err)
   159  	})
   160  }
   161  
   162  func (sub *feedOfSub[T]) Err() <-chan error {
   163  	return sub.err
   164  }