From 49a027a7a88cb792361bdc85d5f065d9526e1da5 Mon Sep 17 00:00:00 2001 From: Tiance <1033935631@qq.com> Date: Tue, 14 Mar 2023 17:29:06 +0800 Subject: [PATCH 1/2] feat: make chain tipset fetching 1000x faster --- pkg/chain/chain_index.go | 60 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/pkg/chain/chain_index.go b/pkg/chain/chain_index.go index c6d0c1cc70..572afcd0be 100644 --- a/pkg/chain/chain_index.go +++ b/pkg/chain/chain_index.go @@ -3,17 +3,19 @@ package chain import ( "context" "fmt" + "sync" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/venus/venus-shared/types" - lru "github.com/hashicorp/golang-lru" ) -var DefaultChainIndexCacheSize = 32 << 10 +var DefaultChainIndexCacheSize = 32 << 15 // ChainIndex tipset height index, used to getting tipset by height quickly type ChainIndex struct { //nolint - skipCache *lru.ARCCache + indexCacheLk sync.Mutex + indexCache map[types.TipSetKey]*lbEntry loadTipSet loadTipSetFunc @@ -22,17 +24,14 @@ type ChainIndex struct { //nolint // NewChainIndex return a new chain index with arc cache func NewChainIndex(lts loadTipSetFunc) *ChainIndex { - sc, _ := lru.NewARC(DefaultChainIndexCacheSize) return &ChainIndex{ - skipCache: sc, + indexCache: make(map[types.TipSetKey]*lbEntry, DefaultChainIndexCacheSize), loadTipSet: lts, skipLength: 20, } } type lbEntry struct { - ts *types.TipSet - parentHeight abi.ChainEpoch targetHeight abi.ChainEpoch target types.TipSetKey } @@ -48,26 +47,36 @@ func (ci *ChainIndex) GetTipSetByHeight(ctx context.Context, from *types.TipSet, rounded, err := ci.roundDown(ctx, from) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to round down: %w", err) } + ci.indexCacheLk.Lock() + defer ci.indexCacheLk.Unlock() cur := rounded.Key() - // cur := from.Key() for { - cval, ok := ci.skipCache.Get(cur) + lbe, ok := ci.indexCache[cur] if !ok { fc, err := ci.fillCache(ctx, cur) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to fill cache: %w", err) } - cval = fc + lbe = fc } - lbe := cval.(*lbEntry) - if lbe.ts.Height() == to || lbe.parentHeight < to { - return lbe.ts, nil - } else if to > lbe.targetHeight { - return ci.walkBack(ctx, lbe.ts, to) + if to == lbe.targetHeight { + ts, err := ci.loadTipSet(ctx, lbe.target) + if err != nil { + return nil, fmt.Errorf("failed to load tipset: %w", err) + } + + return ts, nil + } + if to > lbe.targetHeight { + ts, err := ci.loadTipSet(ctx, cur) + if err != nil { + return nil, fmt.Errorf("failed to load tipset: %w", err) + } + return ci.walkBack(ctx, ts, to) } cur = lbe.target @@ -79,16 +88,17 @@ func (ci *ChainIndex) GetTipsetByHeightWithoutCache(ctx context.Context, from *t return ci.walkBack(ctx, from, to) } +// Caller must hold indexCacheLk func (ci *ChainIndex) fillCache(ctx context.Context, tsk types.TipSetKey) (*lbEntry, error) { ts, err := ci.loadTipSet(ctx, tsk) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load tipset: %w", err) } if ts.Height() == 0 { return &lbEntry{ - ts: ts, - parentHeight: 0, + targetHeight: 0, + target: tsk, }, nil } @@ -111,17 +121,15 @@ func (ci *ChainIndex) fillCache(ctx context.Context, tsk types.TipSetKey) (*lbEn } else { skipTarget, err = ci.walkBack(ctx, parent, rheight) if err != nil { - return nil, fmt.Errorf("fillCache walkback: %s", err) + return nil, fmt.Errorf("fillCache walkback: %w", err) } } lbe := &lbEntry{ - ts: ts, - parentHeight: parent.Height(), targetHeight: skipTarget.Height(), target: skipTarget.Key(), } - ci.skipCache.Add(tsk, lbe) + ci.indexCache[tsk] = lbe return lbe, nil } @@ -136,7 +144,7 @@ func (ci *ChainIndex) roundDown(ctx context.Context, ts *types.TipSet) (*types.T rounded, err := ci.walkBack(ctx, ts, target) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to walk back: %w", err) } return rounded, nil @@ -156,7 +164,7 @@ func (ci *ChainIndex) walkBack(ctx context.Context, from *types.TipSet, to abi.C for { pts, err := ci.loadTipSet(ctx, ts.Parents()) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load tipset: %w", err) } if to > pts.Height() { From 02acbd9128741be23e700831ac7fd819352701da Mon Sep 17 00:00:00 2001 From: Tiance <1033935631@qq.com> Date: Thu, 16 Mar 2023 10:13:54 +0800 Subject: [PATCH 2/2] feat: try to reduce the use of memory of ci --- .github/workflows/test.yml | 3 +++ pkg/chain/chain_index.go | 12 ++++++++++++ pkg/chain/chain_index_test.go | 3 ++- pkg/chain/store_test.go | 3 ++- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 705f91a006..4122275d89 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,6 +8,9 @@ on: branches: - '**' +env: + CHAIN_INDEX_CACHE: 2048 + jobs: test: diff --git a/pkg/chain/chain_index.go b/pkg/chain/chain_index.go index 572afcd0be..fe30156481 100644 --- a/pkg/chain/chain_index.go +++ b/pkg/chain/chain_index.go @@ -3,6 +3,8 @@ package chain import ( "context" "fmt" + "os" + "strconv" "sync" "github.com/filecoin-project/go-state-types/abi" @@ -12,6 +14,16 @@ import ( var DefaultChainIndexCacheSize = 32 << 15 +func init() { + if s := os.Getenv("CHAIN_INDEX_CACHE"); s != "" { + lcic, err := strconv.Atoi(s) + if err != nil { + log.Errorf("failed to parse 'CHAIN_INDEX_CACHE' env var: %s", err) + } + DefaultChainIndexCacheSize = lcic + } +} + // ChainIndex tipset height index, used to getting tipset by height quickly type ChainIndex struct { //nolint indexCacheLk sync.Mutex diff --git a/pkg/chain/chain_index_test.go b/pkg/chain/chain_index_test.go index c41f64bd82..b3d2c50f29 100644 --- a/pkg/chain/chain_index_test.go +++ b/pkg/chain/chain_index_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "math/rand" + "os" "testing" "github.com/filecoin-project/go-address" @@ -32,7 +33,7 @@ func TestChainIndex(t *testing.T) { head := links[linksCount-1] - DefaultChainIndexCacheSize = 10 + _ = os.Setenv("CHAIN_INDEX_CACHE", "10") chainIndex := NewChainIndex(builder.GetTipSet) chainIndex.skipLength = 10 diff --git a/pkg/chain/store_test.go b/pkg/chain/store_test.go index 8ef8821cb5..992f06b826 100644 --- a/pkg/chain/store_test.go +++ b/pkg/chain/store_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "math/rand" + "os" "testing" "github.com/filecoin-project/go-address" @@ -397,7 +398,7 @@ func TestLoadTipsetMeta(t *testing.T) { requirePutBlocksToCborStore(t, cst, ts.ToSlice()...) } - chain.DefaultChainIndexCacheSize = 2 + _ = os.Setenv("CHAIN_INDEX_CACHE", "2") chain.DefaultTipsetLruCacheSize = 2 cs := chain.NewStore(ds, bs, genTS.At(0).Cid(), chain.NewMockCirculatingSupplyCalculator())