github.com/koko1123/flow-go-1@v0.29.6/module/mempool/stdmap/backend.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package stdmap 4 5 import ( 6 "math" 7 "sync" 8 9 "github.com/koko1123/flow-go-1/model/flow" 10 "github.com/koko1123/flow-go-1/module/mempool" 11 "github.com/koko1123/flow-go-1/module/mempool/stdmap/backdata" 12 _ "github.com/koko1123/flow-go-1/utils/binstat" 13 ) 14 15 // Backend provides synchronized access to a backdata 16 type Backend struct { 17 sync.RWMutex 18 backData mempool.BackData 19 guaranteedCapacity uint 20 batchEject BatchEjectFunc 21 eject EjectFunc 22 ejectionCallbacks []mempool.OnEjection 23 } 24 25 // NewBackend creates a new memory pool backend. 26 // This is using EjectTrueRandomFast() 27 func NewBackend(options ...OptionFunc) *Backend { 28 b := Backend{ 29 backData: backdata.NewMapBackData(), 30 guaranteedCapacity: uint(math.MaxUint32), 31 batchEject: EjectTrueRandomFast, 32 eject: nil, 33 ejectionCallbacks: nil, 34 } 35 for _, option := range options { 36 option(&b) 37 } 38 return &b 39 } 40 41 // Has checks if we already contain the item with the given hash. 42 func (b *Backend) Has(entityID flow.Identifier) bool { 43 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)Has") 44 b.RLock() 45 //binstat.Leave(bs1) 46 47 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Has") 48 //defer binstat.Leave(bs2) 49 defer b.RUnlock() 50 has := b.backData.Has(entityID) 51 return has 52 } 53 54 // Add adds the given item to the pool. 55 func (b *Backend) Add(entity flow.Entity) bool { 56 //bs0 := binstat.EnterTime(binstat.BinStdmap + ".<<lock.(Backend)Add") 57 entityID := entity.ID() // this expensive operation done OUTSIDE of lock :-) 58 //binstat.Leave(bs0) 59 60 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Add") 61 b.Lock() 62 //binstat.Leave(bs1) 63 64 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Add") 65 //defer binstat.Leave(bs2) 66 defer b.Unlock() 67 added := b.backData.Add(entityID, entity) 68 b.reduce() 69 return added 70 } 71 72 // Remove will remove the item with the given hash. 73 func (b *Backend) Remove(entityID flow.Identifier) bool { 74 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Remove") 75 b.Lock() 76 //binstat.Leave(bs1) 77 78 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Remove") 79 //defer binstat.Leave(bs2) 80 defer b.Unlock() 81 _, removed := b.backData.Remove(entityID) 82 return removed 83 } 84 85 // Adjust will adjust the value item using the given function if the given key can be found. 86 // Returns a bool which indicates whether the value was updated. 87 func (b *Backend) Adjust(entityID flow.Identifier, f func(flow.Entity) flow.Entity) (flow.Entity, bool) { 88 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Adjust") 89 b.Lock() 90 //binstat.Leave(bs1) 91 92 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Adjust") 93 //defer binstat.Leave(bs2) 94 defer b.Unlock() 95 entity, wasUpdated := b.backData.Adjust(entityID, f) 96 return entity, wasUpdated 97 } 98 99 // ByID returns the given item from the pool. 100 func (b *Backend) ByID(entityID flow.Identifier) (flow.Entity, bool) { 101 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)ByID") 102 b.RLock() 103 //binstat.Leave(bs1) 104 105 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)ByID") 106 //defer binstat.Leave(bs2) 107 defer b.RUnlock() 108 entity, exists := b.backData.ByID(entityID) 109 return entity, exists 110 } 111 112 // Run executes a function giving it exclusive access to the backdata 113 func (b *Backend) Run(f func(backdata mempool.BackData) error) error { 114 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Run") 115 b.Lock() 116 //binstat.Leave(bs1) 117 118 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Run") 119 //defer binstat.Leave(bs2) 120 defer b.Unlock() 121 err := f(b.backData) 122 b.reduce() 123 return err 124 } 125 126 // Size will return the size of the backend. 127 func (b *Backend) Size() uint { 128 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)Size") 129 b.RLock() 130 //binstat.Leave(bs1) 131 132 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Size") 133 //defer binstat.Leave(bs2) 134 defer b.RUnlock() 135 size := b.backData.Size() 136 return size 137 } 138 139 // Limit returns the maximum number of items allowed in the backend. 140 func (b *Backend) Limit() uint { 141 return b.guaranteedCapacity 142 } 143 144 // All returns all entities from the pool. 145 func (b *Backend) All() []flow.Entity { 146 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)All") 147 b.RLock() 148 //binstat.Leave(bs1) 149 150 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)All") 151 //defer binstat.Leave(bs2) 152 defer b.RUnlock() 153 154 return b.backData.Entities() 155 } 156 157 // Clear removes all entities from the pool. 158 func (b *Backend) Clear() { 159 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".w_lock.(Backend)Clear") 160 b.Lock() 161 //binstat.Leave(bs1) 162 163 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)Clear") 164 //defer binstat.Leave(bs2) 165 defer b.Unlock() 166 b.backData.Clear() 167 } 168 169 // RegisterEjectionCallbacks adds the provided OnEjection callbacks 170 func (b *Backend) RegisterEjectionCallbacks(callbacks ...mempool.OnEjection) { 171 //bs1 := binstat.EnterTime(binstat.BinStdmap + ".r_lock.(Backend)RegisterEjectionCallbacks") 172 b.Lock() 173 //binstat.Leave(bs1) 174 175 //bs2 := binstat.EnterTime(binstat.BinStdmap + ".inlock.(Backend)RegisterEjectionCallbacks") 176 //defer binstat.Leave(bs2) 177 defer b.Unlock() 178 b.ejectionCallbacks = append(b.ejectionCallbacks, callbacks...) 179 } 180 181 // reduce will reduce the size of the kept entities until we are within the 182 // configured memory pool size limit. 183 func (b *Backend) reduce() { 184 //bs := binstat.EnterTime(binstat.BinStdmap + ".??lock.(Backend)reduce") 185 //defer binstat.Leave(bs) 186 187 // we keep reducing the cache size until we are at limit again 188 // this was a loop, but the loop is now in EjectTrueRandomFast() 189 // the ejections are batched, so this call to eject() may not actually 190 // do anything until the batch threshold is reached (currently 128) 191 if b.backData.Size() > b.guaranteedCapacity { 192 // get the key from the eject function 193 // we don't do anything if there is an error 194 if b.batchEject != nil { 195 _ = b.batchEject(b) 196 } else { 197 _, _, _ = b.eject(b) 198 } 199 } 200 }