Skip to content

Commit b066812

Browse files
committed
triedb/pathdb: allocate hash slice from sync pool
1 parent 344d01e commit b066812

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

triedb/pathdb/layertree_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,3 +882,17 @@ func TestStorageLookup(t *testing.T) {
882882
}
883883
}
884884
}
885+
886+
// goos: darwin
887+
// goarch: arm64
888+
// pkg: github.com/ethereum/go-ethereum/triedb/pathdb
889+
// cpu: Apple M1 Pro
890+
// BenchmarkHashList
891+
// BenchmarkHashList-8 52540634 22.61 ns/op 24 B/op 1 allocs/op
892+
func BenchmarkHashList(b *testing.B) {
893+
b.ReportAllocs()
894+
for i := 0; i < b.N; i++ {
895+
l := getHashList()
896+
putHashList(l)
897+
}
898+
}

triedb/pathdb/lookup.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
189189
for accountHash := range diff.states.accountData {
190190
list, exists := l.accounts[accountHash]
191191
if !exists {
192-
list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool
192+
list = getHashList()
193193
}
194194
list = append(list, state)
195195
l.accounts[accountHash] = list
@@ -204,7 +204,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
204204
key := storageKey(accountHash, slotHash)
205205
list, exists := l.storages[key]
206206
if !exists {
207-
list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool
207+
list = getHashList()
208208
}
209209
list = append(list, state)
210210
l.storages[key] = list
@@ -229,7 +229,9 @@ func removeFromList(list []common.Hash, element common.Hash) (bool, []common.Has
229229
// Mitigation: release the array if capacity exceeds threshold.
230230
list = list[1:]
231231
if cap(list) > 1024 {
232-
list = append(make([]common.Hash, 0, len(list)), list...)
232+
newList := append(make([]common.Hash, 0, len(list)), list...)
233+
putHashList(list)
234+
list = newList
233235
}
234236
}
235237
return true, list
@@ -258,6 +260,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
258260
if len(list) != 0 {
259261
l.accounts[accountHash] = list
260262
} else {
263+
putHashList(list)
261264
delete(l.accounts, accountHash)
262265
}
263266
}
@@ -275,6 +278,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
275278
if len(list) != 0 {
276279
l.storages[key] = list
277280
} else {
281+
putHashList(list)
278282
delete(l.storages, key)
279283
}
280284
}
@@ -283,3 +287,24 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
283287
})
284288
return eg.Wait()
285289
}
290+
291+
// hashListPool is not allocation-free. Since a slice header is 24 bytes and
292+
// cannot be stored directly in an interface, interface boxing is involved,
293+
// which typically incurs a 24-byte allocation. This design strikes a balance
294+
// between allocation efficiency and code simplicity. Note that it is possible
295+
// to achieve zero allocations by wrapping the []common.Hash in a struct and
296+
// storing a pointer to that struct in the sync.Pool.
297+
var hashListPool = sync.Pool{
298+
New: func() any {
299+
return make([]common.Hash, 0, 16)
300+
},
301+
}
302+
303+
func getHashList() []common.Hash {
304+
l := hashListPool.Get().([]common.Hash)
305+
return l[:0]
306+
}
307+
308+
func putHashList(l []common.Hash) {
309+
hashListPool.Put(l)
310+
}

0 commit comments

Comments
 (0)