[#791] blobovnicza: Implement method to iterate over object addresses

In previous implementation `Blobovnicza.Iterate` op decoded object data only
and passed it to the handler. There is a need to iterate over all addresses
of the stored objects.

Add `DecodeAddresses` and `WithoutData` methods of `IteratePrm` type. Add
`Address` method to `IterationElement` type. Make `Iterate` to decode object
addresses if `DecodeAddress` was called and not read the data if
`WithoutData` was called. Implement `IterateAddresses` helper function to
simplify the code.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-09-14 17:14:25 +03:00 committed by Leonard Lyubich
parent 8c59ade4ed
commit 5e2ca0d04b
2 changed files with 59 additions and 3 deletions

View file

@ -3,6 +3,7 @@ package blobovnicza
import (
"fmt"
"github.com/nspcc-dev/neofs-api-go/pkg/object"
"go.etcd.io/bbolt"
)
@ -58,6 +59,8 @@ func max(a, b uint64) uint64 {
// IterationElement represents a unit of elements through which Iterate operation passes.
type IterationElement struct {
addr *object.Address
data []byte
}
@ -66,14 +69,33 @@ func (x IterationElement) ObjectData() []byte {
return x.data
}
// Address returns address of the stored object.
func (x IterationElement) Address() *object.Address {
return x.addr
}
// IterationHandler is a generic processor of IterationElement.
type IterationHandler func(IterationElement) error
// IteratePrm groups the parameters of Iterate operation.
type IteratePrm struct {
decodeAddresses bool
withoutData bool
handler IterationHandler
}
// DecodeAddresses sets flag to unmarshal object addresses.
func (x *IteratePrm) DecodeAddresses() {
x.decodeAddresses = true
}
// WithoutData sets flag to not read data of the objects.
func (x *IteratePrm) WithoutData() {
x.withoutData = true
}
// SetHandler sets handler to be called iteratively.
func (x *IteratePrm) SetHandler(h IterationHandler) {
x.handler = h
@ -83,8 +105,9 @@ func (x *IteratePrm) SetHandler(h IterationHandler) {
type IterateRes struct {
}
// Iterate goes through all stored objects, and passes their headers
// to parameterized handler until error return.
// Iterate goes through all stored objects, and passes IterationElement to parameterized handler until error return.
//
// Decodes object addresses if DecodeAddresses was called. Don't read object data if WithoutData was called.
//
// Returns handler's errors directly. Returns nil after iterating finish.
//
@ -95,7 +118,20 @@ func (b *Blobovnicza) Iterate(prm IteratePrm) (*IterateRes, error) {
if err := b.boltDB.View(func(tx *bbolt.Tx) error {
return b.iterateBuckets(tx, func(lower, upper uint64, buck *bbolt.Bucket) (bool, error) {
err := buck.ForEach(func(k, v []byte) error {
elem.data = v
if prm.decodeAddresses {
if elem.addr == nil {
elem.addr = object.NewAddress()
}
if err := addressFromKey(elem.addr, k); err != nil {
return fmt.Errorf("could not decode address key: %w", err)
}
}
if !prm.withoutData {
elem.data = v
}
return prm.handler(elem)
})
@ -120,3 +156,19 @@ func IterateObjects(blz *Blobovnicza, f func([]byte) error) error {
return err
}
// IterateAddresses is a helper function which iterates over Blobovnicza and passes addresses of the objects to f.
func IterateAddresses(blz *Blobovnicza, f func(*object.Address) error) error {
var prm IteratePrm
prm.DecodeAddresses()
prm.WithoutData()
prm.SetHandler(func(elem IterationElement) error {
return f(elem.Address())
})
_, err := blz.Iterate(prm)
return err
}

View file

@ -87,3 +87,7 @@ func (b *Blobovnicza) Put(prm *PutPrm) (*PutRes, error) {
func addressKey(addr *objectSDK.Address) []byte {
return []byte(addr.String())
}
func addressFromKey(dst *objectSDK.Address, data []byte) error {
return dst.Parse(string(data))
}