Merge pull request #4681 from filecoin-project/badger-viewable
move to native badger blockstore; leverage zero-copy View() to deserialize in-place
This commit is contained in:
@@ -77,12 +77,12 @@ func MessagePool(lc fx.Lifecycle, sm *stmgr.StateManager, ps *pubsub.PubSub, ds
|
||||
}
|
||||
|
||||
func ChainRawBlockstore(lc fx.Lifecycle, mctx helpers.MetricsCtx, r repo.LockedRepo) (dtypes.ChainRawBlockstore, error) {
|
||||
blocks, err := r.Datastore("/chain")
|
||||
bs, err := r.Blockstore(repo.BlockstoreChain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bs := blockstore.NewBlockstore(blocks)
|
||||
// TODO potentially replace this cached blockstore by a CBOR cache.
|
||||
cbs, err := blockstore.CachedBlockstore(helpers.LifecycleCtx(mctx, lc), bs, blockstore.DefaultCacheOpts())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package repo
|
||||
|
||||
import badgerbs "github.com/filecoin-project/lotus/lib/blockstore/badger"
|
||||
|
||||
// BadgerBlockstoreOptions returns the badger options to apply for the provided
|
||||
// domain.
|
||||
func BadgerBlockstoreOptions(domain BlockstoreDomain, path string, readonly bool) (badgerbs.Options, error) {
|
||||
if domain != BlockstoreChain {
|
||||
return badgerbs.Options{}, ErrInvalidBlockstoreDomain
|
||||
}
|
||||
|
||||
opts := badgerbs.DefaultOptions(path)
|
||||
|
||||
// Due to legacy usage of blockstore.Blockstore, over a datastore, all
|
||||
// blocks are prefixed with this namespace. In the future, this can go away,
|
||||
// in order to shorten keys, but it'll require a migration.
|
||||
opts.Prefix = "/blocks/"
|
||||
|
||||
// Blockstore values are immutable; therefore we do not expect any
|
||||
// conflicts to emerge.
|
||||
opts.DetectConflicts = false
|
||||
|
||||
// This is to optimize the database on close so it can be opened
|
||||
// read-only and efficiently queried. We don't do that and hanging on
|
||||
// stop isn't nice.
|
||||
opts.CompactL0OnClose = false
|
||||
|
||||
// The alternative is "crash on start and tell the user to fix it". This
|
||||
// will truncate corrupt and unsynced data, which we don't guarantee to
|
||||
// persist anyways.
|
||||
opts.Truncate = true
|
||||
|
||||
// We mmap the index and the value logs; this is important to enable
|
||||
// zero-copy value access.
|
||||
opts.ValueLogLoadingMode = badgerbs.MemoryMap
|
||||
opts.TableLoadingMode = badgerbs.MemoryMap
|
||||
|
||||
// Embed only values < 128 bytes in the LSM tree; larger values are stored
|
||||
// in value logs.
|
||||
opts.ValueThreshold = 128
|
||||
|
||||
// Default table size is already 64MiB. This is here to make it explicit.
|
||||
opts.MaxTableSize = 64 << 20
|
||||
|
||||
// NOTE: The chain blockstore doesn't require any GC (blocks are never
|
||||
// deleted). This will change if we move to a tiered blockstore.
|
||||
|
||||
opts.ReadOnly = readonly
|
||||
|
||||
return opts, nil
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/ipfs/go-datastore"
|
||||
fslock "github.com/ipfs/go-fs-lock"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/multiformats/go-base32"
|
||||
@@ -22,6 +23,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
lblockstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
badgerbs "github.com/filecoin-project/lotus/lib/blockstore/badger"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
@@ -257,6 +260,10 @@ type fsLockedRepo struct {
|
||||
dsErr error
|
||||
dsOnce sync.Once
|
||||
|
||||
bs blockstore.Blockstore
|
||||
bsErr error
|
||||
bsOnce sync.Once
|
||||
|
||||
storageLk sync.Mutex
|
||||
configLk sync.Mutex
|
||||
}
|
||||
@@ -279,11 +286,44 @@ func (fsr *fsLockedRepo) Close() error {
|
||||
}
|
||||
}
|
||||
|
||||
// type assertion will return ok=false if fsr.bs is nil altogether.
|
||||
if c, ok := fsr.bs.(io.Closer); ok && c != nil {
|
||||
if err := c.Close(); err != nil {
|
||||
return xerrors.Errorf("could not close blockstore: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = fsr.closer.Close()
|
||||
fsr.closer = nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Blockstore returns a blockstore for the provided data domain.
|
||||
func (fsr *fsLockedRepo) Blockstore(domain BlockstoreDomain) (blockstore.Blockstore, error) {
|
||||
if domain != BlockstoreChain {
|
||||
return nil, ErrInvalidBlockstoreDomain
|
||||
}
|
||||
|
||||
fsr.bsOnce.Do(func() {
|
||||
path := fsr.join(filepath.Join(fsDatastore, "chain"))
|
||||
readonly := fsr.readonly
|
||||
|
||||
opts, err := BadgerBlockstoreOptions(domain, path, readonly)
|
||||
if err != nil {
|
||||
fsr.bsErr = err
|
||||
return
|
||||
}
|
||||
|
||||
bs, err := badgerbs.Open(opts)
|
||||
if err != nil {
|
||||
fsr.bsErr = err
|
||||
}
|
||||
fsr.bs = lblockstore.WrapIDStore(bs)
|
||||
})
|
||||
|
||||
return fsr.bs, fsr.bsErr
|
||||
}
|
||||
|
||||
// join joins path elements with fsr.path
|
||||
func (fsr *fsLockedRepo) join(paths ...string) string {
|
||||
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
||||
|
||||
@@ -16,17 +16,7 @@ import (
|
||||
|
||||
type dsCtor func(path string, readonly bool) (datastore.Batching, error)
|
||||
|
||||
func ChainBadgerOptions() badger.Options {
|
||||
opts := badger.DefaultOptions
|
||||
opts.GcInterval = 0 // disable GC for chain datastore
|
||||
|
||||
opts.Options = dgbadger.DefaultOptions("").WithTruncate(true).
|
||||
WithValueThreshold(128)
|
||||
return opts
|
||||
}
|
||||
|
||||
var fsDatastores = map[string]dsCtor{
|
||||
"chain": chainBadgerDs,
|
||||
"metadata": levelDs,
|
||||
|
||||
// Those need to be fast for large writes... but also need a really good GC :c
|
||||
@@ -35,12 +25,6 @@ var fsDatastores = map[string]dsCtor{
|
||||
"client": badgerDs, // client specific
|
||||
}
|
||||
|
||||
func chainBadgerDs(path string, readonly bool) (datastore.Batching, error) {
|
||||
opts := ChainBadgerOptions()
|
||||
opts.ReadOnly = readonly
|
||||
return badger.NewDatastore(path, &opts)
|
||||
}
|
||||
|
||||
func badgerDs(path string, readonly bool) (datastore.Batching, error) {
|
||||
opts := badger.DefaultOptions
|
||||
opts.ReadOnly = readonly
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
@@ -12,11 +13,26 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// BlockstoreDomain represents the domain of a blockstore.
|
||||
type BlockstoreDomain string
|
||||
|
||||
const (
|
||||
// BlockstoreChain represents the blockstore domain for chain data.
|
||||
// Right now, this includes chain objects (tipsets, blocks, messages), as
|
||||
// well as state. In the future, they may get segregated into different
|
||||
// domains.
|
||||
BlockstoreChain = BlockstoreDomain("chain")
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoAPIEndpoint = errors.New("API not running (no endpoint)")
|
||||
ErrNoAPIToken = errors.New("API token not set")
|
||||
ErrRepoAlreadyLocked = errors.New("repo is already locked (lotus daemon already running)")
|
||||
ErrClosedRepo = errors.New("repo is no longer open")
|
||||
|
||||
// ErrInvalidBlockstoreDomain is returned by LockedRepo#Blockstore() when
|
||||
// an unrecognized domain is requested.
|
||||
ErrInvalidBlockstoreDomain = errors.New("invalid blockstore domain")
|
||||
)
|
||||
|
||||
type Repo interface {
|
||||
@@ -37,6 +53,9 @@ type LockedRepo interface {
|
||||
// Returns datastore defined in this repo.
|
||||
Datastore(namespace string) (datastore.Batching, error)
|
||||
|
||||
// Blockstore returns an IPLD blockstore for the requested domain.
|
||||
Blockstore(domain BlockstoreDomain) (blockstore.Blockstore, error)
|
||||
|
||||
// Returns config in this repo
|
||||
Config() (interface{}, error)
|
||||
SetConfig(func(interface{})) error
|
||||
|
||||
+17
-9
@@ -14,10 +14,10 @@ import (
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
)
|
||||
|
||||
@@ -31,8 +31,9 @@ type MemRepo struct {
|
||||
repoLock chan struct{}
|
||||
token *byte
|
||||
|
||||
datastore datastore.Datastore
|
||||
keystore map[string]types.KeyInfo
|
||||
datastore datastore.Datastore
|
||||
keystore map[string]types.KeyInfo
|
||||
blockstore blockstore.Blockstore
|
||||
|
||||
// given a repo type, produce the default config
|
||||
configF func(t RepoType) interface{}
|
||||
@@ -158,11 +159,11 @@ func NewMemory(opts *MemRepoOptions) *MemRepo {
|
||||
}
|
||||
|
||||
return &MemRepo{
|
||||
repoLock: make(chan struct{}, 1),
|
||||
|
||||
datastore: opts.Ds,
|
||||
configF: opts.ConfigF,
|
||||
keystore: opts.KeyStore,
|
||||
repoLock: make(chan struct{}, 1),
|
||||
blockstore: blockstore.WrapIDStore(blockstore.NewTemporarySync()),
|
||||
datastore: opts.Ds,
|
||||
configF: opts.ConfigF,
|
||||
keystore: opts.KeyStore,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +244,13 @@ func (lmem *lockedMemRepo) Datastore(ns string) (datastore.Batching, error) {
|
||||
return namespace.Wrap(lmem.mem.datastore, datastore.NewKey(ns)), nil
|
||||
}
|
||||
|
||||
func (lmem *lockedMemRepo) Blockstore(domain BlockstoreDomain) (blockstore.Blockstore, error) {
|
||||
if domain != BlockstoreChain {
|
||||
return nil, ErrInvalidBlockstoreDomain
|
||||
}
|
||||
return lmem.mem.blockstore, nil
|
||||
}
|
||||
|
||||
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user