mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-07 21:47:02 +09:00
135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package badgerfilestore
|
|
|
|
import (
|
|
"context"
|
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonfile/fileblockstore"
|
|
"github.com/dgraph-io/badger/v3"
|
|
blocks "github.com/ipfs/go-block-format"
|
|
"github.com/ipfs/go-cid"
|
|
format "github.com/ipfs/go-ipld-format"
|
|
)
|
|
|
|
const keyPrefix = "files/blocks/"
|
|
|
|
func NewBadgerStorage(db *badger.DB) fileblockstore.BlockStoreLocal {
|
|
return &badgerStorage{db: db}
|
|
}
|
|
|
|
type badgerStorage struct {
|
|
db *badger.DB
|
|
}
|
|
|
|
func (f *badgerStorage) Get(ctx context.Context, k cid.Cid) (b blocks.Block, err error) {
|
|
err = f.db.View(func(txn *badger.Txn) (e error) {
|
|
it, e := txn.Get(key(k))
|
|
if e != nil {
|
|
return e
|
|
}
|
|
if b, e = blockFromItem(it); e != nil {
|
|
return e
|
|
}
|
|
return
|
|
})
|
|
if err == badger.ErrKeyNotFound {
|
|
err = &format.ErrNotFound{Cid: k}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (f *badgerStorage) GetMany(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
|
|
var res = make(chan blocks.Block)
|
|
go func() {
|
|
defer close(res)
|
|
_ = f.db.View(func(txn *badger.Txn) error {
|
|
// TODO: log errors
|
|
for _, k := range ks {
|
|
it, gerr := txn.Get(key(k))
|
|
if gerr != nil {
|
|
return gerr
|
|
}
|
|
b, berr := blockFromItem(it)
|
|
if berr != nil {
|
|
return berr
|
|
}
|
|
res <- b
|
|
}
|
|
return nil
|
|
})
|
|
}()
|
|
return res
|
|
}
|
|
|
|
func (f *badgerStorage) Add(ctx context.Context, bs []blocks.Block) error {
|
|
return f.db.Update(func(txn *badger.Txn) error {
|
|
for _, b := range bs {
|
|
if err := txn.Set(key(b.Cid()), b.RawData()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (f *badgerStorage) Delete(ctx context.Context, c cid.Cid) error {
|
|
return f.db.Update(func(txn *badger.Txn) error {
|
|
return txn.Delete(key(c))
|
|
})
|
|
}
|
|
|
|
func (f *badgerStorage) ExistsCids(ctx context.Context, ks []cid.Cid) (exists []cid.Cid, err error) {
|
|
err = f.db.View(func(txn *badger.Txn) error {
|
|
for _, k := range ks {
|
|
_, e := txn.Get(key(k))
|
|
if e == nil {
|
|
exists = append(exists, k)
|
|
} else if e != badger.ErrKeyNotFound {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
return
|
|
}
|
|
|
|
func (f *badgerStorage) NotExistsBlocks(ctx context.Context, bs []blocks.Block) (notExists []blocks.Block, err error) {
|
|
notExists = bs[:0]
|
|
err = f.db.View(func(txn *badger.Txn) error {
|
|
for _, b := range bs {
|
|
_, e := txn.Get(key(b.Cid()))
|
|
if e == badger.ErrKeyNotFound {
|
|
notExists = append(notExists, b)
|
|
} else if e != nil {
|
|
return e
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
return
|
|
}
|
|
|
|
func key(c cid.Cid) []byte {
|
|
return []byte(keyPrefix + c.String())
|
|
}
|
|
|
|
func parseCID(key []byte) (cid.Cid, error) {
|
|
if len(key) <= len(keyPrefix) {
|
|
return cid.Cid{}, errInvalidKey
|
|
}
|
|
return cid.Decode(string(key[len(keyPrefix):]))
|
|
}
|
|
|
|
func blockFromItem(it *badger.Item) (b blocks.Block, err error) {
|
|
c, err := parseCID(it.Key())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = it.Value(func(val []byte) error {
|
|
if b, err = blocks.NewBlockWithCid(val, c); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|