github.com/koko1123/flow-go-1@v0.29.6/module/mempool/queue/heroQueue.go (about)

     1  package queue
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/rs/zerolog"
     7  
     8  	"github.com/koko1123/flow-go-1/model/flow"
     9  	"github.com/koko1123/flow-go-1/module"
    10  	herocache "github.com/koko1123/flow-go-1/module/mempool/herocache/backdata"
    11  	"github.com/koko1123/flow-go-1/module/mempool/herocache/backdata/heropool"
    12  )
    13  
    14  // HeroQueue implements a HeroCache-based in-memory queue.
    15  // HeroCache is a key-value cache with zero heap allocation and optimized Garbage Collection.
    16  type HeroQueue struct {
    17  	mu        sync.RWMutex
    18  	cache     *herocache.Cache
    19  	sizeLimit uint
    20  }
    21  
    22  func NewHeroQueue(sizeLimit uint32, logger zerolog.Logger, collector module.HeroCacheMetrics) *HeroQueue {
    23  	return &HeroQueue{
    24  		cache: herocache.NewCache(
    25  			sizeLimit,
    26  			herocache.DefaultOversizeFactor,
    27  			heropool.NoEjection,
    28  			logger.With().Str("mempool", "hero-queue").Logger(),
    29  			collector),
    30  		sizeLimit: uint(sizeLimit),
    31  	}
    32  }
    33  
    34  // Push stores the entity into the queue.
    35  // Boolean returned variable determines whether push was successful, i.e.,
    36  // push may be dropped if queue is full or already exists.
    37  func (c *HeroQueue) Push(entity flow.Entity) bool {
    38  	c.mu.Lock()
    39  	defer c.mu.Unlock()
    40  
    41  	if c.cache.Size() >= c.sizeLimit {
    42  		// we check size before attempt on a push,
    43  		// although HeroCache is on no-ejection mode and discards pushes beyond limit,
    44  		// we save an id computation by just checking the size here.
    45  		return false
    46  	}
    47  
    48  	return c.cache.Add(entity.ID(), entity)
    49  }
    50  
    51  // Pop removes and returns the head of queue, and updates the head to the next element.
    52  // Boolean return value determines whether pop is successful, i.e., popping an empty queue returns false.
    53  func (c *HeroQueue) Pop() (flow.Entity, bool) {
    54  	c.mu.Lock()
    55  	defer c.mu.Unlock()
    56  
    57  	head, ok := c.cache.Head()
    58  	if !ok {
    59  		// cache is empty, and there is no head yet to pop.
    60  		return nil, false
    61  	}
    62  
    63  	c.cache.Remove(head.ID())
    64  	return head, true
    65  }
    66  
    67  func (c *HeroQueue) Size() uint {
    68  	c.mu.RLock()
    69  	defer c.mu.RUnlock()
    70  
    71  	return c.cache.Size()
    72  }