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