github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/protocols/blockrecords/brprocessor/processor.go (about)

     1  package brprocessor
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"github.com/unicornultrafoundation/go-helios/native/dag"
     8  	"github.com/unicornultrafoundation/go-helios/native/idx"
     9  	"github.com/unicornultrafoundation/go-helios/utils/datasemaphore"
    10  	"github.com/unicornultrafoundation/go-helios/utils/workers"
    11  
    12  	"github.com/unicornultrafoundation/go-u2u/native/ibr"
    13  )
    14  
    15  var (
    16  	ErrBusy = errors.New("failed to acquire events semaphore")
    17  )
    18  
    19  // Processor is responsible for processing incoming events
    20  type Processor struct {
    21  	cfg Config
    22  
    23  	quit chan struct{}
    24  	wg   sync.WaitGroup
    25  
    26  	callback Callback
    27  
    28  	inserter *workers.Workers
    29  
    30  	itemsSemaphore *datasemaphore.DataSemaphore
    31  }
    32  
    33  type ItemCallback struct {
    34  	Process  func(br ibr.LlrIdxFullBlockRecord) error
    35  	Released func(br ibr.LlrIdxFullBlockRecord, peer string, err error)
    36  }
    37  
    38  type Callback struct {
    39  	Item ItemCallback
    40  }
    41  
    42  // New creates an event processor
    43  func New(itemsSemaphore *datasemaphore.DataSemaphore, cfg Config, callback Callback) *Processor {
    44  	f := &Processor{
    45  		cfg:            cfg,
    46  		quit:           make(chan struct{}),
    47  		itemsSemaphore: itemsSemaphore,
    48  	}
    49  	f.callback = callback
    50  	f.inserter = workers.New(&f.wg, f.quit, cfg.MaxTasks)
    51  	return f
    52  }
    53  
    54  // Start boots up the items processor.
    55  func (f *Processor) Start() {
    56  	f.inserter.Start(1)
    57  }
    58  
    59  // Stop interrupts the processor, canceling all the pending operations.
    60  // Stop waits until all the internal goroutines have finished.
    61  func (f *Processor) Stop() {
    62  	close(f.quit)
    63  	f.itemsSemaphore.Terminate()
    64  	f.wg.Wait()
    65  }
    66  
    67  // Overloaded returns true if too much items are being processed
    68  func (f *Processor) Overloaded() bool {
    69  	return f.inserter.TasksCount() > f.cfg.MaxTasks*3/4
    70  }
    71  
    72  func (f *Processor) Enqueue(peer string, items []ibr.LlrIdxFullBlockRecord, totalSize uint64, done func()) error {
    73  	metric := dag.Metric{Num: idx.Event(len(items)), Size: totalSize}
    74  	if !f.itemsSemaphore.Acquire(metric, f.cfg.SemaphoreTimeout) {
    75  		return ErrBusy
    76  	}
    77  
    78  	return f.inserter.Enqueue(func() {
    79  		if done != nil {
    80  			defer done()
    81  		}
    82  		defer f.itemsSemaphore.Release(metric)
    83  		for i, item := range items {
    84  			// process item
    85  			err := f.callback.Item.Process(item)
    86  			items[i].Txs = nil
    87  			items[i].Receipts = nil
    88  			f.callback.Item.Released(item, peer, err)
    89  		}
    90  	})
    91  }
    92  
    93  func (f *Processor) TasksCount() int {
    94  	return f.inserter.TasksCount()
    95  }