add (salted) bloom filter liveset

This commit is contained in:
vyzo 2021-02-28 09:59:11 +02:00
parent aba6530411
commit 97abbe1eca
7 changed files with 107 additions and 18 deletions

View File

@ -3,6 +3,8 @@ package splitstore
import (
"path/filepath"
"golang.org/x/xerrors"
cid "github.com/ipfs/go-cid"
)
@ -19,10 +21,15 @@ type LiveSetEnv interface {
Close() error
}
func NewLiveSetEnv(path string, useLMDB bool) (LiveSetEnv, error) {
if useLMDB {
func NewLiveSetEnv(path string, liveSetType string) (LiveSetEnv, error) {
switch liveSetType {
case "", "bloom":
return NewBloomLiveSetEnv()
case "bolt":
return NewBoltLiveSetEnv(filepath.Join(path, "sweep.bolt"))
case "lmdb":
return NewLMDBLiveSetEnv(filepath.Join(path, "sweep.lmdb"))
default:
return nil, xerrors.Errorf("unknown live set type %s", liveSetType)
}
return NewBoltLiveSetEnv(filepath.Join(path, "sweep.bolt"))
}

View File

@ -0,0 +1,65 @@
package splitstore
import (
"math/rand"
"golang.org/x/xerrors"
bbloom "github.com/ipfs/bbloom"
cid "github.com/ipfs/go-cid"
)
type BloomLiveSetEnv struct{}
var _ LiveSetEnv = (*BloomLiveSetEnv)(nil)
type BloomLiveSet struct {
salt []byte
bf *bbloom.Bloom
}
var _ LiveSet = (*BloomLiveSet)(nil)
func NewBloomLiveSetEnv() (*BloomLiveSetEnv, error) {
return &BloomLiveSetEnv{}, nil
}
func (e *BloomLiveSetEnv) NewLiveSet(name string) (LiveSet, error) {
salt := make([]byte, 4)
_, err := rand.Read(salt)
if err != nil {
return nil, xerrors.Errorf("error reading salt: %w", err)
}
bf, err := bbloom.New(float64(10_000_000), float64(0.01))
if err != nil {
return nil, xerrors.Errorf("error creating bloom filter: %w", err)
}
return &BloomLiveSet{salt: salt, bf: bf}, nil
}
func (e *BloomLiveSetEnv) Close() error {
return nil
}
func (s *BloomLiveSet) saltedKey(cid cid.Cid) []byte {
hash := cid.Hash()
key := make([]byte, len(s.salt)+len(hash))
n := copy(key, s.salt)
copy(key[n:], hash)
return key
}
func (s *BloomLiveSet) Mark(cid cid.Cid) error {
s.bf.Add(s.saltedKey(cid))
return nil
}
func (s *BloomLiveSet) Has(cid cid.Cid) (bool, error) {
return s.bf.Has(s.saltedKey(cid)), nil
}
func (s *BloomLiveSet) Close() error {
return nil
}

View File

@ -3,6 +3,8 @@ package splitstore
import (
"path/filepath"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
cid "github.com/ipfs/go-cid"
)
@ -18,10 +20,13 @@ type TrackingStore interface {
Close() error
}
func NewTrackingStore(path string, useLMDB bool) (TrackingStore, error) {
if useLMDB {
func NewTrackingStore(path string, trackingStoreType string) (TrackingStore, error) {
switch trackingStoreType {
case "", "bolt":
return NewBoltTrackingStore(filepath.Join(path, "snoop.bolt"))
case "lmdb":
return NewLMDBTrackingStore(filepath.Join(path, "snoop.lmdb"))
default:
return nil, xerrors.Errorf("unknown tracking store type %s", trackingStoreType)
}
return NewBoltTrackingStore(filepath.Join(path, "snoop.bolt"))
}

View File

@ -39,8 +39,10 @@ func init() {
}
type Config struct {
// use LMDB for tracking store and liveset instead of BoltDB
UseLMDB bool
// TrackingStore type; bolt (default) or lmdb
TrackingStoreType string
// LiveSet type; bloom (default), bolt, or lmdb
LiveSetType string
// perform full reachability analysis (expensive) for compaction
// You should enable this option if you plan to use the splitstore without a backing coldstore
EnableFullCompaction bool
@ -83,13 +85,13 @@ var _ bstore.Blockstore = (*SplitStore)(nil)
// compaction.
func NewSplitStore(path string, ds dstore.Datastore, cold, hot bstore.Blockstore, cfg *Config) (*SplitStore, error) {
// the tracking store
snoop, err := NewTrackingStore(path, cfg.UseLMDB)
snoop, err := NewTrackingStore(path, cfg.TrackingStoreType)
if err != nil {
return nil, err
}
// the liveset env
env, err := NewLiveSetEnv(path, cfg.UseLMDB)
env, err := NewLiveSetEnv(path, cfg.LiveSetType)
if err != nil {
snoop.Close() //nolint:errcheck
return nil, err

View File

@ -611,10 +611,10 @@ func Repo(r repo.Repo) Option {
Override(new(dtypes.UniversalBlockstore), modules.UniversalBlockstore),
If(cfg.EnableSplitstore,
If(cfg.Splitstore.UseLMDBHotstore,
Override(new(dtypes.HotBlockstore), modules.LMDBHotBlockstore)),
If(!cfg.Splitstore.UseLMDBHotstore,
If(cfg.Splitstore.GetHotStoreType() == "badger",
Override(new(dtypes.HotBlockstore), modules.BadgerHotBlockstore)),
If(cfg.Splitstore.GetHotStoreType() == "lmdb",
Override(new(dtypes.HotBlockstore), modules.LMDBHotBlockstore)),
Override(new(dtypes.SplitBlockstore), modules.SplitBlockstore(cfg)),
Override(new(dtypes.ChainBlockstore), modules.ChainSplitBlockstore),
Override(new(dtypes.StateBlockstore), modules.StateSplitBlockstore),

View File

@ -126,13 +126,22 @@ type Blockstore struct {
}
type Splitstore struct {
UseLMDBHotstore bool
UseLMDBTracking bool
HotStoreType string
TrackingStoreType string
LiveSetType string
EnableFullCompaction bool
EnableGC bool // EXPERIMENTAL
Archival bool
}
func (s *Splitstore) GetHotStoreType() string {
// default is badger
if s.HotStoreType == "" {
return "badger"
}
return s.HotStoreType
}
// // Full Node
type Metrics struct {

View File

@ -105,7 +105,8 @@ func SplitBlockstore(cfg *config.Blockstore) func(lc fx.Lifecycle, r repo.Locked
ss, err := splitstore.NewSplitStore(path, ds, cold, hot,
&splitstore.Config{
UseLMDB: cfg.Splitstore.UseLMDBTracking,
TrackingStoreType: cfg.Splitstore.TrackingStoreType,
LiveSetType: cfg.Splitstore.LiveSetType,
EnableFullCompaction: cfg.Splitstore.EnableFullCompaction,
EnableGC: cfg.Splitstore.EnableGC,
Archival: cfg.Splitstore.Archival,