get rid of goroutine iteration in tracking store; long live ForEach
This commit is contained in:
parent
a586d42c3b
commit
842ec43c2f
@ -1,7 +1,6 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
@ -20,7 +19,7 @@ type TrackingStore interface {
|
||||
PutBatch([]cid.Cid, abi.ChainEpoch) error
|
||||
Get(cid.Cid) (abi.ChainEpoch, error)
|
||||
Delete(cid.Cid) error
|
||||
Keys(context.Context) (<-chan cid.Cid, error)
|
||||
ForEach(func(cid.Cid, abi.ChainEpoch) error) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
@ -40,9 +39,6 @@ func NewTrackingStore(path string) (TrackingStore, error) {
|
||||
if err = env.SetMaxDBs(1); err != nil {
|
||||
return nil, xerrors.Errorf("failed to set LMDB max dbs: %w", err)
|
||||
}
|
||||
// if err = env.SetMaxReaders(2); err != nil {
|
||||
// return nil, xerrors.Errorf("failed to set LMDB max readers: %w", err)
|
||||
// }
|
||||
|
||||
if st, err := os.Stat(path); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(path, 0777); err != nil {
|
||||
@ -129,47 +125,37 @@ func (s *trackingStore) Delete(cid cid.Cid) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *trackingStore) Keys(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
ch := make(chan cid.Cid)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
func (s *trackingStore) ForEach(f func(cid.Cid, abi.ChainEpoch) error) error {
|
||||
return withMaxReadersRetry(
|
||||
func() error {
|
||||
return s.env.View(func(txn *lmdb.Txn) error {
|
||||
txn.RawRead = true
|
||||
cur, err := txn.OpenCursor(s.db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cur.Close()
|
||||
|
||||
err := withMaxReadersRetry(
|
||||
func() error {
|
||||
return s.env.View(func(txn *lmdb.Txn) error {
|
||||
for {
|
||||
k, v, err := cur.Get(nil, nil, lmdb.Next)
|
||||
if err != nil {
|
||||
if lmdb.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
txn.RawRead = true
|
||||
cur, err := txn.OpenCursor(s.db)
|
||||
return err
|
||||
}
|
||||
|
||||
cid := cid.NewCidV1(cid.Raw, k)
|
||||
epoch := bytesToEpoch(v)
|
||||
|
||||
err = f(cid, epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cur.Close()
|
||||
|
||||
for {
|
||||
k, _, err := cur.Get(nil, nil, lmdb.Next)
|
||||
if err != nil {
|
||||
if lmdb.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- cid.NewCidV1(cid.Raw, k):
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("error iterating over tracking store keys: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *trackingStore) Close() error {
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ledgerwatch/lmdb-go/lmdb"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
@ -369,51 +371,37 @@ func (s *SplitStore) compact() {
|
||||
// Phase 2: sweep cold objects:
|
||||
// - If a cold object is reachable in the hot range, it stays in the hotstore.
|
||||
// - If a cold object is reachable in the cold range, it is moved to the coldstore.
|
||||
// - If a cold object is unreachable, it is deleted.
|
||||
ch, err := s.snoop.Keys(context.Background())
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// - If a cold object is unreachable, it is deleted if GC is enabled, otherwise moved to the coldstore.
|
||||
startSweep := time.Now()
|
||||
log.Info("sweeping cold objects")
|
||||
|
||||
// some stats for logging
|
||||
var stHot, stCold, stDead int
|
||||
|
||||
for cid := range ch {
|
||||
wrEpoch, err := s.snoop.Get(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = s.snoop.ForEach(func(cid cid.Cid, wrEpoch abi.ChainEpoch) error {
|
||||
// is the object stil hot?
|
||||
if wrEpoch > coldEpoch {
|
||||
// yes, stay in the hotstore
|
||||
stHot++
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
// the object is cold -- check whether it is reachable in the hot range
|
||||
mark, err := hotSet.Has(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error checking live mark for %s: %w", cid, err)
|
||||
}
|
||||
|
||||
if mark {
|
||||
// the object is reachable in the hot range, stay in the hotstore
|
||||
stHot++
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
// check whether it is reachable in the cold range
|
||||
mark, err = coldSet.Has(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error checkiing cold set for %s: %w", cid, err)
|
||||
}
|
||||
|
||||
if s.enableGC {
|
||||
@ -421,14 +409,12 @@ func (s *SplitStore) compact() {
|
||||
// the object is reachable in the cold range, move it to the cold store
|
||||
blk, err := s.hot.Get(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error retrieving tracked block %s from hotstore: %w ", cid, err)
|
||||
}
|
||||
|
||||
err = s.cold.Put(blk)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error puting block %s to coldstore: %w", cid, err)
|
||||
}
|
||||
|
||||
stCold++
|
||||
@ -440,14 +426,12 @@ func (s *SplitStore) compact() {
|
||||
// if GC is disabled, we move both cold and dead objects to the coldstore
|
||||
blk, err := s.hot.Get(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error retrieving tracked block %s from hotstore: %w ", cid, err)
|
||||
}
|
||||
|
||||
err = s.cold.Put(blk)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error puting block %s to coldstore: %w", cid, err)
|
||||
}
|
||||
|
||||
if mark {
|
||||
@ -460,16 +444,21 @@ func (s *SplitStore) compact() {
|
||||
// delete the object from the hotstore
|
||||
err = s.hot.DeleteBlock(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error deleting block %s from hotstore: %w", cid, err)
|
||||
}
|
||||
|
||||
// remove the snoop tracking
|
||||
err = s.snoop.Delete(cid)
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
return xerrors.Errorf("error deleting cid %s from tracking store: %w", cid, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// TODO do something better here
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Infow("sweeping done", "took", time.Since(startSweep))
|
||||
|
Loading…
Reference in New Issue
Block a user