keep genesis-linked state hot

This commit is contained in:
vyzo 2021-03-19 12:17:32 +02:00
parent e9f531b4aa
commit 7cf75e667d
2 changed files with 67 additions and 2 deletions

View File

@ -101,6 +101,7 @@ type Config struct {
// ChainAccessor allows the Splitstore to access the chain. It will most likely // ChainAccessor allows the Splitstore to access the chain. It will most likely
// be a ChainStore at runtime. // be a ChainStore at runtime.
type ChainAccessor interface { type ChainAccessor interface {
GetGenesis() (*types.BlockHeader, error)
GetTipsetByHeight(context.Context, abi.ChainEpoch, *types.TipSet, bool) (*types.TipSet, error) GetTipsetByHeight(context.Context, abi.ChainEpoch, *types.TipSet, bool) (*types.TipSet, error)
GetHeaviestTipSet() *types.TipSet GetHeaviestTipSet() *types.TipSet
SubscribeHeadChanges(change func(revert []*types.TipSet, apply []*types.TipSet) error) SubscribeHeadChanges(change func(revert []*types.TipSet, apply []*types.TipSet) error)
@ -127,6 +128,8 @@ type SplitStore struct {
cold bstore.Blockstore cold bstore.Blockstore
tracker TrackingStore tracker TrackingStore
genesis, genesisStateRoot cid.Cid
env MarkSetEnv env MarkSetEnv
markSetSize int64 markSetSize int64
@ -326,6 +329,60 @@ func (s *SplitStore) Start(chain ChainAccessor) error {
s.chain = chain s.chain = chain
s.curTs = chain.GetHeaviestTipSet() s.curTs = chain.GetHeaviestTipSet()
// make sure the genesis and its state root are hot
gb, err := chain.GetGenesis()
if err != nil {
return xerrors.Errorf("error getting genesis: %w", err)
}
s.genesis = gb.Cid()
s.genesisStateRoot = gb.ParentStateRoot
has, err := s.hot.Has(s.genesis)
if err != nil {
return xerrors.Errorf("error checking hotstore for genesis: %w", err)
}
if !has {
blk, err := gb.ToStorageBlock()
if err != nil {
return xerrors.Errorf("error converting genesis block to storage block: %w", err)
}
err = s.hot.Put(blk)
if err != nil {
return xerrors.Errorf("error putting genesis block to hotstore: %w", err)
}
}
err = s.walkLinks(s.genesisStateRoot, cid.NewSet(), func(c cid.Cid) error {
has, err = s.hot.Has(c)
if err != nil {
return xerrors.Errorf("error checking hotstore for genesis state root: %w", err)
}
if !has {
blk, err := s.cold.Get(c)
if err != nil {
if err == bstore.ErrNotFound {
return nil
}
return xerrors.Errorf("error retrieving genesis state linked object from coldstore: %w", err)
}
err = s.hot.Put(blk)
if err != nil {
return xerrors.Errorf("error putting genesis state linked object to hotstore: %w", err)
}
}
return nil
})
if err != nil {
return xerrors.Errorf("error walking genesis state root links: %w", err)
}
// load base epoch from metadata ds // load base epoch from metadata ds
// if none, then use current epoch because it's a fresh start // if none, then use current epoch because it's a fresh start
bs, err := s.ds.Get(baseEpochKey) bs, err := s.ds.Get(baseEpochKey)

View File

@ -149,8 +149,8 @@ func testSplitStore(t *testing.T, cfg *Config) {
t.Errorf("expected %d cold blocks, but got %d", 7, coldCnt) t.Errorf("expected %d cold blocks, but got %d", 7, coldCnt)
} }
if hotCnt != 4 { if hotCnt != 5 {
t.Errorf("expected %d hot blocks, but got %d", 4, hotCnt) t.Errorf("expected %d hot blocks, but got %d", 5, hotCnt)
} }
// Make sure we can revert without panicking. // Make sure we can revert without panicking.
@ -165,6 +165,7 @@ type mockChain struct {
t testing.TB t testing.TB
sync.Mutex sync.Mutex
genesis *types.BlockHeader
tipsets []*types.TipSet tipsets []*types.TipSet
listener func(revert []*types.TipSet, apply []*types.TipSet) error listener func(revert []*types.TipSet, apply []*types.TipSet) error
} }
@ -172,6 +173,9 @@ type mockChain struct {
func (c *mockChain) push(ts *types.TipSet) { func (c *mockChain) push(ts *types.TipSet) {
c.Lock() c.Lock()
c.tipsets = append(c.tipsets, ts) c.tipsets = append(c.tipsets, ts)
if c.genesis == nil {
c.genesis = ts.Blocks()[0]
}
c.Unlock() c.Unlock()
if c.listener != nil { if c.listener != nil {
@ -201,6 +205,10 @@ func (c *mockChain) revert(count int) {
} }
} }
func (c *mockChain) GetGenesis() (*types.BlockHeader, error) {
return c.genesis, nil
}
func (c *mockChain) GetTipsetByHeight(_ context.Context, epoch abi.ChainEpoch, _ *types.TipSet, _ bool) (*types.TipSet, error) { func (c *mockChain) GetTipsetByHeight(_ context.Context, epoch abi.ChainEpoch, _ *types.TipSet, _ bool) (*types.TipSet, error) {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()