Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make chain tipset fetching 1000x faster #5824

Merged
merged 2 commits into from
Mar 16, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 34 additions & 26 deletions pkg/chain/chain_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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
}

Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -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() {
Expand Down