mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 17:15:18 +00:00
319 lines
6.3 KiB
Go
319 lines
6.3 KiB
Go
|
package store
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/cockroachdb/pebble"
|
||
|
ds "github.com/ipfs/go-datastore"
|
||
|
dsq "github.com/ipfs/go-datastore/query"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// shim structs for go-datastore
|
||
|
type batch struct {
|
||
|
b *transaction
|
||
|
db KVDB
|
||
|
}
|
||
|
|
||
|
type transaction struct {
|
||
|
tx Transaction
|
||
|
}
|
||
|
|
||
|
type PeerstoreDatastore struct {
|
||
|
db KVDB
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
PEERSTORE = 0x06
|
||
|
)
|
||
|
|
||
|
type Peerstore interface {
|
||
|
ds.TxnDatastore
|
||
|
ds.PersistentDatastore
|
||
|
ds.Batching
|
||
|
}
|
||
|
|
||
|
var _ ds.Datastore = (*PeerstoreDatastore)(nil)
|
||
|
var _ ds.TxnDatastore = (*PeerstoreDatastore)(nil)
|
||
|
var _ ds.Txn = (*transaction)(nil)
|
||
|
var _ ds.PersistentDatastore = (*PeerstoreDatastore)(nil)
|
||
|
var _ ds.Batching = (*PeerstoreDatastore)(nil)
|
||
|
var _ ds.Batch = (*batch)(nil)
|
||
|
var _ Peerstore = (*PeerstoreDatastore)(nil)
|
||
|
|
||
|
func NewPeerstoreDatastore(db KVDB) (*PeerstoreDatastore, error) {
|
||
|
ds := PeerstoreDatastore{
|
||
|
db: db,
|
||
|
}
|
||
|
return &ds, nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Put(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
value []byte,
|
||
|
) (err error) {
|
||
|
return d.db.Set(
|
||
|
append([]byte{PEERSTORE}, key.Bytes()...),
|
||
|
value,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Sync(ctx context.Context, prefix ds.Key) error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Get(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (value []byte, err error) {
|
||
|
val, closer, err := d.db.Get(append([]byte{PEERSTORE}, key.Bytes()...))
|
||
|
if err != nil {
|
||
|
if err == pebble.ErrNotFound {
|
||
|
return nil, ds.ErrNotFound
|
||
|
}
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
out := make([]byte, len(val))
|
||
|
copy(out[:], val[:])
|
||
|
closer.Close()
|
||
|
|
||
|
return val, nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Has(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (exists bool, err error) {
|
||
|
if _, err := d.Get(ctx, key); err != nil {
|
||
|
if err == ds.ErrNotFound {
|
||
|
return false, nil
|
||
|
}
|
||
|
return false, errors.Wrap(err, "has")
|
||
|
}
|
||
|
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) GetSize(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (size int, err error) {
|
||
|
return ds.GetBackedSize(ctx, d, key)
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Delete(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (err error) {
|
||
|
return d.db.Delete(append([]byte{PEERSTORE}, key.Bytes()...))
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Query(ctx context.Context, q dsq.Query) (
|
||
|
dsq.Results,
|
||
|
error,
|
||
|
) {
|
||
|
rnge := []byte{PEERSTORE}
|
||
|
|
||
|
qNaive := q
|
||
|
prefix := ds.NewKey(q.Prefix).String()
|
||
|
if prefix != "/" {
|
||
|
rnge = append(rnge, []byte(prefix+"/")...)
|
||
|
qNaive.Prefix = ""
|
||
|
}
|
||
|
|
||
|
i, err := d.db.NewIter(rnge, nil)
|
||
|
if err != nil {
|
||
|
return nil, errors.Wrap(err, "query")
|
||
|
}
|
||
|
|
||
|
next := i.Next
|
||
|
if len(q.Orders) > 0 {
|
||
|
switch q.Orders[0].(type) {
|
||
|
case dsq.OrderByKey, *dsq.OrderByKey:
|
||
|
qNaive.Orders = nil
|
||
|
i.First()
|
||
|
case dsq.OrderByKeyDescending, *dsq.OrderByKeyDescending:
|
||
|
next = func() bool {
|
||
|
next = i.Prev
|
||
|
return i.Last()
|
||
|
}
|
||
|
qNaive.Orders = nil
|
||
|
default:
|
||
|
i.First()
|
||
|
}
|
||
|
} else {
|
||
|
i.First()
|
||
|
}
|
||
|
r := dsq.ResultsFromIterator(q, dsq.Iterator{
|
||
|
Next: func() (dsq.Result, bool) {
|
||
|
if !next() {
|
||
|
return dsq.Result{}, false
|
||
|
}
|
||
|
k := string(i.Key()[1:])
|
||
|
e := dsq.Entry{Key: k, Size: len(i.Value())}
|
||
|
|
||
|
if !q.KeysOnly {
|
||
|
buf := make([]byte, len(i.Value()))
|
||
|
copy(buf, i.Value())
|
||
|
e.Value = buf
|
||
|
}
|
||
|
return dsq.Result{Entry: e}, true
|
||
|
},
|
||
|
Close: func() error {
|
||
|
return i.Close()
|
||
|
},
|
||
|
})
|
||
|
return dsq.NaiveQueryApply(qNaive, r), nil
|
||
|
}
|
||
|
|
||
|
// TODO: get disk usage of peerstore later
|
||
|
func (d *PeerstoreDatastore) DiskUsage(ctx context.Context) (uint64, error) {
|
||
|
return 0, nil
|
||
|
}
|
||
|
|
||
|
// Closing is not done here:
|
||
|
func (d *PeerstoreDatastore) Close() (err error) {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) Batch(ctx context.Context) (ds.Batch, error) {
|
||
|
return &batch{
|
||
|
b: &transaction{tx: d.db.NewBatch()},
|
||
|
db: d.db,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (d *PeerstoreDatastore) NewTransaction(
|
||
|
ctx context.Context,
|
||
|
readOnly bool,
|
||
|
) (ds.Txn, error) {
|
||
|
tx := d.db.NewBatch()
|
||
|
return &transaction{tx}, nil
|
||
|
}
|
||
|
|
||
|
func (b *batch) Put(ctx context.Context, key ds.Key, value []byte) error {
|
||
|
b.b.Put(ctx, key, value)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (b *batch) Commit(ctx context.Context) error {
|
||
|
return b.b.Commit(ctx)
|
||
|
}
|
||
|
|
||
|
func (b *batch) Delete(ctx context.Context, key ds.Key) error {
|
||
|
b.b.Delete(ctx, key)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Commit(ctx context.Context) error {
|
||
|
return t.tx.Commit()
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Discard(ctx context.Context) {
|
||
|
t.tx.Abort()
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Get(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (value []byte, err error) {
|
||
|
b, closer, err := t.tx.Get(append([]byte{PEERSTORE}, key.Bytes()...))
|
||
|
if err != nil {
|
||
|
if err == pebble.ErrNotFound {
|
||
|
return nil, ds.ErrNotFound
|
||
|
}
|
||
|
return nil, errors.Wrap(err, "get")
|
||
|
}
|
||
|
|
||
|
out := make([]byte, len(b))
|
||
|
copy(out[:], b[:])
|
||
|
closer.Close()
|
||
|
|
||
|
return b, nil
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Put(ctx context.Context, key ds.Key, value []byte) error {
|
||
|
return t.tx.Set(append([]byte{PEERSTORE}, key.Bytes()...), value)
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Has(ctx context.Context, key ds.Key) (
|
||
|
exists bool,
|
||
|
err error,
|
||
|
) {
|
||
|
if _, err := t.Get(ctx, key); err != nil {
|
||
|
if errors.Is(err, ErrNotFound) {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
return false, errors.Wrap(err, "has")
|
||
|
}
|
||
|
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func (t *transaction) GetSize(
|
||
|
ctx context.Context,
|
||
|
key ds.Key,
|
||
|
) (size int, err error) {
|
||
|
return ds.GetBackedSize(ctx, t, key)
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Delete(ctx context.Context, key ds.Key) (err error) {
|
||
|
return t.tx.Delete(append([]byte{PEERSTORE}, key.Bytes()...))
|
||
|
}
|
||
|
|
||
|
func (t *transaction) Query(ctx context.Context, q dsq.Query) (
|
||
|
dsq.Results,
|
||
|
error,
|
||
|
) {
|
||
|
rnge := []byte{PEERSTORE}
|
||
|
qNaive := q
|
||
|
prefix := ds.NewKey(q.Prefix).String()
|
||
|
if prefix != "/" {
|
||
|
rnge = append(rnge, []byte(prefix+"/")...)
|
||
|
qNaive.Prefix = ""
|
||
|
}
|
||
|
|
||
|
i, err := t.tx.NewIter(rnge, nil)
|
||
|
if err != nil {
|
||
|
return nil, errors.Wrap(err, "query")
|
||
|
}
|
||
|
|
||
|
next := i.Next
|
||
|
if len(q.Orders) > 0 {
|
||
|
switch q.Orders[0].(type) {
|
||
|
case dsq.OrderByKey, *dsq.OrderByKey:
|
||
|
qNaive.Orders = nil
|
||
|
case dsq.OrderByKeyDescending, *dsq.OrderByKeyDescending:
|
||
|
next = func() bool {
|
||
|
next = i.Prev
|
||
|
return i.Last()
|
||
|
}
|
||
|
qNaive.Orders = nil
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
r := dsq.ResultsFromIterator(q, dsq.Iterator{
|
||
|
Next: func() (dsq.Result, bool) {
|
||
|
if !next() {
|
||
|
return dsq.Result{}, false
|
||
|
}
|
||
|
k := string(i.Key()[1:])
|
||
|
e := dsq.Entry{Key: k, Size: len(i.Value())}
|
||
|
|
||
|
if !q.KeysOnly {
|
||
|
buf := make([]byte, len(i.Value()))
|
||
|
copy(buf, i.Value())
|
||
|
e.Value = buf
|
||
|
}
|
||
|
return dsq.Result{Entry: e}, true
|
||
|
},
|
||
|
Close: func() error {
|
||
|
return i.Close()
|
||
|
},
|
||
|
})
|
||
|
return dsq.NaiveQueryApply(qNaive, r), nil
|
||
|
}
|