github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/buffer/backend.go (about)

     1  package buffer
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/onflow/flow-go/model/flow"
     7  )
     8  
     9  // item represents an item in the cache: a block header, payload, and the ID
    10  // of the node that sent it to us. The payload is generic.
    11  type item struct {
    12  	header  flow.Slashable[*flow.Header]
    13  	payload interface{}
    14  }
    15  
    16  // backend implements a simple cache of pending blocks, indexed by parent ID.
    17  type backend struct {
    18  	mu sync.RWMutex
    19  	// map of pending header IDs, keyed by parent ID for ByParentID lookups
    20  	blocksByParent map[flow.Identifier][]flow.Identifier
    21  	// set of pending blocks, keyed by ID to avoid duplication
    22  	blocksByID map[flow.Identifier]*item
    23  }
    24  
    25  // newBackend returns a new pending header cache.
    26  func newBackend() *backend {
    27  	cache := &backend{
    28  		blocksByParent: make(map[flow.Identifier][]flow.Identifier),
    29  		blocksByID:     make(map[flow.Identifier]*item),
    30  	}
    31  	return cache
    32  }
    33  
    34  // add adds the item to the cache, returning false if it already exists and
    35  // true otherwise.
    36  func (b *backend) add(block flow.Slashable[*flow.Header], payload interface{}) bool {
    37  
    38  	b.mu.Lock()
    39  	defer b.mu.Unlock()
    40  
    41  	blockID := block.Message.ID()
    42  
    43  	_, exists := b.blocksByID[blockID]
    44  	if exists {
    45  		return false
    46  	}
    47  
    48  	item := &item{
    49  		header:  block,
    50  		payload: payload,
    51  	}
    52  
    53  	b.blocksByID[blockID] = item
    54  	b.blocksByParent[block.Message.ParentID] = append(b.blocksByParent[block.Message.ParentID], blockID)
    55  
    56  	return true
    57  }
    58  
    59  func (b *backend) byID(id flow.Identifier) (*item, bool) {
    60  
    61  	b.mu.RLock()
    62  	defer b.mu.RUnlock()
    63  
    64  	item, exists := b.blocksByID[id]
    65  	if !exists {
    66  		return nil, false
    67  	}
    68  
    69  	return item, true
    70  }
    71  
    72  // byParentID returns a list of cached blocks with the given parent. If no such
    73  // blocks exist, returns false.
    74  func (b *backend) byParentID(parentID flow.Identifier) ([]*item, bool) {
    75  
    76  	b.mu.RLock()
    77  	defer b.mu.RUnlock()
    78  
    79  	forParent, exists := b.blocksByParent[parentID]
    80  	if !exists {
    81  		return nil, false
    82  	}
    83  
    84  	items := make([]*item, 0, len(forParent))
    85  	for _, blockID := range forParent {
    86  		items = append(items, b.blocksByID[blockID])
    87  	}
    88  
    89  	return items, true
    90  }
    91  
    92  // dropForParent removes all cached blocks with the given parent (non-recursively).
    93  func (b *backend) dropForParent(parentID flow.Identifier) {
    94  
    95  	b.mu.Lock()
    96  	defer b.mu.Unlock()
    97  
    98  	children, exists := b.blocksByParent[parentID]
    99  	if !exists {
   100  		return
   101  	}
   102  
   103  	for _, childID := range children {
   104  		delete(b.blocksByID, childID)
   105  	}
   106  	delete(b.blocksByParent, parentID)
   107  }
   108  
   109  // pruneByView prunes any items in the cache that have view less than or
   110  // equal to the given view. The pruning view should be the finalized view.
   111  func (b *backend) pruneByView(view uint64) {
   112  
   113  	b.mu.Lock()
   114  	defer b.mu.Unlock()
   115  
   116  	for id, item := range b.blocksByID {
   117  		if item.header.Message.View <= view {
   118  			delete(b.blocksByID, id)
   119  			delete(b.blocksByParent, item.header.Message.ParentID)
   120  		}
   121  	}
   122  }
   123  
   124  // size returns the number of elements stored in teh backend
   125  func (b *backend) size() uint {
   126  	b.mu.RLock()
   127  	defer b.mu.RUnlock()
   128  	return uint(len(b.blocksByID))
   129  }