8e8265d5ea
Re-configuration of Blobovnicza's object size limit must not affect already stored objects. In previous implementation `Blobovnicza` didn't see objects stored in buckets which became too big after size limit re-configuration. For example, lets consider 1st configuration with 64KB size limit for stored objects. Lets assume that we stored object of 64KB size, and re-configured `Blobovnicza` with 32KB limit. After reboot object should be still available, but actually it isn't. This is caused by `Get` operation algorithm which iterates over configured size ranges only, and doesn't process any other existing size bucket. By the way, increasing of the object size limit didn't lead to the problem even in previous implementation. Make `Blobovnicza.Get` method to iterate over all size buckets regardless of current configuration. This covers the described scenario. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
72 lines
1.6 KiB
Go
72 lines
1.6 KiB
Go
package blobovnicza
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
// GetPrm groups the parameters of Get operation.
|
|
type GetPrm struct {
|
|
addr oid.Address
|
|
}
|
|
|
|
// GetRes groups the resulting values of Get operation.
|
|
type GetRes struct {
|
|
obj []byte
|
|
}
|
|
|
|
// SetAddress sets the address of the requested object.
|
|
func (p *GetPrm) SetAddress(addr oid.Address) {
|
|
p.addr = addr
|
|
}
|
|
|
|
// Object returns binary representation of the requested object.
|
|
func (p GetRes) Object() []byte {
|
|
return p.obj
|
|
}
|
|
|
|
// special error for normal bbolt.Tx.ForEach interruption.
|
|
var errInterruptForEach = errors.New("interrupt for-each")
|
|
|
|
// Get reads an object from Blobovnicza by address.
|
|
//
|
|
// Returns any error encountered that
|
|
// did not allow to completely read the object.
|
|
//
|
|
// Returns an error of type apistatus.ObjectNotFound if the requested object is not
|
|
// presented in Blobovnicza.
|
|
func (b *Blobovnicza) Get(prm GetPrm) (GetRes, error) {
|
|
var (
|
|
data []byte
|
|
addrKey = addressKey(prm.addr)
|
|
)
|
|
|
|
if err := b.boltDB.View(func(tx *bbolt.Tx) error {
|
|
return tx.ForEach(func(_ []byte, buck *bbolt.Bucket) error {
|
|
data = buck.Get(addrKey)
|
|
if data == nil {
|
|
return nil
|
|
}
|
|
|
|
data = slice.Copy(data)
|
|
|
|
return errInterruptForEach
|
|
})
|
|
}); err != nil && err != errInterruptForEach {
|
|
return GetRes{}, err
|
|
}
|
|
|
|
if data == nil {
|
|
var errNotFound apistatus.ObjectNotFound
|
|
|
|
return GetRes{}, errNotFound
|
|
}
|
|
|
|
return GetRes{
|
|
obj: data,
|
|
}, nil
|
|
}
|