From c02137bc6f795d490086527e48af7b7c3744dbad Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 20 Feb 2025 10:24:04 +0800 Subject: [PATCH] triedb/pathdb: remove sync pool --- triedb/pathdb/layertree.go | 24 +++++++++++++-- triedb/pathdb/lookup.go | 60 ++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index ef0cd65d6f..eb8b30dfe1 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -31,8 +31,17 @@ import ( // thread-safe to use. However, callers need to ensure the thread-safety // of the referenced layer by themselves. type layerTree struct { - base *diskLayer - layers map[common.Hash]layer + base *diskLayer + layers map[common.Hash]layer + + // descendants is a two-dimensional map where the keys represent + // an ancestor state root, and the values are the state roots of + // all its descendants. + // + // For example: r -> [c1, c2, ..., cn], where c1 through cn are + // the descendants of state r. + // + // This map includes all the existing diff layers and the disk layer. descendants map[common.Hash]map[common.Hash]struct{} lookup *lookup lock sync.RWMutex @@ -152,8 +161,13 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6 tree.lock.Lock() defer tree.lock.Unlock() + // Link the given layer into the layer set tree.layers[l.rootHash()] = l + + // Link the given layer into its ancestors (up to the current disk layer) tree.fillAncestors(l) + + // Link the given layer into the state mutation history tree.lookup.addLayer(l) return nil } @@ -185,6 +199,8 @@ func (tree *layerTree) cap(root common.Hash, layers int) error { tree.layers = map[common.Hash]layer{ base.rootHash(): base, } + // Resets the descendants map, since there's only a single disk layer + // with no descendants. tree.descendants = make(map[common.Hash]map[common.Hash]struct{}) tree.lookup = newLookup(base, tree.isDescendant) return nil @@ -227,7 +243,7 @@ func (tree *layerTree) cap(root common.Hash, layers int) error { // ->C2'->C3'->C4' // // After change: - // Chain: + // Chain: // (a) C3->C4 (HEAD) // (b) C1->C2 // ->C2'->C3'->C4' @@ -291,6 +307,7 @@ func (tree *layerTree) bottom() *diskLayer { // lookupAccount returns the layer that is confirmed to contain the account data // being searched for. func (tree *layerTree) lookupAccount(accountHash common.Hash, state common.Hash) (layer, error) { + // Hold the read lock to prevent the unexpected layer changes tree.lock.RLock() defer tree.lock.RUnlock() @@ -308,6 +325,7 @@ func (tree *layerTree) lookupAccount(accountHash common.Hash, state common.Hash) // lookupStorage returns the layer that is confirmed to contain the storage slot // data being searched for. func (tree *layerTree) lookupStorage(accountHash common.Hash, slotHash common.Hash, state common.Hash) (layer, error) { + // Hold the read lock to prevent the unexpected layer changes tree.lock.RLock() defer tree.lock.RUnlock() diff --git a/triedb/pathdb/lookup.go b/triedb/pathdb/lookup.go index a43621db77..5326989f47 100644 --- a/triedb/pathdb/lookup.go +++ b/triedb/pathdb/lookup.go @@ -25,31 +25,23 @@ import ( "golang.org/x/sync/errgroup" ) -// slicePool is a shared pool of hash slice, for reducing the GC pressure. -var slicePool = sync.Pool{ - New: func() interface{} { - slice := make([]common.Hash, 0, 16) // Pre-allocate a slice with a reasonable capacity. - return &slice - }, -} - -// getSlice obtains the hash slice from the shared pool. -func getSlice() []common.Hash { - slice := *slicePool.Get().(*[]common.Hash) - slice = slice[:0] - return slice -} - -// returnSlice returns the hash slice back to the shared pool for following usage. -func returnSlice(slice []common.Hash) { - slicePool.Put(&slice) -} - // lookup is an internal structure used to efficiently determine the layer in // which a state entry resides. type lookup struct { - accounts map[common.Hash][]common.Hash - storages map[common.Hash]map[common.Hash][]common.Hash + // accounts represents the mutation history for specific accounts. + // The key is the account address hash, and the value is a slice + // of **diff layer** IDs indicating where the account was modified, + // with the order from oldest to newest. + accounts map[common.Hash][]common.Hash + + // storages represents the mutation history for specific storage + // slot. The key is the account address hash and the storage key + // hash, the value is a slice of **diff layer** IDs indicating + // where the slot was modified, with the order from oldest to newest. + storages map[common.Hash]map[common.Hash][]common.Hash + + // descendant is the callback indicating whether the layer with + // given root is a descendant of the one specified by `ancestor`. descendant func(state common.Hash, ancestor common.Hash) bool } @@ -87,9 +79,9 @@ func newLookup(head layer, descendant func(state common.Hash, ancestor common.Ha // If found, the account data corresponding to the supplied stateID resides // in that layer. Otherwise, two scenarios are possible: // -// The account remains unmodified from the current disk layer up to the state -// layer specified by the stateID: fallback to the disk layer for data retrieval. -// Or the layer specified by the stateID is stale: reject the data retrieval. +// (a) the account remains unmodified from the current disk layer up to the state +// layer specified by the stateID: fallback to the disk layer for data retrieval, +// (b) or the layer specified by the stateID is stale: reject the data retrieval. func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base common.Hash) common.Hash { list := l.accounts[accountHash] for i := len(list) - 1; i >= 0; i-- { @@ -114,10 +106,10 @@ func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base c // If found, the storage data corresponding to the supplied stateID resides // in that layer. Otherwise, two scenarios are possible: // -// The storage slot remains unmodified from the current disk layer up to the -// state layer specified by the stateID: fallback to the disk layer for data -// retrieval. Or the layer specified by the stateID is stale: reject the data -// retrieval. +// (a) the storage slot remains unmodified from the current disk layer up to +// the state layer specified by the stateID: fallback to the disk layer for +// data retrieval, (b) or the layer specified by the stateID is stale: reject +// the data retrieval. func (l *lookup) storageTip(accountHash common.Hash, slotHash common.Hash, stateID common.Hash, base common.Hash) common.Hash { subset, exists := l.storages[accountHash] if exists { @@ -159,7 +151,7 @@ func (l *lookup) addLayer(diff *diffLayer) { for accountHash := range diff.states.accountData { list, exists := l.accounts[accountHash] if !exists { - list = getSlice() + list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool } list = append(list, state) l.accounts[accountHash] = list @@ -178,7 +170,7 @@ func (l *lookup) addLayer(diff *diffLayer) { for slotHash := range slots { list, exists := subset[slotHash] if !exists { - list = getSlice() + list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool } list = append(list, state) subset[slotHash] = list @@ -212,7 +204,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error { if i == 0 { list = list[1:] if cap(list) > 1024 { - list = append(getSlice(), list...) + list = append(make([]common.Hash, 0, len(list)), list...) } } else { list = append(list[:i], list[i+1:]...) @@ -227,7 +219,6 @@ func (l *lookup) removeLayer(diff *diffLayer) error { if len(list) != 0 { l.accounts[accountHash] = list } else { - returnSlice(list) delete(l.accounts, accountHash) } } @@ -252,7 +243,7 @@ func (l *lookup) removeLayer(diff *diffLayer) error { if i == 0 { list = list[1:] if cap(list) > 1024 { - list = append(getSlice(), list...) + list = append(make([]common.Hash, 0, len(list)), list...) } } else { list = append(list[:i], list[i+1:]...) @@ -267,7 +258,6 @@ func (l *lookup) removeLayer(diff *diffLayer) error { if len(list) != 0 { subset[slotHash] = list } else { - returnSlice(subset[slotHash]) delete(subset, slotHash) } }