triedb/pathdb: use channel based slice pool

This commit is contained in:
Gary Rong 2025-02-10 11:38:21 +08:00
parent 4b56cf6107
commit a07beeb2c8
1 changed files with 40 additions and 20 deletions

View File

@ -25,24 +25,42 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
// slicePool is a shared pool of hash slice, for reducing the GC pressure. // slicePool is a pool for hash slice. It is safe for concurrent use.
var slicePool = sync.Pool{ type slicePool struct {
New: func() interface{} { c chan []common.Hash
slice := make([]common.Hash, 0, 16) // Pre-allocate a slice with a reasonable capacity. w int
return &slice
},
} }
// getSlice obtains the hash slice from the shared pool. // newSlicePool creates a new pool for shared hash slice. The sliceCap sets the
func getSlice() []common.Hash { // capacity of newly allocated slices, and the nitems determines how many items
slice := *slicePool.Get().(*[]common.Hash) // the pool will hold, at maximum.
slice = slice[:0] func newSlicePool(sliceCap, nitems int) *slicePool {
return slice return &slicePool{
c: make(chan []common.Hash, nitems),
w: sliceCap,
}
} }
// returnSlice returns the hash slice back to the shared pool for following usage. // get returns a slice. Safe for concurrent use.
func returnSlice(slice []common.Hash) { func (p *slicePool) get() []common.Hash {
slicePool.Put(&slice) select {
case b := <-p.c:
return b[:0]
default:
return make([]common.Hash, 0, p.w)
}
}
// put returns a slice to the pool. Safe for concurrent use. This method
// will ignore slices that are too large (>3x the cap)
func (p *slicePool) put(b []common.Hash) {
if len(b) > 3*p.w {
return
}
select {
case p.c <- b:
default:
}
} }
// lookup is an internal structure used to efficiently determine the layer in // lookup is an internal structure used to efficiently determine the layer in
@ -51,6 +69,7 @@ type lookup struct {
accounts map[common.Hash][]common.Hash accounts map[common.Hash][]common.Hash
storages map[common.Hash]map[common.Hash][]common.Hash storages map[common.Hash]map[common.Hash][]common.Hash
descendant func(state common.Hash, ancestor common.Hash) bool descendant func(state common.Hash, ancestor common.Hash) bool
pool *slicePool
} }
// newLookup initializes the lookup structure. // newLookup initializes the lookup structure.
@ -67,6 +86,7 @@ func newLookup(head layer, descendant func(state common.Hash, ancestor common.Ha
accounts: make(map[common.Hash][]common.Hash), accounts: make(map[common.Hash][]common.Hash),
storages: make(map[common.Hash]map[common.Hash][]common.Hash), storages: make(map[common.Hash]map[common.Hash][]common.Hash),
descendant: descendant, descendant: descendant,
pool: newSlicePool(16, 4096),
} }
// Apply the diff layers from bottom to top // Apply the diff layers from bottom to top
for i := len(layers) - 1; i >= 0; i-- { for i := len(layers) - 1; i >= 0; i-- {
@ -159,7 +179,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
for accountHash := range diff.states.accountData { for accountHash := range diff.states.accountData {
list, exists := l.accounts[accountHash] list, exists := l.accounts[accountHash]
if !exists { if !exists {
list = getSlice() list = l.pool.get()
} }
list = append(list, state) list = append(list, state)
l.accounts[accountHash] = list l.accounts[accountHash] = list
@ -178,7 +198,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
for slotHash := range slots { for slotHash := range slots {
list, exists := subset[slotHash] list, exists := subset[slotHash]
if !exists { if !exists {
list = getSlice() list = l.pool.get()
} }
list = append(list, state) list = append(list, state)
subset[slotHash] = list subset[slotHash] = list
@ -212,7 +232,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
if i == 0 { if i == 0 {
list = list[1:] list = list[1:]
if cap(list) > 1024 { if cap(list) > 1024 {
list = append(getSlice(), list...) list = append(l.pool.get(), list...)
} }
} else { } else {
list = append(list[:i], list[i+1:]...) list = append(list[:i], list[i+1:]...)
@ -227,7 +247,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
if len(list) != 0 { if len(list) != 0 {
l.accounts[accountHash] = list l.accounts[accountHash] = list
} else { } else {
returnSlice(list) l.pool.put(list)
delete(l.accounts, accountHash) delete(l.accounts, accountHash)
} }
} }
@ -252,7 +272,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
if i == 0 { if i == 0 {
list = list[1:] list = list[1:]
if cap(list) > 1024 { if cap(list) > 1024 {
list = append(getSlice(), list...) list = append(l.pool.get(), list...)
} }
} else { } else {
list = append(list[:i], list[i+1:]...) list = append(list[:i], list[i+1:]...)
@ -267,7 +287,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error {
if len(list) != 0 { if len(list) != 0 {
subset[slotHash] = list subset[slotHash] = list
} else { } else {
returnSlice(subset[slotHash]) l.pool.put(subset[slotHash])
delete(subset, slotHash) delete(subset, slotHash)
} }
} }