From 745aacef74c40f4004d2b7c12ae25cc4f644f32e Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Fri, 30 Dec 2022 19:47:21 +0700 Subject: [PATCH] coherent state cache: change btree type (#813) --- go.mod | 13 ++++--- go.sum | 4 +-- kv/kvcache/cache.go | 73 ++++++++++++++++++++++------------------ kv/kvcache/cache_test.go | 3 +- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index 5adf3d478..7ad1fb73a 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,14 @@ module github.com/ledgerwatch/erigon-lib go 1.18 +require ( + github.com/ledgerwatch/interfaces v0.0.0-20221226080656-9ea2ff13ca12 + github.com/ledgerwatch/log/v3 v3.6.0 + github.com/ledgerwatch/secp256k1 v1.0.0 + github.com/ledgerwatch/trackerslist v1.0.0 + github.com/torquem-ch/mdbx-go v0.27.4 +) + require ( github.com/RoaringBitmap/roaring v1.2.1 github.com/VictoriaMetrics/metrics v1.23.0 @@ -15,17 +23,12 @@ require ( 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.1 - github.com/ledgerwatch/interfaces v0.0.0-20221226080656-9ea2ff13ca12 - github.com/ledgerwatch/log/v3 v3.6.0 - github.com/ledgerwatch/secp256k1 v1.0.0 - github.com/ledgerwatch/trackerslist v1.0.0 github.com/matryer/moq v0.3.0 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/quasilyte/go-ruleguard/dsl v0.3.21 github.com/spaolacci/murmur3 v1.1.0 github.com/stretchr/testify v1.8.1 github.com/tidwall/btree v1.5.0 - github.com/torquem-ch/mdbx-go v0.27.0 go.uber.org/atomic v1.10.0 golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 diff --git a/go.sum b/go.sum index e3807bb40..d71bb4df2 100644 --- a/go.sum +++ b/go.sum @@ -381,8 +381,8 @@ github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYms github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/torquem-ch/mdbx-go v0.27.0 h1:FquhRvKL2zweMdk1R6UdOx3h6DiHgJ0+P9yQvSouURI= -github.com/torquem-ch/mdbx-go v0.27.0/go.mod h1:T2fsoJDVppxfAPTLd1svUgH1kpPmeXdPESmroSHcL1E= +github.com/torquem-ch/mdbx-go v0.27.4 h1:XDqtNuCoY6RMqfcyB0pWAPtDavCFxkMjcSUd4g6HelY= +github.com/torquem-ch/mdbx-go v0.27.4/go.mod h1:T2fsoJDVppxfAPTLd1svUgH1kpPmeXdPESmroSHcL1E= github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= diff --git a/kv/kvcache/cache.go b/kv/kvcache/cache.go index de850c4db..1d3d81f06 100644 --- a/kv/kvcache/cache.go +++ b/kv/kvcache/cache.go @@ -27,7 +27,7 @@ import ( "github.com/VictoriaMetrics/metrics" "github.com/c2h5oh/datasize" - "github.com/google/btree" + btree2 "github.com/tidwall/btree" "go.uber.org/atomic" "golang.org/x/crypto/sha3" @@ -120,8 +120,8 @@ type Coherent struct { } type CoherentRoot struct { - cache *btree.BTreeG[*Element] - codeCache *btree.BTreeG[*Element] + cache *btree2.BTreeG[*Element] + codeCache *btree2.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. @@ -177,6 +177,7 @@ func New(cfg CoherentConfig) *Coherent { if cfg.KeepViews == 0 { panic("empty config passed") } + return &Coherent{ roots: map[uint64]*CoherentRoot{}, stateEvict: &ThreadSafeEvictionList{l: NewList()}, @@ -206,8 +207,8 @@ func (c *Coherent) selectOrCreateRoot(versionID uint64) *CoherentRoot { r = &CoherentRoot{ ready: make(chan struct{}), - cache: btree.NewG[*Element](DEGREE, Less), - codeCache: btree.NewG[*Element](DEGREE, Less), + cache: btree2.NewBTreeG[*Element](Less), + codeCache: btree2.NewBTreeG[*Element](Less), } c.roots[versionID] = r return r @@ -229,22 +230,26 @@ func (c *Coherent) advanceRoot(stateVersionID uint64) (r *CoherentRoot) { if prevView, ok := c.roots[stateVersionID-1]; ok && prevView.isCanonical { //log.Info("advance: clone", "from", viewID-1, "to", viewID) - r.cache = prevView.cache.Clone() - r.codeCache = prevView.codeCache.Clone() + r.cache = prevView.cache.Copy() + r.codeCache = prevView.codeCache.Copy() } else { c.stateEvict.Init() c.codeEvict.Init() if r.cache == nil { //log.Info("advance: new", "to", viewID) - r.cache = btree.NewG[*Element](DEGREE, Less) - r.codeCache = btree.NewG[*Element](DEGREE, Less) + r.cache = btree2.NewBTreeG[*Element](Less) + r.codeCache = btree2.NewBTreeG[*Element](Less) } else { - r.cache.Ascend(func(i *Element) bool { - c.stateEvict.PushFront(i) + r.cache.Walk(func(items []*Element) bool { + for _, i := range items { + c.stateEvict.PushFront(i) + } return true }) - r.codeCache.Ascend(func(i *Element) bool { - c.codeEvict.PushFront(i) + r.codeCache.Walk(func(items []*Element) bool { + for _, i := range items { + c.codeEvict.PushFront(i) + } return true }) } @@ -445,7 +450,7 @@ func (c *Coherent) removeOldestCode(r *CoherentRoot) { } func (c *Coherent) add(k, v []byte, r *CoherentRoot, id uint64) *Element { it := &Element{K: k, V: v} - replaced, _ := r.cache.ReplaceOrInsert(it) + replaced, _ := r.cache.Set(it) if c.latestStateVersionID != id { //fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id) return it @@ -464,7 +469,7 @@ func (c *Coherent) add(k, v []byte, r *CoherentRoot, id uint64) *Element { } func (c *Coherent) addCode(k, v []byte, r *CoherentRoot, id uint64) *Element { it := &Element{K: k, V: v} - replaced, _ := r.codeCache.ReplaceOrInsert(it) + replaced, _ := r.codeCache.Set(it) if c.latestStateVersionID != id { //fmt.Printf("add to non-last viewID: %d<%d\n", c.latestViewID, id) return it @@ -527,11 +532,11 @@ func (c *Coherent) ValidateCurrentRoot(ctx context.Context, tx kv.Tx) (*CacheVal clearCache := false - compare := func(cache *btree.BTreeG[*Element], bucket string) (bool, [][]byte, error) { + compare := func(cache *btree2.BTreeG[*Element], bucket string) (bool, [][]byte, error) { keys := make([][]byte, 0) for { - val, ok := cache.DeleteMax() + val, ok := cache.PopMax() if !ok { break } @@ -587,19 +592,19 @@ func (c *Coherent) ValidateCurrentRoot(ctx context.Context, tx kv.Tx) (*CacheVal return result, nil } -func (c *Coherent) cloneCaches(r *CoherentRoot) (cache *btree.BTreeG[*Element], codeCache *btree.BTreeG[*Element]) { +func (c *Coherent) cloneCaches(r *CoherentRoot) (cache *btree2.BTreeG[*Element], codeCache *btree2.BTreeG[*Element]) { c.lock.Lock() defer c.lock.Unlock() - cache = r.cache.Clone() - codeCache = r.codeCache.Clone() + cache = r.cache.Copy() + codeCache = r.codeCache.Copy() return cache, codeCache } func (c *Coherent) clearCaches(r *CoherentRoot) { c.lock.Lock() defer c.lock.Unlock() - r.cache.Clear(false) - r.codeCache.Clear(false) + r.cache.Clear() + r.codeCache.Clear() } type Stat struct { @@ -647,18 +652,20 @@ func AssertCheckValues(ctx context.Context, tx kv.Tx, cache Cache) (int, error) if !ok { return 0, nil } - 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 { - return false + root.cache.Walk(func(items []*Element) bool { + for _, i := range items { + k, v := i.K, i.V + var dbV []byte + dbV, err = tx.GetOne(kv.PlainState, k) + if err != nil { + return false + } + if !bytes.Equal(dbV, v) { + err = fmt.Errorf("key: %x, has different values: %x != %x", k, v, dbV) + return false + } + checked++ } - if !bytes.Equal(dbV, v) { - err = fmt.Errorf("key: %x, has different values: %x != %x", k, v, dbV) - return false - } - checked++ return true }) return checked, err diff --git a/kv/kvcache/cache_test.go b/kv/kvcache/cache_test.go index 5b7805133..520d86b31 100644 --- a/kv/kvcache/cache_test.go +++ b/kv/kvcache/cache_test.go @@ -22,13 +22,12 @@ import ( "sync" "testing" - "github.com/stretchr/testify/require" - "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/gointerfaces" "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/memdb" + "github.com/stretchr/testify/require" ) func TestEvictionInUnexpectedOrder(t *testing.T) {