feat: chain: make fetching tipset by height 1000x faster
This commit is contained in:
parent
faedc12531
commit
90c89288b6
@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultChainIndexCacheSize = 32 << 10
|
var DefaultChainIndexCacheSize = 32 << 15
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if s := os.Getenv("LOTUS_CHAIN_INDEX_CACHE"); s != "" {
|
if s := os.Getenv("LOTUS_CHAIN_INDEX_CACHE"); s != "" {
|
||||||
@ -27,7 +27,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ChainIndex struct {
|
type ChainIndex struct {
|
||||||
skipCache *lru.ARCCache
|
indexCacheLk sync.Mutex
|
||||||
|
indexCache map[types.TipSetKey]*lbEntry
|
||||||
|
|
||||||
loadTipSet loadTipSetFunc
|
loadTipSet loadTipSetFunc
|
||||||
|
|
||||||
@ -36,17 +37,14 @@ type ChainIndex struct {
|
|||||||
type loadTipSetFunc func(context.Context, types.TipSetKey) (*types.TipSet, error)
|
type loadTipSetFunc func(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||||
|
|
||||||
func NewChainIndex(lts loadTipSetFunc) *ChainIndex {
|
func NewChainIndex(lts loadTipSetFunc) *ChainIndex {
|
||||||
sc, _ := lru.NewARC(DefaultChainIndexCacheSize)
|
|
||||||
return &ChainIndex{
|
return &ChainIndex{
|
||||||
skipCache: sc,
|
indexCache: make(map[types.TipSetKey]*lbEntry, DefaultChainIndexCacheSize),
|
||||||
loadTipSet: lts,
|
loadTipSet: lts,
|
||||||
skipLength: 20,
|
skipLength: 20,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type lbEntry struct {
|
type lbEntry struct {
|
||||||
ts *types.TipSet
|
|
||||||
parentHeight abi.ChainEpoch
|
|
||||||
targetHeight abi.ChainEpoch
|
targetHeight abi.ChainEpoch
|
||||||
target types.TipSetKey
|
target types.TipSetKey
|
||||||
}
|
}
|
||||||
@ -58,25 +56,36 @@ func (ci *ChainIndex) GetTipsetByHeight(ctx context.Context, from *types.TipSet,
|
|||||||
|
|
||||||
rounded, err := ci.roundDown(ctx, from)
|
rounded, err := ci.roundDown(ctx, from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to round down: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci.indexCacheLk.Lock()
|
||||||
|
defer ci.indexCacheLk.Unlock()
|
||||||
cur := rounded.Key()
|
cur := rounded.Key()
|
||||||
for {
|
for {
|
||||||
cval, ok := ci.skipCache.Get(cur)
|
lbe, ok := ci.indexCache[cur]
|
||||||
if !ok {
|
if !ok {
|
||||||
fc, err := ci.fillCache(ctx, cur)
|
fc, err := ci.fillCache(ctx, cur)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to fill cache: %w", err)
|
||||||
}
|
}
|
||||||
cval = fc
|
lbe = fc
|
||||||
}
|
}
|
||||||
|
|
||||||
lbe := cval.(*lbEntry)
|
if to == lbe.targetHeight {
|
||||||
if lbe.ts.Height() == to || lbe.parentHeight < to {
|
ts, err := ci.loadTipSet(ctx, lbe.target)
|
||||||
return lbe.ts, nil
|
if err != nil {
|
||||||
} else if to > lbe.targetHeight {
|
return nil, xerrors.Errorf("failed to load tipset: %w", err)
|
||||||
return ci.walkBack(ctx, lbe.ts, to)
|
}
|
||||||
|
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
if to > lbe.targetHeight {
|
||||||
|
ts, err := ci.loadTipSet(ctx, cur)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load tipset: %w", err)
|
||||||
|
}
|
||||||
|
return ci.walkBack(ctx, ts, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = lbe.target
|
cur = lbe.target
|
||||||
@ -87,16 +96,17 @@ func (ci *ChainIndex) GetTipsetByHeightWithoutCache(ctx context.Context, from *t
|
|||||||
return ci.walkBack(ctx, from, to)
|
return ci.walkBack(ctx, from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Caller must hold indexCacheLk
|
||||||
func (ci *ChainIndex) fillCache(ctx context.Context, tsk types.TipSetKey) (*lbEntry, error) {
|
func (ci *ChainIndex) fillCache(ctx context.Context, tsk types.TipSetKey) (*lbEntry, error) {
|
||||||
ts, err := ci.loadTipSet(ctx, tsk)
|
ts, err := ci.loadTipSet(ctx, tsk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to load tipset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ts.Height() == 0 {
|
if ts.Height() == 0 {
|
||||||
return &lbEntry{
|
return &lbEntry{
|
||||||
ts: ts,
|
targetHeight: 0,
|
||||||
parentHeight: 0,
|
target: tsk,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,12 +134,10 @@ func (ci *ChainIndex) fillCache(ctx context.Context, tsk types.TipSetKey) (*lbEn
|
|||||||
}
|
}
|
||||||
|
|
||||||
lbe := &lbEntry{
|
lbe := &lbEntry{
|
||||||
ts: ts,
|
|
||||||
parentHeight: parent.Height(),
|
|
||||||
targetHeight: skipTarget.Height(),
|
targetHeight: skipTarget.Height(),
|
||||||
target: skipTarget.Key(),
|
target: skipTarget.Key(),
|
||||||
}
|
}
|
||||||
ci.skipCache.Add(tsk, lbe)
|
ci.indexCache[tsk] = lbe
|
||||||
|
|
||||||
return lbe, nil
|
return lbe, nil
|
||||||
}
|
}
|
||||||
@ -144,7 +152,7 @@ func (ci *ChainIndex) roundDown(ctx context.Context, ts *types.TipSet) (*types.T
|
|||||||
|
|
||||||
rounded, err := ci.walkBack(ctx, ts, target)
|
rounded, err := ci.walkBack(ctx, ts, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to walk back: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rounded, nil
|
return rounded, nil
|
||||||
@ -164,7 +172,7 @@ func (ci *ChainIndex) walkBack(ctx context.Context, from *types.TipSet, to abi.C
|
|||||||
for {
|
for {
|
||||||
pts, err := ci.loadTipSet(ctx, ts.Parents())
|
pts, err := ci.loadTipSet(ctx, ts.Parents())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, xerrors.Errorf("failed to load tipset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if to > pts.Height() {
|
if to > pts.Height() {
|
||||||
|
Loading…
Reference in New Issue
Block a user