RIP bbolt-backed markset
This commit is contained in:
parent
9dbb2e0abd
commit
451ddf50ab
@ -1,8 +1,6 @@
|
|||||||
package splitstore
|
package splitstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
@ -30,14 +28,12 @@ func OpenMarkSetEnv(path string, mtype string) (MarkSetEnv, error) {
|
|||||||
switch mtype {
|
switch mtype {
|
||||||
case "bloom":
|
case "bloom":
|
||||||
return NewBloomMarkSetEnv(false)
|
return NewBloomMarkSetEnv(false)
|
||||||
case "bloomts":
|
case "bloomts": // thread-safe
|
||||||
return NewBloomMarkSetEnv(true)
|
return NewBloomMarkSetEnv(true)
|
||||||
case "map":
|
case "map":
|
||||||
return NewMapMarkSetEnv(false)
|
return NewMapMarkSetEnv(false)
|
||||||
case "mapts":
|
case "mapts": // thread-safe
|
||||||
return NewMapMarkSetEnv(true)
|
return NewMapMarkSetEnv(true)
|
||||||
case "bolt":
|
|
||||||
return NewBoltMarkSetEnv(filepath.Join(path, "markset.bolt"))
|
|
||||||
default:
|
default:
|
||||||
return nil, xerrors.Errorf("unknown mark set type %s", mtype)
|
return nil, xerrors.Errorf("unknown mark set type %s", mtype)
|
||||||
}
|
}
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
package splitstore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
bolt "go.etcd.io/bbolt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const boltMarkSetStaging = 16384
|
|
||||||
|
|
||||||
type BoltMarkSetEnv struct {
|
|
||||||
db *bolt.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ MarkSetEnv = (*BoltMarkSetEnv)(nil)
|
|
||||||
|
|
||||||
type BoltMarkSet struct {
|
|
||||||
db *bolt.DB
|
|
||||||
bucketId []byte
|
|
||||||
|
|
||||||
// cache for batching
|
|
||||||
mx sync.RWMutex
|
|
||||||
pend map[string]struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ MarkSet = (*BoltMarkSet)(nil)
|
|
||||||
|
|
||||||
func NewBoltMarkSetEnv(path string) (*BoltMarkSetEnv, error) {
|
|
||||||
db, err := bolt.Open(path, 0644,
|
|
||||||
&bolt.Options{
|
|
||||||
Timeout: 1 * time.Second,
|
|
||||||
NoSync: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &BoltMarkSetEnv{db: db}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *BoltMarkSetEnv) Create(name string, hint int64) (MarkSet, error) {
|
|
||||||
bucketId := []byte(name)
|
|
||||||
err := e.db.Update(func(tx *bolt.Tx) error {
|
|
||||||
_, err := tx.CreateBucketIfNotExists(bucketId)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("error creating bolt db bucket %s: %w", name, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &BoltMarkSet{
|
|
||||||
db: e.db,
|
|
||||||
bucketId: bucketId,
|
|
||||||
pend: make(map[string]struct{}),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *BoltMarkSetEnv) Close() error {
|
|
||||||
return e.db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoltMarkSet) Mark(cid cid.Cid) error {
|
|
||||||
s.mx.Lock()
|
|
||||||
defer s.mx.Unlock()
|
|
||||||
|
|
||||||
key := cid.Hash()
|
|
||||||
s.pend[string(key)] = struct{}{}
|
|
||||||
|
|
||||||
if len(s.pend) < boltMarkSetStaging {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := s.db.Batch(func(tx *bolt.Tx) error {
|
|
||||||
b := tx.Bucket(s.bucketId)
|
|
||||||
for key := range s.pend {
|
|
||||||
err := b.Put([]byte(key), markBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.pend = make(map[string]struct{})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoltMarkSet) Has(cid cid.Cid) (result bool, err error) {
|
|
||||||
s.mx.RLock()
|
|
||||||
defer s.mx.RUnlock()
|
|
||||||
|
|
||||||
key := cid.Hash()
|
|
||||||
_, result = s.pend[string(key)]
|
|
||||||
if result {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.db.View(func(tx *bolt.Tx) error {
|
|
||||||
b := tx.Bucket(s.bucketId)
|
|
||||||
v := b.Get(key)
|
|
||||||
result = v != nil
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoltMarkSet) Close() error {
|
|
||||||
return s.db.Update(func(tx *bolt.Tx) error {
|
|
||||||
return tx.DeleteBucket(s.bucketId)
|
|
||||||
})
|
|
||||||
}
|
|
@ -8,8 +8,8 @@ import (
|
|||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBoltMarkSet(t *testing.T) {
|
func TestMapMarkSet(t *testing.T) {
|
||||||
testMarkSet(t, "bolt")
|
testMarkSet(t, "map")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBloomMarkSet(t *testing.T) {
|
func TestBloomMarkSet(t *testing.T) {
|
||||||
|
@ -92,7 +92,8 @@ const (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
// MarkSetType is the type of mark set to use.
|
// MarkSetType is the type of mark set to use.
|
||||||
//
|
//
|
||||||
// Sane values are: "mapts", "bolt" (if you are memory constrained).
|
// Only current sane value is "mapts", but we may add an option for a disk-backed
|
||||||
|
// markset for memory-constrained situations.
|
||||||
MarkSetType string
|
MarkSetType string
|
||||||
|
|
||||||
// DiscardColdBlocks indicates whether to skip moving cold blocks to the coldstore.
|
// DiscardColdBlocks indicates whether to skip moving cold blocks to the coldstore.
|
||||||
|
Loading…
Reference in New Issue
Block a user