github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/core/blockstm/mvhashmap.go (about) 1 package blockstm 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/emirpasic/gods/maps/treemap" 8 9 "github.com/ethereum/go-ethereum/common" 10 ) 11 12 const FlagDone = 0 13 const FlagEstimate = 1 14 15 const addressType = 1 16 const stateType = 2 17 const subpathType = 3 18 19 const KeyLength = common.AddressLength + common.HashLength + 2 20 21 type Key [KeyLength]byte 22 23 func (k Key) IsAddress() bool { 24 return k[KeyLength-1] == addressType 25 } 26 27 func (k Key) IsState() bool { 28 return k[KeyLength-1] == stateType 29 } 30 31 func (k Key) IsSubpath() bool { 32 return k[KeyLength-1] == subpathType 33 } 34 35 func (k Key) GetAddress() common.Address { 36 return common.BytesToAddress(k[:common.AddressLength]) 37 } 38 39 func (k Key) GetStateKey() common.Hash { 40 return common.BytesToHash(k[common.AddressLength : KeyLength-2]) 41 } 42 43 func (k Key) GetSubpath() byte { 44 return k[KeyLength-2] 45 } 46 47 func newKey(addr common.Address, hash common.Hash, subpath byte, keyType byte) Key { 48 var k Key 49 50 copy(k[:common.AddressLength], addr.Bytes()) 51 copy(k[common.AddressLength:KeyLength-2], hash.Bytes()) 52 k[KeyLength-2] = subpath 53 k[KeyLength-1] = keyType 54 55 return k 56 } 57 58 func NewAddressKey(addr common.Address) Key { 59 return newKey(addr, common.Hash{}, 0, addressType) 60 } 61 62 func NewStateKey(addr common.Address, hash common.Hash) Key { 63 k := newKey(addr, hash, 0, stateType) 64 if !k.IsState() { 65 panic(fmt.Errorf("key is not a state key")) 66 } 67 68 return k 69 } 70 71 func NewSubpathKey(addr common.Address, subpath byte) Key { 72 return newKey(addr, common.Hash{}, subpath, subpathType) 73 } 74 75 type MVHashMap struct { 76 m sync.Map 77 s sync.Map 78 } 79 80 func MakeMVHashMap() *MVHashMap { 81 return &MVHashMap{} 82 } 83 84 type WriteCell struct { 85 flag uint 86 incarnation int 87 data interface{} 88 } 89 90 type TxnIndexCells struct { 91 rw sync.RWMutex 92 tm *treemap.Map 93 } 94 95 type Version struct { 96 TxnIndex int 97 Incarnation int 98 } 99 100 func (mv *MVHashMap) getKeyCells(k Key, fNoKey func(kenc Key) *TxnIndexCells) (cells *TxnIndexCells) { 101 val, ok := mv.m.Load(k) 102 103 if !ok { 104 cells = fNoKey(k) 105 } else { 106 cells = val.(*TxnIndexCells) 107 } 108 109 return 110 } 111 112 func (mv *MVHashMap) Write(k Key, v Version, data interface{}) { 113 cells := mv.getKeyCells(k, func(kenc Key) (cells *TxnIndexCells) { 114 n := &TxnIndexCells{ 115 rw: sync.RWMutex{}, 116 tm: treemap.NewWithIntComparator(), 117 } 118 cells = n 119 val, _ := mv.m.LoadOrStore(kenc, n) 120 cells = val.(*TxnIndexCells) 121 return 122 }) 123 124 cells.rw.RLock() 125 ci, ok := cells.tm.Get(v.TxnIndex) 126 cells.rw.RUnlock() 127 128 if ok { 129 if ci.(*WriteCell).incarnation > v.Incarnation { 130 panic(fmt.Errorf("existing transaction value does not have lower incarnation: %v, %v", 131 k, v.TxnIndex)) 132 } 133 134 ci.(*WriteCell).flag = FlagDone 135 ci.(*WriteCell).incarnation = v.Incarnation 136 ci.(*WriteCell).data = data 137 } else { 138 cells.rw.Lock() 139 if ci, ok = cells.tm.Get(v.TxnIndex); !ok { 140 cells.tm.Put(v.TxnIndex, &WriteCell{ 141 flag: FlagDone, 142 incarnation: v.Incarnation, 143 data: data, 144 }) 145 } else { 146 ci.(*WriteCell).flag = FlagDone 147 ci.(*WriteCell).incarnation = v.Incarnation 148 ci.(*WriteCell).data = data 149 } 150 cells.rw.Unlock() 151 } 152 } 153 154 func (mv *MVHashMap) ReadStorage(k Key, fallBack func() any) any { 155 data, ok := mv.s.Load(string(k[:])) 156 if !ok { 157 data = fallBack() 158 data, _ = mv.s.LoadOrStore(string(k[:]), data) 159 } 160 161 return data 162 } 163 164 func (mv *MVHashMap) MarkEstimate(k Key, txIdx int) { 165 cells := mv.getKeyCells(k, func(_ Key) *TxnIndexCells { 166 panic(fmt.Errorf("path must already exist")) 167 }) 168 169 cells.rw.RLock() 170 if ci, ok := cells.tm.Get(txIdx); !ok { 171 panic(fmt.Sprintf("should not happen - cell should be present for path. TxIdx: %v, path, %x, cells keys: %v", txIdx, k, cells.tm.Keys())) 172 } else { 173 ci.(*WriteCell).flag = FlagEstimate 174 } 175 cells.rw.RUnlock() 176 } 177 178 func (mv *MVHashMap) Delete(k Key, txIdx int) { 179 cells := mv.getKeyCells(k, func(_ Key) *TxnIndexCells { 180 panic(fmt.Errorf("path must already exist")) 181 }) 182 183 cells.rw.Lock() 184 defer cells.rw.Unlock() 185 cells.tm.Remove(txIdx) 186 } 187 188 const ( 189 MVReadResultDone = 0 190 MVReadResultDependency = 1 191 MVReadResultNone = 2 192 ) 193 194 type MVReadResult struct { 195 depIdx int 196 incarnation int 197 value interface{} 198 } 199 200 func (res *MVReadResult) DepIdx() int { 201 return res.depIdx 202 } 203 204 func (res *MVReadResult) Incarnation() int { 205 return res.incarnation 206 } 207 208 func (res *MVReadResult) Value() interface{} { 209 return res.value 210 } 211 212 func (mvr MVReadResult) Status() int { 213 if mvr.depIdx != -1 { 214 if mvr.incarnation == -1 { 215 return MVReadResultDependency 216 } else { 217 return MVReadResultDone 218 } 219 } 220 221 return MVReadResultNone 222 } 223 224 func (mv *MVHashMap) Read(k Key, txIdx int) (res MVReadResult) { 225 res.depIdx = -1 226 res.incarnation = -1 227 228 cells := mv.getKeyCells(k, func(_ Key) *TxnIndexCells { 229 return nil 230 }) 231 if cells == nil { 232 return 233 } 234 235 cells.rw.RLock() 236 fk, fv := cells.tm.Floor(txIdx - 1) 237 cells.rw.RUnlock() 238 239 if fk != nil && fv != nil { 240 c := fv.(*WriteCell) 241 switch c.flag { 242 case FlagEstimate: 243 res.depIdx = fk.(int) 244 res.value = c.data 245 case FlagDone: 246 { 247 res.depIdx = fk.(int) 248 res.incarnation = c.incarnation 249 res.value = c.data 250 } 251 default: 252 panic(fmt.Errorf("should not happen - unknown flag value")) 253 } 254 } 255 256 return 257 } 258 259 func (mv *MVHashMap) FlushMVWriteSet(writes []WriteDescriptor) { 260 for _, v := range writes { 261 mv.Write(v.Path, v.V, v.Val) 262 } 263 } 264 265 func ValidateVersion(txIdx int, lastInputOutput *TxnInputOutput, versionedData *MVHashMap) (valid bool) { 266 valid = true 267 268 for _, rd := range lastInputOutput.ReadSet(txIdx) { 269 mvResult := versionedData.Read(rd.Path, txIdx) 270 switch mvResult.Status() { 271 case MVReadResultDone: 272 valid = rd.Kind == ReadKindMap && rd.V == Version{ 273 TxnIndex: mvResult.depIdx, 274 Incarnation: mvResult.incarnation, 275 } 276 case MVReadResultDependency: 277 valid = false 278 case MVReadResultNone: 279 valid = rd.Kind == ReadKindStorage // feels like an assertion? 280 default: 281 panic(fmt.Errorf("should not happen - undefined mv read status: %ver", mvResult.Status())) 282 } 283 284 if !valid { 285 break 286 } 287 } 288 289 return 290 }