code.vegaprotocol.io/vega@v0.79.0/core/broker/sequence_generator.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  	"sync"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  )
    23  
    24  type gen struct {
    25  	mu       sync.Mutex
    26  	blockSeq map[string]uint64
    27  	blocks   []string
    28  }
    29  
    30  func newGen() *gen {
    31  	return &gen{
    32  		blockSeq: map[string]uint64{},
    33  		blocks:   make([]string, 0, 4),
    34  	}
    35  }
    36  
    37  // setSequence adds sequence ID to the event objects, returns the arguments because
    38  // the events might be passed by value (interface values)
    39  // returns the more restrictive event object - once seq ID is set, it should be treated as RO.
    40  func (g *gen) setSequence(evts ...events.Event) []events.Event {
    41  	if len(evts) == 0 {
    42  		return nil
    43  	}
    44  	hash := evts[0].TraceID()
    45  	g.mu.Lock()
    46  	cur, ok := g.blockSeq[hash]
    47  	if !ok {
    48  		g.blocks = append(g.blocks, hash)
    49  		cur = 1
    50  		g.blockSeq[hash] = cur
    51  		// if we're adding a new hash, check if we're up to 3, and remove it if needed
    52  		defer g.cleanID()
    53  	}
    54  	// defer call stack is LIFO, cleanID acquires a lock, so ensure we release it here first
    55  	defer g.mu.Unlock()
    56  	// set sequence ID to the next sequence ID available
    57  	ret := make([]events.Event, 0, len(evts))
    58  	// create slice of ids
    59  	for _, e := range evts {
    60  		e.SetSequenceID(cur)
    61  		// so if cur == 1 (new block), and we send 3 events with composite count of 1 -> cur == 4 (the next seq id to be set)
    62  		// if cur == 1, a composite count of 3 will send the event with seq ID 1, and set the next seq ID to be 1 + 3 == 4
    63  		// unpacking such an event leaves seq. ID 1, 2, and 3 available.
    64  		cur += e.CompositeCount()
    65  		ret = append(ret, e)
    66  	}
    67  	// update the mapk
    68  	g.blockSeq[hash] = cur
    69  	return ret
    70  }
    71  
    72  func (g *gen) cleanID() {
    73  	g.mu.Lock()
    74  	if len(g.blocks) == 4 {
    75  		delete(g.blockSeq, g.blocks[0])
    76  		g.blocks = g.blocks[1:]
    77  	}
    78  	g.mu.Unlock()
    79  }