code.vegaprotocol.io/vega@v0.79.0/datanode/broker/broker.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package broker
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"sync"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/events"
    25  	"code.vegaprotocol.io/vega/datanode/entities"
    26  	"code.vegaprotocol.io/vega/libs/broker"
    27  	"code.vegaprotocol.io/vega/logging"
    28  	"code.vegaprotocol.io/vega/protos/vega"
    29  )
    30  
    31  // TestInterface interface (horribly named) is declared here to provide a drop-in replacement for broker mocks used throughout
    32  // in addition to providing the classical mockgen functionality, this mock can be used to check the actual events that will be generated
    33  // so we don't have to rely on test-only helper functions.
    34  type TestInterface interface {
    35  	Send(event events.Event)
    36  	Subscribe(s broker.Subscriber) int
    37  	SubscribeBatch(subs ...broker.Subscriber)
    38  	Unsubscribe(k int)
    39  	Receive(ctx context.Context) error
    40  }
    41  
    42  type EventReceiver interface {
    43  	Listen() error
    44  	Receive(ctx context.Context) (<-chan events.Event, <-chan error)
    45  }
    46  
    47  type RawEventReceiver interface {
    48  	Listen() error
    49  	Receive(ctx context.Context) (<-chan []byte, <-chan error)
    50  }
    51  
    52  type rawEventReceiverSender interface {
    53  	RawEventReceiver
    54  	Send(events.Event) error
    55  }
    56  
    57  type subscription struct {
    58  	broker.Subscriber
    59  	required bool
    60  }
    61  
    62  type ChainInfoI interface {
    63  	SetChainID(string) error
    64  	GetChainID() (string, error)
    65  }
    66  
    67  type OrderEventWithVegaTime struct {
    68  	events.Order
    69  	vegaTime time.Time
    70  }
    71  
    72  func (oe *OrderEventWithVegaTime) VegaTime() time.Time {
    73  	return oe.vegaTime
    74  }
    75  
    76  func (oe *OrderEventWithVegaTime) GetOrder() *vega.Order {
    77  	return oe.Order.Order()
    78  }
    79  
    80  // Broker - the base broker type
    81  // perhaps we can extend this to embed into type-specific brokers.
    82  type Broker struct {
    83  	ctx   context.Context
    84  	mu    sync.RWMutex
    85  	tSubs map[events.Type]map[int]*subscription
    86  	// these fields ensure a unique ID for all subscribers, regardless of what event types they subscribe to
    87  	// once the broker context is cancelled, this map will be used to notify all subscribers, who can then
    88  	// close their internal channels. We can then cleanly shut down (not having unclosed channels)
    89  	subs   map[int]subscription
    90  	keys   []int
    91  	eChans map[events.Type]chan []events.Event
    92  	smVer  int // version of subscriber map
    93  
    94  	eventSource EventReceiver
    95  	quit        chan struct{}
    96  	chainID     string
    97  	vegaTime    time.Time
    98  }
    99  
   100  // New creates a new base broker.
   101  func New(ctx context.Context, log *logging.Logger, config Config, chainID string,
   102  	eventsource EventReceiver,
   103  ) (*Broker, error) {
   104  	log = log.Named(namedLogger)
   105  	log.SetLevel(config.Level.Get())
   106  
   107  	b := &Broker{
   108  		ctx:         ctx,
   109  		tSubs:       map[events.Type]map[int]*subscription{},
   110  		subs:        map[int]subscription{},
   111  		keys:        []int{},
   112  		eChans:      map[events.Type]chan []events.Event{},
   113  		eventSource: eventsource,
   114  		quit:        make(chan struct{}),
   115  		chainID:     chainID,
   116  	}
   117  
   118  	return b, nil
   119  }
   120  
   121  func (b *Broker) sendChannel(sub broker.Subscriber, evts []events.Event) {
   122  	// wait for a max of 1 second
   123  	timeout := time.NewTimer(time.Second)
   124  	defer func() {
   125  		// drain the channel if we managed to leave the function before the timer expired
   126  		if !timeout.Stop() {
   127  			<-timeout.C
   128  		}
   129  	}()
   130  	select {
   131  	case <-b.ctx.Done():
   132  		return
   133  	case <-sub.Closed():
   134  		return
   135  	case sub.C() <- evts:
   136  		return
   137  	case <-timeout.C:
   138  		return
   139  	}
   140  }
   141  
   142  func (b *Broker) sendChannelSync(sub broker.Subscriber, evts []events.Event) bool {
   143  	select {
   144  	case <-b.ctx.Done():
   145  		return false
   146  	case <-sub.Skip():
   147  		return false
   148  	case <-sub.Closed():
   149  		return true
   150  	case sub.C() <- evts:
   151  		return false
   152  	default:
   153  		// @TODO perhaps log that we've encountered the channel buffer of a subscriber
   154  		// this could help us find out what combination of event types + batch sizes are
   155  		// problematic
   156  		go b.sendChannel(sub, evts)
   157  		return false
   158  	}
   159  }
   160  
   161  func (b *Broker) startSending(t events.Type, evt events.Event) {
   162  	var (
   163  		subs map[int]*subscription
   164  		ver  int
   165  	)
   166  	b.mu.Lock()
   167  	ch, ok := b.eChans[t]
   168  	if !ok {
   169  		subs, ver = b.getSubsByType(t, 0)
   170  		ln := len(subs) + 1                      // at least buffer 1
   171  		ch = make(chan []events.Event, ln*20+20) // create a channel with buffer, min 40
   172  		b.eChans[t] = ch                         // assign the newly created channel
   173  	}
   174  	b.mu.Unlock()
   175  
   176  	if t == events.TimeUpdate {
   177  		timeUpdate := evt.(entities.TimeUpdateEvent)
   178  		b.vegaTime = timeUpdate.Time().Truncate(time.Microsecond)
   179  	}
   180  
   181  	if t == events.OrderEvent {
   182  		orderEvent := evt.(*events.Order)
   183  		evt = &OrderEventWithVegaTime{*orderEvent, b.vegaTime}
   184  	}
   185  
   186  	ch <- []events.Event{evt}
   187  	if ok {
   188  		// we already started the routine to consume the channel
   189  		// we can return here
   190  		return
   191  	}
   192  	go func(ch chan []events.Event, t events.Type) {
   193  		defer func() {
   194  			b.mu.Lock()
   195  			delete(b.eChans, t)
   196  			close(ch)
   197  			b.mu.Unlock()
   198  		}()
   199  		for {
   200  			select {
   201  			case <-b.ctx.Done():
   202  				return
   203  			case events := <-ch:
   204  				// we're only reading here, so allow multiple routines to do traverse the map simultaneously
   205  				b.mu.RLock()
   206  				ns, nv := b.getSubsByType(t, ver)
   207  				b.mu.RUnlock()
   208  				// if nv == ver, the subs haven't changed
   209  				if nv != ver {
   210  					ver = nv
   211  					subs = ns
   212  				}
   213  				unsub := make([]int, 0, len(subs))
   214  				for k, sub := range subs {
   215  					select {
   216  					case <-sub.Skip():
   217  						continue
   218  					case <-sub.Closed():
   219  						unsub = append(unsub, k)
   220  					default:
   221  						if sub.required {
   222  							sub.Push(events...)
   223  						} else if rm := b.sendChannelSync(sub, events); rm {
   224  							unsub = append(unsub, k)
   225  						}
   226  					}
   227  				}
   228  				if len(unsub) != 0 {
   229  					b.mu.Lock()
   230  					b.rmSubs(unsub...)
   231  					// we could update the sub map here, because we know subscribers have been removed
   232  					// but that would hold a write lock for a longer time.
   233  					b.mu.Unlock()
   234  				}
   235  			}
   236  		}
   237  	}(ch, t)
   238  }
   239  
   240  // Send sends an event to all subscribers.
   241  func (b *Broker) Send(event events.Event) {
   242  	b.startSending(event.Type(), event)
   243  }
   244  
   245  // simplified version for better performance - unfortunately, we'll still need to copy the map.
   246  func (b *Broker) getSubsByType(t events.Type, sv int) (map[int]*subscription, int) {
   247  	// we add the entire ALL map to type-specific maps, so if set, we can return this map directly
   248  	if sv != 0 && sv == b.smVer {
   249  		return nil, sv
   250  	}
   251  	subs, ok := b.tSubs[t]
   252  	if !ok && t != events.TxErrEvent {
   253  		// if a typed map isn't set (yet), and it's not the error event, we can return
   254  		// ALL subscribers directly instead
   255  		subs = b.tSubs[events.All]
   256  	}
   257  	// we still need to create a copy to keep the race detector happy
   258  	cpy := make(map[int]*subscription, len(subs))
   259  	for k, v := range subs {
   260  		cpy[k] = v
   261  	}
   262  	return cpy, b.smVer
   263  }
   264  
   265  // Subscribe registers a new subscriber, returning the key.
   266  func (b *Broker) Subscribe(s broker.Subscriber) int {
   267  	b.mu.Lock()
   268  	k := b.subscribe(s)
   269  	b.mu.Unlock()
   270  	return k
   271  }
   272  
   273  func (b *Broker) SubscribeBatch(subs ...broker.Subscriber) {
   274  	b.mu.Lock()
   275  	for _, s := range subs {
   276  		k := b.subscribe(s)
   277  		s.SetID(k)
   278  	}
   279  	b.mu.Unlock()
   280  }
   281  
   282  func (b *Broker) subscribe(s broker.Subscriber) int {
   283  	k := b.getKey()
   284  	sub := subscription{
   285  		Subscriber: s,
   286  		required:   s.Ack(),
   287  	}
   288  	b.subs[k] = sub
   289  	types := sub.Types()
   290  	// filter out weird types values like []events.Type{events.PartyEvent, events.All,}
   291  	// those subscribers subscribe to all events no matter what, so treat them accordingly
   292  	isAll := false
   293  	if len(types) == 0 {
   294  		isAll = true
   295  		types = []events.Type{events.All}
   296  	} else {
   297  		for _, t := range types {
   298  			if t == events.All {
   299  				types = []events.Type{events.All}
   300  				isAll = true
   301  				break
   302  			}
   303  		}
   304  	}
   305  	for _, t := range types {
   306  		if _, ok := b.tSubs[t]; !ok {
   307  			b.tSubs[t] = map[int]*subscription{}
   308  			if !isAll {
   309  				// not the ALL event, so can be added to the map, and as the "all" subscribers should be
   310  				for ak, as := range b.tSubs[events.All] {
   311  					b.tSubs[t][ak] = as
   312  				}
   313  			}
   314  		}
   315  		b.tSubs[t][k] = &sub
   316  	}
   317  	if isAll {
   318  		for t := range b.tSubs {
   319  			// Don't add ALL subs to the map they're already in, and don't add it to the
   320  			// special TxErrEvent map, but we should add them to all other maps
   321  			if t != events.All && t != events.TxErrEvent {
   322  				b.tSubs[t][k] = &sub
   323  			}
   324  		}
   325  	}
   326  	b.smVer++
   327  	return k
   328  }
   329  
   330  // Unsubscribe removes subscriber from broker
   331  // this does not change the state of the subscriber.
   332  func (b *Broker) Unsubscribe(k int) {
   333  	b.mu.Lock()
   334  	b.rmSubs(k)
   335  	b.mu.Unlock()
   336  }
   337  
   338  func (b *Broker) getKey() int {
   339  	if len(b.keys) > 0 {
   340  		k := b.keys[0]
   341  		b.keys = b.keys[1:] // pop first element
   342  		return k
   343  	}
   344  	return len(b.subs) + 1 // add  1 to avoid zero value
   345  }
   346  
   347  func (b *Broker) rmSubs(keys ...int) {
   348  	if len(keys) == 0 {
   349  		return
   350  	}
   351  	for _, k := range keys {
   352  		// if the sub doesn't exist, this could be a duplicate call
   353  		// we do not want the keys slice to contain duplicate values
   354  		// and so we have to check this first
   355  		s, ok := b.subs[k]
   356  		if !ok {
   357  			return
   358  		}
   359  		types := s.Types()
   360  		for _, t := range types {
   361  			if t == events.All {
   362  				types = nil
   363  				break
   364  			}
   365  		}
   366  		if len(types) == 0 {
   367  			// remove in all subscribers then
   368  			for _, v := range b.tSubs {
   369  				delete(v, k)
   370  			}
   371  		} else {
   372  			for _, t := range types {
   373  				delete(b.tSubs[t], k) // remove key from typed subs map
   374  			}
   375  		}
   376  		delete(b.subs, k)
   377  		b.keys = append(b.keys, k)
   378  	}
   379  	b.smVer++
   380  }
   381  
   382  func (b *Broker) Receive(ctx context.Context) error {
   383  	if err := b.eventSource.Listen(); err != nil {
   384  		return err
   385  	}
   386  
   387  	receiveCh, errCh := b.eventSource.Receive(ctx)
   388  
   389  	for e := range receiveCh {
   390  		if err := checkChainID(b.chainID, e.ChainID()); err != nil {
   391  			return err
   392  		}
   393  		b.Send(e)
   394  	}
   395  
   396  	select {
   397  	case err := <-errCh:
   398  		return err
   399  	default:
   400  		return nil
   401  	}
   402  }
   403  
   404  func checkChainID(expectedChainID string, chainID string) error {
   405  	if chainID != expectedChainID {
   406  		return fmt.Errorf("mismatched chain id received: %s, want %s", chainID, expectedChainID)
   407  	}
   408  	return nil
   409  }