diff --git a/go.mod b/go.mod index 7957727f7..4ff54c24f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/flanglet/kanzi-go v1.9.1-0.20211212184056-72dda96261ee github.com/go-stack/stack v1.8.1 github.com/gofrs/flock v0.8.1 - github.com/google/btree v1.0.1 + github.com/google/btree v1.1.2 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/holiman/uint256 v1.2.0 diff --git a/go.sum b/go.sum index 824e4c57f..ff6e87f8d 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= diff --git a/kv/kvcache/cache.go b/kv/kvcache/cache.go index 9d2f08c05..cd06d9807 100644 --- a/kv/kvcache/cache.go +++ b/kv/kvcache/cache.go @@ -99,8 +99,8 @@ type Coherent struct { } type CoherentRoot struct { - cache *btree.BTree - codeCache *btree.BTree + cache *btree.BTreeG[*Element] + codeCache *btree.BTreeG[*Element] ready chan struct{} // close when ready readyChanClosed atomic.Bool // protecting `ready` field from double-close (on unwind). Consumers don't need check this field. @@ -178,8 +178,8 @@ func (c *Coherent) selectOrCreateRoot(viewID ViewID) *CoherentRoot { r = &CoherentRoot{ ready: make(chan struct{}), - cache: btree.New(DEGREE), - codeCache: btree.New(DEGREE), + cache: btree.NewG[*Element](DEGREE, Less), + codeCache: btree.NewG[*Element](DEGREE, Less), } c.roots[viewID] = r return r @@ -202,15 +202,15 @@ func (c *Coherent) advanceRoot(viewID ViewID) (r *CoherentRoot) { c.codeEvict.Init() if r.cache == nil { //log.Info("advance: new", "to", viewID) - r.cache = btree.New(DEGREE) - r.codeCache = btree.New(DEGREE) + r.cache = btree.NewG[*Element](DEGREE, Less) + r.codeCache = btree.NewG[*Element](DEGREE, Less) } else { - r.cache.Ascend(func(i btree.Item) bool { - c.stateEvict.PushFront(i.(*Element)) + r.cache.Ascend(func(i *Element) bool { + c.stateEvict.PushFront(i) return true }) - r.codeCache.Ascend(func(i btree.Item) bool { - c.codeEvict.PushFront(i.(*Element)) + r.codeCache.Ascend(func(i *Element) bool { + c.codeEvict.PushFront(i) return true }) } @@ -309,7 +309,7 @@ func (c *Coherent) View(ctx context.Context, tx kv.Tx) (CacheView, error) { return &CoherentView{viewID: ViewID(tx.ViewID()), tx: tx, cache: c}, nil } -func (c *Coherent) getFromCache(k []byte, id ViewID, code bool) (btree.Item, *CoherentRoot, error) { +func (c *Coherent) getFromCache(k []byte, id ViewID, code bool) (*Element, *CoherentRoot, error) { c.lock.RLock() defer c.lock.RUnlock() r, ok := c.roots[id] @@ -318,14 +318,14 @@ func (c *Coherent) getFromCache(k []byte, id ViewID, code bool) (btree.Item, *Co } isLatest := c.latestViewID == id - var it btree.Item + var it *Element if code { - it = r.codeCache.Get(&Element{K: k}) + it, _ = r.codeCache.Get(&Element{K: k}) } else { - it = r.cache.Get(&Element{K: k}) + it, _ = r.cache.Get(&Element{K: k}) } if it != nil && isLatest { - c.stateEvict.MoveToFront(it.(*Element)) + c.stateEvict.MoveToFront(it) } return it, r, nil @@ -339,7 +339,7 @@ func (c *Coherent) Get(k []byte, tx kv.Tx, id ViewID) ([]byte, error) { if it != nil { //fmt.Printf("from cache: %#x,%x\n", k, it.(*Element).V) c.hits.Inc() - return it.(*Element).V, nil + return it.V, nil } c.miss.Inc() @@ -364,7 +364,7 @@ func (c *Coherent) GetCode(k []byte, tx kv.Tx, id ViewID) ([]byte, error) { if it != nil { //fmt.Printf("from cache: %#x,%x\n", k, it.(*Element).V) c.codeHits.Inc() - return it.(*Element).V, nil + return it.V, nil } c.codeMiss.Inc() @@ -395,13 +395,13 @@ func (c *Coherent) removeOldestCode(r *CoherentRoot) { } func (c *Coherent) add(k, v []byte, r *CoherentRoot, id ViewID) *Element { it := &Element{K: k, V: v} - replaced := r.cache.ReplaceOrInsert(it) + replaced, _ := r.cache.ReplaceOrInsert(it) if c.latestViewID != id { //fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id) return it } if replaced != nil { - c.stateEvict.Remove(replaced.(*Element)) + c.stateEvict.Remove(replaced) } c.stateEvict.PushFront(it) evict := c.stateEvict.Len() > c.cfg.KeysLimit @@ -413,13 +413,13 @@ func (c *Coherent) add(k, v []byte, r *CoherentRoot, id ViewID) *Element { } func (c *Coherent) addCode(k, v []byte, r *CoherentRoot, id ViewID) *Element { it := &Element{K: k, V: v} - replaced := r.codeCache.ReplaceOrInsert(it) + replaced, _ := r.codeCache.ReplaceOrInsert(it) if c.latestViewID != id { //fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id) return it } if replaced != nil { - c.codeEvict.Remove(replaced.(*Element)) + c.codeEvict.Remove(replaced) } c.codeEvict.PushFront(it) evict := c.codeEvict.Len() > c.cfg.CodeKeysLimit @@ -475,8 +475,8 @@ func AssertCheckValues(ctx context.Context, tx kv.Tx, cache Cache) (int, error) if !ok { return 0, nil } - root.cache.Ascend(func(i btree.Item) bool { - k, v := i.(*Element).K, i.(*Element).V + root.cache.Ascend(func(i *Element) bool { + k, v := i.K, i.V var dbV []byte dbV, err = tx.GetOne(kv.PlainState, k) if err != nil { @@ -536,9 +536,7 @@ type Element struct { K, V []byte } -func (e *Element) Less(than btree.Item) bool { - return bytes.Compare(e.K, than.(*Element).K) < 0 -} +func Less(a, b *Element) bool { return bytes.Compare(a.K, b.K) < 0 } type ThreadSafeEvictionList struct { l *List diff --git a/txpool/pool.go b/txpool/pool.go index 5042f163c..e55d2c250 100644 --- a/txpool/pool.go +++ b/txpool/pool.go @@ -266,13 +266,11 @@ func newSender(nonce uint64, balance uint256.Int) *sender { var emptySender = newSender(0, *uint256.NewInt(0)) -type sortByNonce struct{ *metaTx } - -func (i sortByNonce) Less(than btree.Item) bool { - if i.metaTx.Tx.SenderID != than.(sortByNonce).metaTx.Tx.SenderID { - return i.metaTx.Tx.SenderID < than.(sortByNonce).metaTx.Tx.SenderID +func SortByNonceLess(a, b *metaTx) bool { + if a.Tx.SenderID != b.Tx.SenderID { + return a.Tx.SenderID < b.Tx.SenderID } - return i.metaTx.Tx.Nonce < than.(sortByNonce).metaTx.Tx.Nonce + return a.Tx.Nonce < b.Tx.Nonce } func calcProtocolBaseFee(baseFee uint64) uint64 { @@ -333,8 +331,8 @@ func New(newTxs chan types.Hashes, coreDB kv.RoDB, cfg Config, cache kvcache.Cac } byNonce := &BySenderAndNonce{ - tree: btree.New(32), - search: sortByNonce{&metaTx{Tx: &types.TxSlot{}}}, + tree: btree.NewG[*metaTx](32, SortByNonceLess), + search: &metaTx{Tx: &types.TxSlot{}}, senderIDTxnCount: map[uint64]int{}, } tracedSenders := make(map[string]struct{}) @@ -1898,18 +1896,17 @@ func (sc *sendersBatch) onNewBlock(stateChanges *remote.StateChangeBatch, unwind // - All senders stored inside 1 large BTree - because iterate over 1 BTree is faster than over map[senderId]BTree // - sortByNonce used as non-pointer wrapper - because iterate over BTree of pointers is 2x slower type BySenderAndNonce struct { - tree *btree.BTree - search sortByNonce + tree *btree.BTreeG[*metaTx] + search *metaTx senderIDTxnCount map[uint64]int // count of sender's txns in the pool - may differ from nonce } func (b *BySenderAndNonce) nonce(senderID uint64) (nonce uint64, ok bool) { s := b.search - s.metaTx.Tx.SenderID = senderID - s.metaTx.Tx.Nonce = math.MaxUint64 + s.Tx.SenderID = senderID + s.Tx.Nonce = math.MaxUint64 - b.tree.DescendLessOrEqual(s, func(i btree.Item) bool { - mt := i.(sortByNonce).metaTx + b.tree.DescendLessOrEqual(s, func(mt *metaTx) bool { if mt.Tx.SenderID == senderID { nonce = mt.Tx.Nonce ok = true @@ -1919,17 +1916,15 @@ func (b *BySenderAndNonce) nonce(senderID uint64) (nonce uint64, ok bool) { return nonce, ok } func (b *BySenderAndNonce) ascendAll(f func(*metaTx) bool) { - b.tree.Ascend(func(i btree.Item) bool { - mt := i.(sortByNonce).metaTx + b.tree.Ascend(func(mt *metaTx) bool { return f(mt) }) } func (b *BySenderAndNonce) ascend(senderID uint64, f func(*metaTx) bool) { s := b.search - s.metaTx.Tx.SenderID = senderID - s.metaTx.Tx.Nonce = 0 - b.tree.AscendGreaterOrEqual(s, func(i btree.Item) bool { - mt := i.(sortByNonce).metaTx + s.Tx.SenderID = senderID + s.Tx.Nonce = 0 + b.tree.AscendGreaterOrEqual(s, func(mt *metaTx) bool { if mt.Tx.SenderID != senderID { return false } @@ -1938,10 +1933,9 @@ func (b *BySenderAndNonce) ascend(senderID uint64, f func(*metaTx) bool) { } func (b *BySenderAndNonce) descend(senderID uint64, f func(*metaTx) bool) { s := b.search - s.metaTx.Tx.SenderID = senderID - s.metaTx.Tx.Nonce = math.MaxUint64 - b.tree.DescendLessOrEqual(s, func(i btree.Item) bool { - mt := i.(sortByNonce).metaTx + s.Tx.SenderID = senderID + s.Tx.Nonce = math.MaxUint64 + b.tree.DescendLessOrEqual(s, func(mt *metaTx) bool { if mt.Tx.SenderID != senderID { return false } @@ -1961,21 +1955,20 @@ func (b *BySenderAndNonce) hasTxs(senderID uint64) bool { } func (b *BySenderAndNonce) get(senderID, txNonce uint64) *metaTx { s := b.search - s.metaTx.Tx.SenderID = senderID - s.metaTx.Tx.Nonce = txNonce - if found := b.tree.Get(s); found != nil { - return found.(sortByNonce).metaTx + s.Tx.SenderID = senderID + s.Tx.Nonce = txNonce + if found, ok := b.tree.Get(s); ok { + return found } return nil } //nolint func (b *BySenderAndNonce) has(mt *metaTx) bool { - found := b.tree.Get(sortByNonce{mt}) - return found != nil + return b.tree.Has(mt) } func (b *BySenderAndNonce) delete(mt *metaTx) { - if b.tree.Delete(sortByNonce{mt}) != nil { + if _, ok := b.tree.Delete(mt); ok { senderID := mt.Tx.SenderID count := b.senderIDTxnCount[senderID] if count > 1 { @@ -1986,9 +1979,9 @@ func (b *BySenderAndNonce) delete(mt *metaTx) { } } func (b *BySenderAndNonce) replaceOrInsert(mt *metaTx) *metaTx { - it := b.tree.ReplaceOrInsert(sortByNonce{mt}) - if it != nil { - return it.(sortByNonce).metaTx + it, ok := b.tree.ReplaceOrInsert(mt) + if ok { + return it } b.senderIDTxnCount[mt.Tx.SenderID]++ return nil