github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/mempool/stdmap/identifier_map.go (about) 1 package stdmap 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/flow-go/model/flow" 7 "github.com/onflow/flow-go/module/mempool" 8 "github.com/onflow/flow-go/module/mempool/model" 9 ) 10 11 // IdentifierMap represents a concurrency-safe memory pool for IdMapEntity. 12 type IdentifierMap struct { 13 *Backend 14 } 15 16 // NewIdentifierMap creates a new memory pool for IdMapEntity. 17 func NewIdentifierMap(limit uint) (*IdentifierMap, error) { 18 i := &IdentifierMap{ 19 Backend: NewBackend(WithLimit(limit)), 20 } 21 return i, nil 22 } 23 24 // Append will append the id to the list of identifiers associated with key. 25 func (i *IdentifierMap) Append(key, id flow.Identifier) error { 26 return i.Backend.Run(func(backdata mempool.BackData) error { 27 var ids map[flow.Identifier]struct{} 28 entity, ok := backdata.ByID(key) 29 if !ok { 30 // no record with key is available in the mempool, 31 // initializes ids. 32 ids = make(map[flow.Identifier]struct{}) 33 } else { 34 idMapEntity, ok := entity.(model.IdMapEntity) 35 if !ok { 36 return fmt.Errorf("could not assert entity to IdMapEntity") 37 } 38 39 ids = idMapEntity.IDs 40 if _, ok := ids[id]; ok { 41 // id is already associated with the key 42 // no need to append 43 return nil 44 } 45 46 // removes map entry associated with key for update 47 if _, removed := backdata.Remove(key); !removed { 48 return fmt.Errorf("potential race condition on removing from identifier map") 49 } 50 } 51 52 // appends id to the ids list 53 ids[id] = struct{}{} 54 55 // adds the new ids list associated with key to mempool 56 idMapEntity := model.IdMapEntity{ 57 Key: key, 58 IDs: ids, 59 } 60 61 if added := backdata.Add(key, idMapEntity); !added { 62 return fmt.Errorf("potential race condition on adding to identifier map") 63 } 64 65 return nil 66 }) 67 } 68 69 // Get returns list of all identifiers associated with key and true, if the key exists in the mempool. 70 // Otherwise it returns nil and false. 71 func (i *IdentifierMap) Get(key flow.Identifier) ([]flow.Identifier, bool) { 72 ids := make([]flow.Identifier, 0) 73 err := i.Run(func(backdata mempool.BackData) error { 74 entity, ok := backdata.ByID(key) 75 if !ok { 76 return fmt.Errorf("could not retrieve key from backend") 77 } 78 79 mapEntity, ok := entity.(model.IdMapEntity) 80 if !ok { 81 return fmt.Errorf("could not assert entity as IdMapEntity") 82 } 83 84 for id := range mapEntity.IDs { 85 ids = append(ids, id) 86 } 87 88 return nil 89 }) 90 91 if err != nil { 92 return nil, false 93 } 94 return ids, true 95 } 96 97 // Has returns true if the key exists in the map, i.e., there is at least an id 98 // attached to it. 99 func (i *IdentifierMap) Has(key flow.Identifier) bool { 100 return i.Backend.Has(key) 101 } 102 103 // Remove removes the given key with all associated identifiers. 104 func (i *IdentifierMap) Remove(key flow.Identifier) bool { 105 return i.Backend.Remove(key) 106 } 107 108 // RemoveIdFromKey removes the id from the list of identifiers associated with key. 109 // If the list becomes empty, it also removes the key from the map. 110 func (i *IdentifierMap) RemoveIdFromKey(key, id flow.Identifier) error { 111 err := i.Backend.Run(func(backdata mempool.BackData) error { 112 // var ids map[flow.Identifier]struct{} 113 entity, ok := backdata.ByID(key) 114 if !ok { 115 // entity key has already been removed 116 return nil 117 } 118 119 idMapEntity, ok := entity.(model.IdMapEntity) 120 if !ok { 121 return fmt.Errorf("could not assert entity to IdMapEntity") 122 } 123 124 if _, ok := idMapEntity.IDs[id]; !ok { 125 // id has already been removed from the key map 126 return nil 127 } 128 129 // removes map entry associated with key for update 130 if _, removed := backdata.Remove(key); !removed { 131 return fmt.Errorf("potential race condition on removing from identifier map") 132 } 133 134 // removes id from the secondary map of the key 135 delete(idMapEntity.IDs, id) 136 137 if len(idMapEntity.IDs) == 0 { 138 // all ids related to key are removed, so there is no need 139 // to add key back to the idMapEntity 140 return nil 141 } 142 143 // adds the new ids list associated with key to mempool 144 idMapEntity = model.IdMapEntity{ 145 Key: key, 146 IDs: idMapEntity.IDs, 147 } 148 149 if added := backdata.Add(key, idMapEntity); !added { 150 return fmt.Errorf("potential race condition on adding to identifier map") 151 } 152 153 return nil 154 }) 155 156 return err 157 } 158 159 // Size returns number of IdMapEntities in mempool 160 func (i *IdentifierMap) Size() uint { 161 return i.Backend.Size() 162 } 163 164 // Keys returns a list of all keys in the mempool 165 func (i *IdentifierMap) Keys() ([]flow.Identifier, bool) { 166 entities := i.Backend.All() 167 keys := make([]flow.Identifier, 0) 168 for _, entity := range entities { 169 idMapEntity, ok := entity.(model.IdMapEntity) 170 if !ok { 171 return nil, false 172 } 173 keys = append(keys, idMapEntity.Key) 174 } 175 return keys, true 176 }