lotus/blockstore/splitstore/markset_bolt.go

125 lines
2.1 KiB
Go
Raw Normal View History

2021-02-27 10:44:31 +00:00
package splitstore
import (
"sync"
2021-02-27 10:44:31 +00:00
"time"
"golang.org/x/xerrors"
cid "github.com/ipfs/go-cid"
bolt "go.etcd.io/bbolt"
)
const boltMarkSetStaging = 16384
type BoltMarkSetEnv struct {
2021-02-27 10:44:31 +00:00
db *bolt.DB
}
var _ MarkSetEnv = (*BoltMarkSetEnv)(nil)
2021-02-27 10:44:31 +00:00
type BoltMarkSet struct {
2021-02-27 10:44:31 +00:00
db *bolt.DB
bucketId []byte
// cache for batching
mx sync.RWMutex
pend map[string]struct{}
2021-02-27 10:44:31 +00:00
}
var _ MarkSet = (*BoltMarkSet)(nil)
2021-02-27 10:44:31 +00:00
func NewBoltMarkSetEnv(path string) (*BoltMarkSetEnv, error) {
2021-02-27 10:44:31 +00:00
db, err := bolt.Open(path, 0644,
&bolt.Options{
Timeout: 1 * time.Second,
2021-02-27 14:06:33 +00:00
NoSync: true,
2021-02-27 10:44:31 +00:00
})
if err != nil {
return nil, err
}
return &BoltMarkSetEnv{db: db}, nil
2021-02-27 10:44:31 +00:00
}
func (e *BoltMarkSetEnv) Create(name string, hint int64) (MarkSet, error) {
2021-02-27 10:44:31 +00:00
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
2021-02-27 10:44:31 +00:00
}
func (e *BoltMarkSetEnv) Close() error {
2021-02-27 10:44:31 +00:00
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 {
2021-02-27 10:44:31 +00:00
b := tx.Bucket(s.bucketId)
for key := range s.pend {
err := b.Put([]byte(key), markBytes)
if err != nil {
return err
}
}
return nil
2021-02-27 10:44:31 +00:00
})
if err != nil {
return err
}
s.pend = make(map[string]struct{})
return nil
2021-02-27 10:44:31 +00:00
}
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
}
2021-02-27 10:44:31 +00:00
err = s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(s.bucketId)
v := b.Get(key)
2021-02-27 10:44:31 +00:00
result = v != nil
return nil
})
return result, err
}
func (s *BoltMarkSet) Close() error {
2021-02-27 10:44:31 +00:00
return s.db.Update(func(tx *bolt.Tx) error {
return tx.DeleteBucket(s.bucketId)
})
}