forked from TrueCloudLab/frostfs-node
[#1247] object: Return NOT_FOUND
and ALREADY_REMOVED
statuses
Replace `ErrNotFound`/`ErrAlreadyRemoved` error from `pkg/core/object` package with `ObjectNotFound`/`ObjectAlreadyRemoved` one from `apistatus` package. These errors are returned by storage node's server as NeoFS API statuses. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
f32c9670ad
commit
70ffdf3478
49 changed files with 348 additions and 178 deletions
|
@ -2,13 +2,6 @@ package object
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
// ErrNotFound is a basic "not found" error returned by
|
|
||||||
// object read functions.
|
|
||||||
var ErrNotFound = errors.New("object not found")
|
|
||||||
|
|
||||||
// ErrRangeOutOfBounds is a basic error of violation of the boundaries of the
|
// ErrRangeOutOfBounds is a basic error of violation of the boundaries of the
|
||||||
// payload of an object.
|
// payload of an object.
|
||||||
var ErrRangeOutOfBounds = errors.New("payload range is out of bounds")
|
var ErrRangeOutOfBounds = errors.New("payload range is out of bounds")
|
||||||
|
|
||||||
// ErrAlreadyRemoved returned when object has tombstone in graveyard.
|
|
||||||
var ErrAlreadyRemoved = errors.New("object already removed")
|
|
||||||
|
|
|
@ -7,12 +7,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
coreObject "github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
neofsapiclient "github.com/nspcc-dev/neofs-node/pkg/innerring/internal/client"
|
neofsapiclient "github.com/nspcc-dev/neofs-node/pkg/innerring/internal/client"
|
||||||
auditproc "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
|
auditproc "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/cache"
|
"github.com/nspcc-dev/neofs-node/pkg/network/cache"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/audit"
|
"github.com/nspcc-dev/neofs-node/pkg/services/audit"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -60,6 +60,8 @@ func (c *ClientCache) Get(info clientcore.NodeInfo) (clientcore.Client, error) {
|
||||||
|
|
||||||
// GetSG polls the container from audit task to get the object by id.
|
// GetSG polls the container from audit task to get the object by id.
|
||||||
// Returns storage groups structure from received object.
|
// Returns storage groups structure from received object.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if storage group is missing.
|
||||||
func (c *ClientCache) GetSG(task *audit.Task, id *oidSDK.ID) (*storagegroup.StorageGroup, error) {
|
func (c *ClientCache) GetSG(task *audit.Task, id *oidSDK.ID) (*storagegroup.StorageGroup, error) {
|
||||||
sgAddress := new(addressSDK.Address)
|
sgAddress := new(addressSDK.Address)
|
||||||
sgAddress.SetContainerID(task.ContainerID())
|
sgAddress.SetContainerID(task.ContainerID())
|
||||||
|
@ -115,7 +117,9 @@ func (c *ClientCache) getSG(ctx context.Context, addr *addressSDK.Address, nm *n
|
||||||
return sg, nil
|
return sg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, coreObject.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeader requests node from the container under audit to return object header by id.
|
// GetHeader requests node from the container under audit to return object header by id.
|
||||||
|
|
|
@ -167,6 +167,9 @@ func (s settlementDeps) ContainerNodes(e uint64, cid *cid.ID) ([]common.NodeInfo
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SGInfo returns audit.SGInfo by object address.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if storage group is missing.
|
||||||
func (s settlementDeps) SGInfo(addr *addressSDK.Address) (audit.SGInfo, error) {
|
func (s settlementDeps) SGInfo(addr *addressSDK.Address) (audit.SGInfo, error) {
|
||||||
cn, nm, err := s.buildContainer(0, addr.ContainerID())
|
cn, nm, err := s.buildContainer(0, addr.ContainerID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -34,7 +33,7 @@ func testAddress() *addressSDK.Address {
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPutGet(t *testing.T, blz *Blobovnicza, sz uint64, expPut, expGet error) *addressSDK.Address {
|
func testPutGet(t *testing.T, blz *Blobovnicza, sz uint64, assertErrPut, assertErrGet func(error) bool) *addressSDK.Address {
|
||||||
// create binary object
|
// create binary object
|
||||||
data := make([]byte, sz)
|
data := make([]byte, sz)
|
||||||
|
|
||||||
|
@ -45,26 +44,34 @@ func testPutGet(t *testing.T, blz *Blobovnicza, sz uint64, expPut, expGet error)
|
||||||
pPut.SetAddress(addr)
|
pPut.SetAddress(addr)
|
||||||
pPut.SetMarshaledObject(data)
|
pPut.SetMarshaledObject(data)
|
||||||
_, err := blz.Put(pPut)
|
_, err := blz.Put(pPut)
|
||||||
require.True(t, errors.Is(err, expPut))
|
if assertErrPut != nil {
|
||||||
|
require.True(t, assertErrPut(err))
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
if expPut != nil {
|
if assertErrPut != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
testGet(t, blz, addr, data, expGet)
|
testGet(t, blz, addr, data, assertErrGet)
|
||||||
|
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGet(t *testing.T, blz *Blobovnicza, addr *addressSDK.Address, expObj []byte, expErr error) {
|
func testGet(t *testing.T, blz *Blobovnicza, addr *addressSDK.Address, expObj []byte, assertErr func(error) bool) {
|
||||||
pGet := new(GetPrm)
|
pGet := new(GetPrm)
|
||||||
pGet.SetAddress(addr)
|
pGet.SetAddress(addr)
|
||||||
|
|
||||||
// try to read object from Blobovnicza
|
// try to read object from Blobovnicza
|
||||||
res, err := blz.Get(pGet)
|
res, err := blz.Get(pGet)
|
||||||
require.True(t, errors.Is(err, expErr))
|
if assertErr != nil {
|
||||||
|
require.True(t, assertErr(err))
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
if expErr == nil {
|
if assertErr == nil {
|
||||||
require.Equal(t, expObj, res.Object())
|
require.Equal(t, expObj, res.Object())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +101,7 @@ func TestBlobovnicza(t *testing.T) {
|
||||||
require.NoError(t, blz.Init())
|
require.NoError(t, blz.Init())
|
||||||
|
|
||||||
// try to read non-existent address
|
// try to read non-existent address
|
||||||
testGet(t, blz, testAddress(), nil, object.ErrNotFound)
|
testGet(t, blz, testAddress(), nil, IsErrNotFound)
|
||||||
|
|
||||||
filled := uint64(15 * 1 << 10)
|
filled := uint64(15 * 1 << 10)
|
||||||
|
|
||||||
|
@ -109,7 +116,7 @@ func TestBlobovnicza(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// should return 404
|
// should return 404
|
||||||
testGet(t, blz, addr, nil, object.ErrNotFound)
|
testGet(t, blz, addr, nil, IsErrNotFound)
|
||||||
|
|
||||||
// fill Blobovnicza fully
|
// fill Blobovnicza fully
|
||||||
for ; filled < sizeLim; filled += objSizeLim {
|
for ; filled < sizeLim; filled += objSizeLim {
|
||||||
|
@ -117,7 +124,9 @@ func TestBlobovnicza(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// from now objects should not be saved
|
// from now objects should not be saved
|
||||||
testPutGet(t, blz, 1024, ErrFull, nil)
|
testPutGet(t, blz, 1024, func(err error) bool {
|
||||||
|
return errors.Is(err, ErrFull)
|
||||||
|
}, nil)
|
||||||
|
|
||||||
require.NoError(t, blz.Close())
|
require.NoError(t, blz.Close())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package blobovnicza
|
package blobovnicza
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -26,7 +26,7 @@ func (p *DeletePrm) SetAddress(addr *addressSDK.Address) {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely delete the object.
|
// did not allow to completely delete the object.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if the object to be deleted is not in blobovnicza.
|
// Returns apistatus.ObjectNotFound if the object to be deleted is not in blobovnicza.
|
||||||
//
|
//
|
||||||
// Should not be called in read-only configuration.
|
// Should not be called in read-only configuration.
|
||||||
func (b *Blobovnicza) Delete(prm *DeletePrm) (*DeleteRes, error) {
|
func (b *Blobovnicza) Delete(prm *DeletePrm) (*DeleteRes, error) {
|
||||||
|
@ -65,7 +65,9 @@ func (b *Blobovnicza) Delete(prm *DeletePrm) (*DeleteRes, error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if err == nil && !removed {
|
if err == nil && !removed {
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
13
pkg/local_object_storage/blobovnicza/errors.go
Normal file
13
pkg/local_object_storage/blobovnicza/errors.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package blobovnicza
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrNotFound checks if error returned by Blobovnicza Get/Delete method
|
||||||
|
// corresponds to missing object.
|
||||||
|
func IsErrNotFound(err error) bool {
|
||||||
|
return errors.As(err, new(apistatus.ObjectNotFound))
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package blobovnicza
|
package blobovnicza
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -32,7 +32,7 @@ func (p *GetRes) Object() []byte {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object.
|
// did not allow to completely read the object.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if requested object is not
|
// Returns apistatus.ObjectNotFound if requested object is not
|
||||||
// presented in Blobovnicza.
|
// presented in Blobovnicza.
|
||||||
func (b *Blobovnicza) Get(prm *GetPrm) (*GetRes, error) {
|
func (b *Blobovnicza) Get(prm *GetPrm) (*GetRes, error) {
|
||||||
var (
|
var (
|
||||||
|
@ -60,7 +60,9 @@ func (b *Blobovnicza) Get(prm *GetPrm) (*GetRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return &GetRes{
|
return &GetRes{
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
||||||
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -224,7 +225,7 @@ func (b *blobovniczas) get(prm *GetSmallPrm) (res *GetSmallRes, err error) {
|
||||||
|
|
||||||
res, err = b.getObjectFromLevel(bPrm, p, !ok)
|
res, err = b.getObjectFromLevel(bPrm, p, !ok)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, object.ErrNotFound) {
|
if !blobovnicza.IsErrNotFound(err) {
|
||||||
b.log.Debug("could not get object from level",
|
b.log.Debug("could not get object from level",
|
||||||
zap.String("level", p),
|
zap.String("level", p),
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -240,7 +241,9 @@ func (b *blobovniczas) get(prm *GetSmallPrm) (res *GetSmallRes, err error) {
|
||||||
|
|
||||||
if err == nil && res == nil {
|
if err == nil && res == nil {
|
||||||
// not found in any blobovnicza
|
// not found in any blobovnicza
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -273,7 +276,7 @@ func (b *blobovniczas) delete(prm *DeleteSmallPrm) (res *DeleteSmallRes, err err
|
||||||
|
|
||||||
res, err = b.deleteObjectFromLevel(bPrm, p, !ok, prm)
|
res, err = b.deleteObjectFromLevel(bPrm, p, !ok, prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, object.ErrNotFound) {
|
if !blobovnicza.IsErrNotFound(err) {
|
||||||
b.log.Debug("could not remove object from level",
|
b.log.Debug("could not remove object from level",
|
||||||
zap.String("level", p),
|
zap.String("level", p),
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -293,7 +296,9 @@ func (b *blobovniczas) delete(prm *DeleteSmallPrm) (res *DeleteSmallRes, err err
|
||||||
|
|
||||||
if err == nil && res == nil {
|
if err == nil && res == nil {
|
||||||
// not found in any blobovnicza
|
// not found in any blobovnicza
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -323,7 +328,7 @@ func (b *blobovniczas) getRange(prm *GetRangeSmallPrm) (res *GetRangeSmallRes, e
|
||||||
res, err = b.getRangeFromLevel(prm, p, !ok)
|
res, err = b.getRangeFromLevel(prm, p, !ok)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
outOfBounds := errors.Is(err, object.ErrRangeOutOfBounds)
|
outOfBounds := errors.Is(err, object.ErrRangeOutOfBounds)
|
||||||
if !errors.Is(err, object.ErrNotFound) && !outOfBounds {
|
if !blobovnicza.IsErrNotFound(err) && !outOfBounds {
|
||||||
b.log.Debug("could not get object from level",
|
b.log.Debug("could not get object from level",
|
||||||
zap.String("level", p),
|
zap.String("level", p),
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -342,7 +347,9 @@ func (b *blobovniczas) getRange(prm *GetRangeSmallPrm) (res *GetRangeSmallRes, e
|
||||||
|
|
||||||
if err == nil && res == nil {
|
if err == nil && res == nil {
|
||||||
// not found in any blobovnicza
|
// not found in any blobovnicza
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -365,7 +372,7 @@ func (b *blobovniczas) deleteObjectFromLevel(prm *blobovnicza.DeletePrm, blzPath
|
||||||
if ok {
|
if ok {
|
||||||
if res, err := b.deleteObject(v.(*blobovnicza.Blobovnicza), prm, dp); err == nil {
|
if res, err := b.deleteObject(v.(*blobovnicza.Blobovnicza), prm, dp); err == nil {
|
||||||
return res, err
|
return res, err
|
||||||
} else if !errors.Is(err, object.ErrNotFound) {
|
} else if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not remove object from opened blobovnicza",
|
log.Debug("could not remove object from opened blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -383,7 +390,7 @@ func (b *blobovniczas) deleteObjectFromLevel(prm *blobovnicza.DeletePrm, blzPath
|
||||||
if ok && tryActive {
|
if ok && tryActive {
|
||||||
if res, err := b.deleteObject(active.blz, prm, dp); err == nil {
|
if res, err := b.deleteObject(active.blz, prm, dp); err == nil {
|
||||||
return res, err
|
return res, err
|
||||||
} else if !errors.Is(err, object.ErrNotFound) {
|
} else if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not remove object from active blobovnicza",
|
log.Debug("could not remove object from active blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -397,7 +404,9 @@ func (b *blobovniczas) deleteObjectFromLevel(prm *blobovnicza.DeletePrm, blzPath
|
||||||
// and it's pointless to open them).
|
// and it's pointless to open them).
|
||||||
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
||||||
log.Debug("index is too big")
|
log.Debug("index is too big")
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// open blobovnicza (cached inside)
|
// open blobovnicza (cached inside)
|
||||||
|
@ -426,7 +435,7 @@ func (b *blobovniczas) getObjectFromLevel(prm *blobovnicza.GetPrm, blzPath strin
|
||||||
if ok {
|
if ok {
|
||||||
if res, err := b.getObject(v.(*blobovnicza.Blobovnicza), prm); err == nil {
|
if res, err := b.getObject(v.(*blobovnicza.Blobovnicza), prm); err == nil {
|
||||||
return res, err
|
return res, err
|
||||||
} else if !errors.Is(err, object.ErrNotFound) {
|
} else if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not read object from opened blobovnicza",
|
log.Debug("could not read object from opened blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -445,7 +454,7 @@ func (b *blobovniczas) getObjectFromLevel(prm *blobovnicza.GetPrm, blzPath strin
|
||||||
if ok && tryActive {
|
if ok && tryActive {
|
||||||
if res, err := b.getObject(active.blz, prm); err == nil {
|
if res, err := b.getObject(active.blz, prm); err == nil {
|
||||||
return res, err
|
return res, err
|
||||||
} else if !errors.Is(err, object.ErrNotFound) {
|
} else if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not get object from active blobovnicza",
|
log.Debug("could not get object from active blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -459,7 +468,9 @@ func (b *blobovniczas) getObjectFromLevel(prm *blobovnicza.GetPrm, blzPath strin
|
||||||
// and it's pointless to open them).
|
// and it's pointless to open them).
|
||||||
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
||||||
log.Debug("index is too big")
|
log.Debug("index is too big")
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// open blobovnicza (cached inside)
|
// open blobovnicza (cached inside)
|
||||||
|
@ -492,7 +503,7 @@ func (b *blobovniczas) getRangeFromLevel(prm *GetRangeSmallPrm, blzPath string,
|
||||||
errors.Is(err, object.ErrRangeOutOfBounds):
|
errors.Is(err, object.ErrRangeOutOfBounds):
|
||||||
return res, err
|
return res, err
|
||||||
default:
|
default:
|
||||||
if !errors.Is(err, object.ErrNotFound) {
|
if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not read payload range from opened blobovnicza",
|
log.Debug("could not read payload range from opened blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -516,7 +527,7 @@ func (b *blobovniczas) getRangeFromLevel(prm *GetRangeSmallPrm, blzPath string,
|
||||||
errors.Is(err, object.ErrRangeOutOfBounds):
|
errors.Is(err, object.ErrRangeOutOfBounds):
|
||||||
return res, err
|
return res, err
|
||||||
default:
|
default:
|
||||||
if !errors.Is(err, object.ErrNotFound) {
|
if !blobovnicza.IsErrNotFound(err) {
|
||||||
log.Debug("could not read payload range from active blobovnicza",
|
log.Debug("could not read payload range from active blobovnicza",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
)
|
)
|
||||||
|
@ -531,7 +542,10 @@ func (b *blobovniczas) getRangeFromLevel(prm *GetRangeSmallPrm, blzPath string,
|
||||||
// and it's pointless to open them).
|
// and it's pointless to open them).
|
||||||
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
if u64FromHexString(filepath.Base(blzPath)) > active.ind {
|
||||||
log.Debug("index is too big")
|
log.Debug("index is too big")
|
||||||
return nil, object.ErrNotFound
|
|
||||||
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// open blobovnicza (cached inside)
|
// open blobovnicza (cached inside)
|
||||||
|
|
|
@ -2,13 +2,13 @@ package blobstor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -153,9 +153,9 @@ func TestBlobovniczas(t *testing.T) {
|
||||||
gPrm.SetAddress(addrList[i])
|
gPrm.SetAddress(addrList[i])
|
||||||
|
|
||||||
_, err = b.get(gPrm)
|
_, err = b.get(gPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
_, err = b.delete(dPrm)
|
_, err = b.delete(dPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ package blobstor
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
||||||
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeleteBigPrm groups the parameters of DeleteBig operation.
|
// DeleteBigPrm groups the parameters of DeleteBig operation.
|
||||||
|
@ -21,11 +21,13 @@ type DeleteBigRes struct{}
|
||||||
// Returns any error encountered that did not allow
|
// Returns any error encountered that did not allow
|
||||||
// to completely remove the object.
|
// to completely remove the object.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if there is no object to delete.
|
// Returns apistatus.ObjectNotFound if there is no object to delete.
|
||||||
func (b *BlobStor) DeleteBig(prm *DeleteBigPrm) (*DeleteBigRes, error) {
|
func (b *BlobStor) DeleteBig(prm *DeleteBigPrm) (*DeleteBigRes, error) {
|
||||||
err := b.fsTree.Delete(prm.addr)
|
err := b.fsTree.Delete(prm.addr)
|
||||||
if errors.Is(err, fstree.ErrFileNotFound) {
|
if errors.Is(err, fstree.ErrFileNotFound) {
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
err = errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -17,7 +17,7 @@ type DeleteSmallRes struct{}
|
||||||
// Returns any error encountered that did not allow
|
// Returns any error encountered that did not allow
|
||||||
// to completely remove the object.
|
// to completely remove the object.
|
||||||
//
|
//
|
||||||
// Returns ErrObjectNotFound if there is no object to delete.
|
// Returns apistatus.ObjectNotFound if there is no object to delete.
|
||||||
func (b *BlobStor) DeleteSmall(prm *DeleteSmallPrm) (*DeleteSmallRes, error) {
|
func (b *BlobStor) DeleteSmall(prm *DeleteSmallPrm) (*DeleteSmallRes, error) {
|
||||||
return b.blobovniczas.delete(prm)
|
return b.blobovniczas.delete(prm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,14 +24,16 @@ type GetBigRes struct {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object.
|
// did not allow to completely read the object.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if requested object is not
|
// Returns apistatus.ObjectNotFound if requested object is not
|
||||||
// presented in shallow dir.
|
// presented in shallow dir.
|
||||||
func (b *BlobStor) GetBig(prm *GetBigPrm) (*GetBigRes, error) {
|
func (b *BlobStor) GetBig(prm *GetBigPrm) (*GetBigRes, error) {
|
||||||
// get compressed object data
|
// get compressed object data
|
||||||
data, err := b.fsTree.Get(prm.addr)
|
data, err := b.fsTree.Get(prm.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, fstree.ErrFileNotFound) {
|
if errors.Is(err, fstree.ErrFileNotFound) {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("could not read object from fs tree: %w", err)
|
return nil, fmt.Errorf("could not read object from fs tree: %w", err)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,12 +27,15 @@ type GetRangeBigRes struct {
|
||||||
// did not allow to completely read the object payload range.
|
// did not allow to completely read the object payload range.
|
||||||
//
|
//
|
||||||
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
||||||
|
// Returns apistatus.ObjectNotFound if object is missing.
|
||||||
func (b *BlobStor) GetRangeBig(prm *GetRangeBigPrm) (*GetRangeBigRes, error) {
|
func (b *BlobStor) GetRangeBig(prm *GetRangeBigPrm) (*GetRangeBigRes, error) {
|
||||||
// get compressed object data
|
// get compressed object data
|
||||||
data, err := b.fsTree.Get(prm.addr)
|
data, err := b.fsTree.Get(prm.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, fstree.ErrFileNotFound) {
|
if errors.Is(err, fstree.ErrFileNotFound) {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("could not read object from fs tree: %w", err)
|
return nil, fmt.Errorf("could not read object from fs tree: %w", err)
|
||||||
|
|
|
@ -21,6 +21,7 @@ type GetRangeSmallRes struct {
|
||||||
// did not allow to completely read the object payload range.
|
// did not allow to completely read the object payload range.
|
||||||
//
|
//
|
||||||
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing in blobovnicza(s).
|
||||||
func (b *BlobStor) GetRangeSmall(prm *GetRangeSmallPrm) (*GetRangeSmallRes, error) {
|
func (b *BlobStor) GetRangeSmall(prm *GetRangeSmallPrm) (*GetRangeSmallRes, error) {
|
||||||
return b.blobovniczas.getRange(prm)
|
return b.blobovniczas.getRange(prm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ type GetSmallRes struct {
|
||||||
//
|
//
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object.
|
// did not allow to completely read the object.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing in blobovnicza(s).
|
||||||
func (b *BlobStor) GetSmall(prm *GetSmallPrm) (*GetSmallRes, error) {
|
func (b *BlobStor) GetSmall(prm *GetSmallPrm) (*GetSmallRes, error) {
|
||||||
return b.blobovniczas.get(prm)
|
return b.blobovniczas.get(prm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +14,7 @@ func (e *StorageEngine) exists(addr *addressSDK.Address) (bool, error) {
|
||||||
e.iterateOverSortedShards(addr, func(_ int, sh hashedShard) (stop bool) {
|
e.iterateOverSortedShards(addr, func(_ int, sh hashedShard) (stop bool) {
|
||||||
res, err := sh.Exists(shPrm)
|
res, err := sh.Exists(shPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, object.ErrAlreadyRemoved) {
|
if shard.IsErrRemoved(err) {
|
||||||
alreadyRemoved = true
|
alreadyRemoved = true
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -33,7 +31,9 @@ func (e *StorageEngine) exists(addr *addressSDK.Address) (bool, error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if alreadyRemoved {
|
if alreadyRemoved {
|
||||||
return false, object.ErrAlreadyRemoved
|
var errRemoved apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
|
return false, errRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
return exists, nil
|
return exists, nil
|
||||||
|
|
|
@ -3,9 +3,9 @@ package engine
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -42,7 +42,8 @@ func (r *GetRes) Object() *objectSDK.Object {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object part.
|
// did not allow to completely read the object part.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if requested object is missing in local storage.
|
// Returns apistatus.ObjectNotFound if requested object is missing in local storage.
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been marked as removed.
|
||||||
//
|
//
|
||||||
// Returns an error if executions are blocked (see BlockExecution).
|
// Returns an error if executions are blocked (see BlockExecution).
|
||||||
func (e *StorageEngine) Get(prm *GetPrm) (res *GetRes, err error) {
|
func (e *StorageEngine) Get(prm *GetPrm) (res *GetRes, err error) {
|
||||||
|
@ -63,8 +64,10 @@ func (e *StorageEngine) get(prm *GetPrm) (*GetRes, error) {
|
||||||
obj *objectSDK.Object
|
obj *objectSDK.Object
|
||||||
siErr *objectSDK.SplitInfoError
|
siErr *objectSDK.SplitInfoError
|
||||||
|
|
||||||
|
errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
outSI *objectSDK.SplitInfo
|
outSI *objectSDK.SplitInfo
|
||||||
outError = object.ErrNotFound
|
outError error = errNotFound
|
||||||
|
|
||||||
shardWithMeta hashedShard
|
shardWithMeta hashedShard
|
||||||
metaError error
|
metaError error
|
||||||
|
@ -81,7 +84,7 @@ func (e *StorageEngine) get(prm *GetPrm) (*GetRes, error) {
|
||||||
metaError = err
|
metaError = err
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, object.ErrNotFound):
|
case shard.IsErrNotFound(err):
|
||||||
return false // ignore, go to next shard
|
return false // ignore, go to next shard
|
||||||
case errors.As(err, &siErr):
|
case errors.As(err, &siErr):
|
||||||
siErr = err.(*objectSDK.SplitInfoError)
|
siErr = err.(*objectSDK.SplitInfoError)
|
||||||
|
@ -98,7 +101,7 @@ func (e *StorageEngine) get(prm *GetPrm) (*GetRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
case errors.Is(err, object.ErrAlreadyRemoved):
|
case shard.IsErrRemoved(err):
|
||||||
outError = err
|
outError = err
|
||||||
|
|
||||||
return true // stop, return it back
|
return true // stop, return it back
|
||||||
|
@ -118,7 +121,7 @@ func (e *StorageEngine) get(prm *GetPrm) (*GetRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
if shardWithMeta.Shard == nil || !errors.Is(outError, object.ErrNotFound) {
|
if shardWithMeta.Shard == nil || !shard.IsErrNotFound(outError) {
|
||||||
return nil, outError
|
return nil, outError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ package engine
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
)
|
)
|
||||||
|
@ -55,8 +55,8 @@ func (r *HeadRes) Header() *objectSDK.Object {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object header.
|
// did not allow to completely read the object header.
|
||||||
//
|
//
|
||||||
// Returns object.ErrNotFound if requested object is missing in local storage.
|
// Returns apistatus.ObjectNotFound if requested object is missing in local storage.
|
||||||
// Returns object.ErrAlreadyRemoved if requested object was inhumed.
|
// Returns apistatus.ObjectAlreadyRemoved if requested object was inhumed.
|
||||||
//
|
//
|
||||||
// Returns an error if executions are blocked (see BlockExecution).
|
// Returns an error if executions are blocked (see BlockExecution).
|
||||||
func (e *StorageEngine) Head(prm *HeadPrm) (res *HeadRes, err error) {
|
func (e *StorageEngine) Head(prm *HeadPrm) (res *HeadRes, err error) {
|
||||||
|
@ -77,8 +77,10 @@ func (e *StorageEngine) head(prm *HeadPrm) (*HeadRes, error) {
|
||||||
head *objectSDK.Object
|
head *objectSDK.Object
|
||||||
siErr *objectSDK.SplitInfoError
|
siErr *objectSDK.SplitInfoError
|
||||||
|
|
||||||
|
errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
outSI *objectSDK.SplitInfo
|
outSI *objectSDK.SplitInfo
|
||||||
outError = object.ErrNotFound
|
outError error = errNotFound
|
||||||
)
|
)
|
||||||
|
|
||||||
shPrm := new(shard.HeadPrm).
|
shPrm := new(shard.HeadPrm).
|
||||||
|
@ -89,7 +91,7 @@ func (e *StorageEngine) head(prm *HeadPrm) (*HeadRes, error) {
|
||||||
res, err := sh.Head(shPrm)
|
res, err := sh.Head(shPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, object.ErrNotFound):
|
case shard.IsErrNotFound(err):
|
||||||
return false // ignore, go to next shard
|
return false // ignore, go to next shard
|
||||||
case errors.As(err, &siErr):
|
case errors.As(err, &siErr):
|
||||||
siErr = err.(*objectSDK.SplitInfoError)
|
siErr = err.(*objectSDK.SplitInfoError)
|
||||||
|
@ -106,7 +108,7 @@ func (e *StorageEngine) head(prm *HeadPrm) (*HeadRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
case errors.Is(err, object.ErrAlreadyRemoved):
|
case shard.IsErrRemoved(err):
|
||||||
outError = err
|
outError = err
|
||||||
|
|
||||||
return true // stop, return it back
|
return true // stop, return it back
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
|
@ -116,7 +115,7 @@ func (e *StorageEngine) inhumeAddr(addr *addressSDK.Address, prm *shard.InhumePr
|
||||||
WithAddress(addr),
|
WithAddress(addr),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, object.ErrAlreadyRemoved) {
|
if shard.IsErrRemoved(err) {
|
||||||
// inhumed once - no need to be inhumed again
|
// inhumed once - no need to be inhumed again
|
||||||
status = 2
|
status = 2
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -36,6 +36,8 @@ func (p *PutPrm) WithObject(obj *objectSDK.Object) *PutPrm {
|
||||||
// did not allow to completely save the object.
|
// did not allow to completely save the object.
|
||||||
//
|
//
|
||||||
// Returns an error if executions are blocked (see BlockExecution).
|
// Returns an error if executions are blocked (see BlockExecution).
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been marked as removed.
|
||||||
func (e *StorageEngine) Put(prm *PutPrm) (res *PutRes, err error) {
|
func (e *StorageEngine) Put(prm *PutPrm) (res *PutRes, err error) {
|
||||||
err = e.execIfNotBlocked(func() error {
|
err = e.execIfNotBlocked(func() error {
|
||||||
res, err = e.put(prm)
|
res, err = e.put(prm)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -58,8 +59,8 @@ func (r *RngRes) Object() *objectSDK.Object {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object part.
|
// did not allow to completely read the object part.
|
||||||
//
|
//
|
||||||
// Returns ErrNotFound if requested object is missing in local storage.
|
// Returns apistatus.ObjectNotFound if requested object is missing in local storage.
|
||||||
// Returns ErrAlreadyRemoved if requested object is inhumed.
|
// Returns apistatus.ObjectAlreadyRemoved if requested object is inhumed.
|
||||||
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
||||||
//
|
//
|
||||||
// Returns an error if executions are blocked (see BlockExecution).
|
// Returns an error if executions are blocked (see BlockExecution).
|
||||||
|
@ -81,8 +82,10 @@ func (e *StorageEngine) getRange(prm *RngPrm) (*RngRes, error) {
|
||||||
obj *objectSDK.Object
|
obj *objectSDK.Object
|
||||||
siErr *objectSDK.SplitInfoError
|
siErr *objectSDK.SplitInfoError
|
||||||
|
|
||||||
|
errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
outSI *objectSDK.SplitInfo
|
outSI *objectSDK.SplitInfo
|
||||||
outError = object.ErrNotFound
|
outError error = errNotFound
|
||||||
|
|
||||||
shardWithMeta hashedShard
|
shardWithMeta hashedShard
|
||||||
metaError error
|
metaError error
|
||||||
|
@ -100,7 +103,7 @@ func (e *StorageEngine) getRange(prm *RngPrm) (*RngRes, error) {
|
||||||
metaError = err
|
metaError = err
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, object.ErrNotFound):
|
case shard.IsErrNotFound(err):
|
||||||
return false // ignore, go to next shard
|
return false // ignore, go to next shard
|
||||||
case errors.As(err, &siErr):
|
case errors.As(err, &siErr):
|
||||||
siErr = err.(*objectSDK.SplitInfoError)
|
siErr = err.(*objectSDK.SplitInfoError)
|
||||||
|
@ -118,7 +121,7 @@ func (e *StorageEngine) getRange(prm *RngPrm) (*RngRes, error) {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
case
|
case
|
||||||
errors.Is(err, object.ErrAlreadyRemoved),
|
shard.IsErrRemoved(err),
|
||||||
errors.Is(err, object.ErrRangeOutOfBounds):
|
errors.Is(err, object.ErrRangeOutOfBounds):
|
||||||
outError = err
|
outError = err
|
||||||
|
|
||||||
|
@ -139,7 +142,7 @@ func (e *StorageEngine) getRange(prm *RngPrm) (*RngRes, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
if shardWithMeta.Shard == nil || !errors.Is(outError, object.ErrNotFound) {
|
if shardWithMeta.Shard == nil || !shard.IsErrNotFound(outError) {
|
||||||
return nil, outError
|
return nil, outError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,13 @@ func TestReset(t *testing.T) {
|
||||||
|
|
||||||
addrToInhume := generateAddress()
|
addrToInhume := generateAddress()
|
||||||
|
|
||||||
assertExists := func(addr *addressSDK.Address, expExists bool, expErr error) {
|
assertExists := func(addr *addressSDK.Address, expExists bool, assertErr func(error) bool) {
|
||||||
exists, err := meta.Exists(db, addr)
|
exists, err := meta.Exists(db, addr)
|
||||||
require.ErrorIs(t, err, expErr)
|
if assertErr != nil {
|
||||||
|
require.True(t, assertErr(err))
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
require.Equal(t, expExists, exists)
|
require.Equal(t, expExists, exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +40,7 @@ func TestReset(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assertExists(addr, true, nil)
|
assertExists(addr, true, nil)
|
||||||
assertExists(addrToInhume, false, object.ErrAlreadyRemoved)
|
assertExists(addrToInhume, false, meta.IsErrRemoved)
|
||||||
|
|
||||||
err = db.Reset()
|
err = db.Reset()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
|
@ -97,7 +98,7 @@ func (db *DB) delete(tx *bbolt.Tx, addr *addressSDK.Address, refCounter referenc
|
||||||
// unmarshal object, work only with physically stored (raw == true) objects
|
// unmarshal object, work only with physically stored (raw == true) objects
|
||||||
obj, err := db.get(tx, addr, false, true)
|
obj, err := db.get(tx, addr, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, object.ErrNotFound) {
|
if errors.As(err, new(apistatus.ObjectNotFound)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
pkg/local_object_storage/metabase/errors.go
Normal file
13
pkg/local_object_storage/metabase/errors.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrRemoved checks if error returned by Shard Exists/Get/Put method
|
||||||
|
// corresponds to removed object.
|
||||||
|
func IsErrRemoved(err error) bool {
|
||||||
|
return errors.As(err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -39,6 +39,8 @@ func (p *ExistsRes) Exists() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if object is presented in DB.
|
// Exists checks if object is presented in DB.
|
||||||
|
//
|
||||||
|
// See DB.Exists docs.
|
||||||
func Exists(db *DB, addr *addressSDK.Address) (bool, error) {
|
func Exists(db *DB, addr *addressSDK.Address) (bool, error) {
|
||||||
r, err := db.Exists(new(ExistsPrm).WithAddress(addr))
|
r, err := db.Exists(new(ExistsPrm).WithAddress(addr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -50,6 +52,8 @@ func Exists(db *DB, addr *addressSDK.Address) (bool, error) {
|
||||||
|
|
||||||
// Exists returns ErrAlreadyRemoved if addr was marked as removed. Otherwise it
|
// Exists returns ErrAlreadyRemoved if addr was marked as removed. Otherwise it
|
||||||
// returns true if addr is in primary index or false if it is not.
|
// returns true if addr is in primary index or false if it is not.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been placed in graveyard.
|
||||||
func (db *DB) Exists(prm *ExistsPrm) (res *ExistsRes, err error) {
|
func (db *DB) Exists(prm *ExistsPrm) (res *ExistsRes, err error) {
|
||||||
res = new(ExistsRes)
|
res = new(ExistsRes)
|
||||||
|
|
||||||
|
@ -66,9 +70,13 @@ func (db *DB) exists(tx *bbolt.Tx, addr *addressSDK.Address) (exists bool, err e
|
||||||
// check graveyard first
|
// check graveyard first
|
||||||
switch inGraveyard(tx, addr) {
|
switch inGraveyard(tx, addr) {
|
||||||
case 1:
|
case 1:
|
||||||
return false, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return false, errNotFound
|
||||||
case 2:
|
case 2:
|
||||||
return false, object.ErrAlreadyRemoved
|
var errRemoved apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
|
return false, errRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
objKey := objectKey(addr.ObjectID())
|
objKey := objectKey(addr.ObjectID())
|
||||||
|
|
|
@ -3,7 +3,7 @@ package meta
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
@ -69,6 +69,9 @@ func GetRaw(db *DB, addr *addressSDK.Address, raw bool) (*objectSDK.Object, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns object header for specified address.
|
// Get returns object header for specified address.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if object is missing in DB.
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been placed in graveyard.
|
||||||
func (db *DB) Get(prm *GetPrm) (res *GetRes, err error) {
|
func (db *DB) Get(prm *GetPrm) (res *GetRes, err error) {
|
||||||
res = new(GetRes)
|
res = new(GetRes)
|
||||||
|
|
||||||
|
@ -89,9 +92,13 @@ func (db *DB) get(tx *bbolt.Tx, addr *addressSDK.Address, checkGraveyard, raw bo
|
||||||
if checkGraveyard {
|
if checkGraveyard {
|
||||||
switch inGraveyard(tx, addr) {
|
switch inGraveyard(tx, addr) {
|
||||||
case 1:
|
case 1:
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
case 2:
|
case 2:
|
||||||
return nil, object.ErrAlreadyRemoved
|
var errRemoved apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
|
return nil, errRemoved
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +146,9 @@ func getVirtualObject(tx *bbolt.Tx, cid *cid.ID, key []byte, raw bool) (*objectS
|
||||||
|
|
||||||
parentBucket := tx.Bucket(parentBucketName(cid))
|
parentBucket := tx.Bucket(parentBucketName(cid))
|
||||||
if parentBucket == nil {
|
if parentBucket == nil {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
relativeLst, err := decodeList(parentBucket.Get(key))
|
relativeLst, err := decodeList(parentBucket.Get(key))
|
||||||
|
@ -148,7 +157,9 @@ func getVirtualObject(tx *bbolt.Tx, cid *cid.ID, key []byte, raw bool) (*objectS
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(relativeLst) == 0 { // this should never happen though
|
if len(relativeLst) == 0 { // this should never happen though
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// pick last item, for now there is not difference which address to pick
|
// pick last item, for now there is not difference which address to pick
|
||||||
|
@ -167,7 +178,9 @@ func getVirtualObject(tx *bbolt.Tx, cid *cid.ID, key []byte, raw bool) (*objectS
|
||||||
par := child.Parent()
|
par := child.Parent()
|
||||||
|
|
||||||
if par == nil { // this should never happen though
|
if par == nil { // this should never happen though
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return par, nil
|
return par, nil
|
||||||
|
@ -179,5 +192,7 @@ func getSplitInfoError(tx *bbolt.Tx, cid *cid.ID, key []byte) error {
|
||||||
return objectSDK.NewSplitInfoError(splitInfo)
|
return objectSDK.NewSplitInfoError(splitInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
return object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return errNotFound
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -112,12 +113,12 @@ func TestDB_Get(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, meta.Inhume(db, obj, ts))
|
require.NoError(t, meta.Inhume(db, obj, ts))
|
||||||
_, err := meta.Get(db, obj)
|
_, err := meta.Get(db, obj)
|
||||||
require.ErrorIs(t, err, object.ErrAlreadyRemoved)
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
obj = generateAddress()
|
obj = generateAddress()
|
||||||
require.NoError(t, meta.Inhume(db, obj, nil))
|
require.NoError(t, meta.Inhume(db, obj, nil))
|
||||||
_, err = meta.Get(db, obj)
|
_, err = meta.Get(db, obj)
|
||||||
require.ErrorIs(t, err, object.ErrNotFound)
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package meta_test
|
package meta_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
|
@ -28,10 +27,10 @@ func TestDB_Inhume(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = meta.Exists(db, object.AddressOf(raw))
|
_, err = meta.Exists(db, object.AddressOf(raw))
|
||||||
require.EqualError(t, err, object.ErrAlreadyRemoved.Error())
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
_, err = meta.Get(db, object.AddressOf(raw))
|
_, err = meta.Get(db, object.AddressOf(raw))
|
||||||
require.EqualError(t, err, object.ErrAlreadyRemoved.Error())
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInhumeTombOnTomb(t *testing.T) {
|
func TestInhumeTombOnTomb(t *testing.T) {
|
||||||
|
@ -56,7 +55,7 @@ func TestInhumeTombOnTomb(t *testing.T) {
|
||||||
|
|
||||||
// addr1 should become inhumed {addr1:addr2}
|
// addr1 should become inhumed {addr1:addr2}
|
||||||
_, err = db.Exists(existsPrm.WithAddress(addr1))
|
_, err = db.Exists(existsPrm.WithAddress(addr1))
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
// try to inhume addr3 via addr1
|
// try to inhume addr3 via addr1
|
||||||
_, err = db.Inhume(inhumePrm.
|
_, err = db.Inhume(inhumePrm.
|
||||||
|
@ -73,7 +72,7 @@ func TestInhumeTombOnTomb(t *testing.T) {
|
||||||
|
|
||||||
// addr3 should be inhumed {addr3: addr1}
|
// addr3 should be inhumed {addr3: addr1}
|
||||||
_, err = db.Exists(existsPrm.WithAddress(addr3))
|
_, err = db.Exists(existsPrm.WithAddress(addr3))
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
// try to inhume addr1 (which is already a tombstone in graveyard)
|
// try to inhume addr1 (which is already a tombstone in graveyard)
|
||||||
_, err = db.Inhume(inhumePrm.
|
_, err = db.Inhume(inhumePrm.
|
||||||
|
|
|
@ -56,6 +56,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Put saves the object in DB.
|
// Put saves the object in DB.
|
||||||
|
//
|
||||||
|
// See DB.Put docs.
|
||||||
func Put(db *DB, obj *objectSDK.Object, id *blobovnicza.ID) error {
|
func Put(db *DB, obj *objectSDK.Object, id *blobovnicza.ID) error {
|
||||||
_, err := db.Put(new(PutPrm).
|
_, err := db.Put(new(PutPrm).
|
||||||
WithObject(obj).
|
WithObject(obj).
|
||||||
|
@ -67,6 +69,8 @@ func Put(db *DB, obj *objectSDK.Object, id *blobovnicza.ID) error {
|
||||||
|
|
||||||
// Put saves object header in metabase. Object payload expected to be cut.
|
// Put saves object header in metabase. Object payload expected to be cut.
|
||||||
// Big objects have nil blobovniczaID.
|
// Big objects have nil blobovniczaID.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been placed in graveyard.
|
||||||
func (db *DB) Put(prm *PutPrm) (res *PutRes, err error) {
|
func (db *DB) Put(prm *PutPrm) (res *PutRes, err error) {
|
||||||
err = db.boltDB.Batch(func(tx *bbolt.Tx) error {
|
err = db.boltDB.Batch(func(tx *bbolt.Tx) error {
|
||||||
return db.put(tx, prm.obj, prm.id, nil)
|
return db.put(tx, prm.obj, prm.id, nil)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package shard
|
package shard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
|
@ -114,7 +113,7 @@ func (s *Shard) refillMetabase() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
err := meta.Put(s.metaBase, obj, blzID)
|
err := meta.Put(s.metaBase, obj, blzID)
|
||||||
if err != nil && !errors.Is(err, object.ErrAlreadyRemoved) {
|
if err != nil && !meta.IsErrRemoved(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
||||||
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
objecttest "github.com/nspcc-dev/neofs-sdk-go/object/test"
|
objecttest "github.com/nspcc-dev/neofs-sdk-go/object/test"
|
||||||
|
@ -99,7 +100,7 @@ func TestRefillMetabase(t *testing.T) {
|
||||||
res, err := sh.Head(headPrm.WithAddress(addr))
|
res, err := sh.Head(headPrm.WithAddress(addr))
|
||||||
|
|
||||||
if expObj == nil {
|
if expObj == nil {
|
||||||
require.ErrorIs(t, err, object.ErrNotFound)
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,9 +123,9 @@ func TestRefillMetabase(t *testing.T) {
|
||||||
_, err := sh.Head(headPrm.WithAddress(member))
|
_, err := sh.Head(headPrm.WithAddress(member))
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
require.ErrorIs(t, err, object.ErrAlreadyRemoved)
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
} else {
|
} else {
|
||||||
require.ErrorIs(t, err, object.ErrNotFound)
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package shard
|
package shard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
||||||
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -46,7 +44,7 @@ func (s *Shard) Delete(prm *DeletePrm) (*DeleteRes, error) {
|
||||||
for i := range prm.addr {
|
for i := range prm.addr {
|
||||||
if s.hasWriteCache() {
|
if s.hasWriteCache() {
|
||||||
err := s.writeCache.Delete(prm.addr[i])
|
err := s.writeCache.Delete(prm.addr[i])
|
||||||
if err != nil && !errors.Is(err, object.ErrNotFound) {
|
if err != nil && !writecache.IsErrNotFound(err) {
|
||||||
s.log.Error("can't delete object from write cache", zap.String("error", err.Error()))
|
s.log.Error("can't delete object from write cache", zap.String("error", err.Error()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -50,7 +51,7 @@ func testShardDelete(t *testing.T, hasWriteCache bool) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = sh.Get(getPrm)
|
_, err = sh.Get(getPrm)
|
||||||
require.EqualError(t, err, object.ErrNotFound.Error())
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("small object", func(t *testing.T) {
|
t.Run("small object", func(t *testing.T) {
|
||||||
|
@ -73,6 +74,6 @@ func testShardDelete(t *testing.T, hasWriteCache bool) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = sh.Get(getPrm)
|
_, err = sh.Get(getPrm)
|
||||||
require.EqualError(t, err, object.ErrNotFound.Error())
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
19
pkg/local_object_storage/shard/errors.go
Normal file
19
pkg/local_object_storage/shard/errors.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package shard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrNotFound checks if error returned by Shard Get/Head/GetRange method
|
||||||
|
// corresponds to missing object.
|
||||||
|
func IsErrNotFound(err error) bool {
|
||||||
|
return errors.As(err, new(apistatus.ObjectNotFound))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrRemoved checks if error returned by Shard Exists/Get/Head/GetRange method
|
||||||
|
// corresponds to removed object.
|
||||||
|
func IsErrRemoved(err error) bool {
|
||||||
|
return errors.As(err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
}
|
|
@ -33,6 +33,8 @@ func (p *ExistsRes) Exists() bool {
|
||||||
//
|
//
|
||||||
// Returns any error encountered that does not allow to
|
// Returns any error encountered that does not allow to
|
||||||
// unambiguously determine the presence of an object.
|
// unambiguously determine the presence of an object.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if object has been marked as removed.
|
||||||
func (s *Shard) Exists(prm *ExistsPrm) (*ExistsRes, error) {
|
func (s *Shard) Exists(prm *ExistsPrm) (*ExistsRes, error) {
|
||||||
exists, err := s.objectExists(prm.addr)
|
exists, err := s.objectExists(prm.addr)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
|
||||||
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -62,7 +64,8 @@ func (r *GetRes) HasMeta() bool {
|
||||||
// Returns any error encountered that
|
// Returns any error encountered that
|
||||||
// did not allow to completely read the object part.
|
// did not allow to completely read the object part.
|
||||||
//
|
//
|
||||||
// Returns object.ErrNotFound if requested object is missing in shard.
|
// Returns apistatus.ObjectNotFound if requested object is missing in shard.
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if requested object has been marked as removed in shard.
|
||||||
func (s *Shard) Get(prm *GetPrm) (*GetRes, error) {
|
func (s *Shard) Get(prm *GetPrm) (*GetRes, error) {
|
||||||
var big, small storFetcher
|
var big, small storFetcher
|
||||||
|
|
||||||
|
@ -112,7 +115,7 @@ func (s *Shard) fetchObjectData(addr *addressSDK.Address, skipMeta bool, big, sm
|
||||||
return res, false, nil
|
return res, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, object.ErrNotFound) {
|
if writecache.IsErrNotFound(err) {
|
||||||
s.log.Debug("object is missing in write-cache")
|
s.log.Debug("object is missing in write-cache")
|
||||||
} else {
|
} else {
|
||||||
s.log.Error("failed to fetch object from write-cache", zap.Error(err))
|
s.log.Error("failed to fetch object from write-cache", zap.Error(err))
|
||||||
|
@ -134,7 +137,9 @@ func (s *Shard) fetchObjectData(addr *addressSDK.Address, skipMeta bool, big, sm
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, false, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, false, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
blobovniczaID, err := meta.IsSmall(s.metaBase, addr)
|
blobovniczaID, err := meta.IsSmall(s.metaBase, addr)
|
||||||
|
|
|
@ -110,10 +110,10 @@ func testGet(t *testing.T, sh *shard.Shard, getPrm *shard.GetPrm, hasWriteCache
|
||||||
res, err := sh.Get(getPrm)
|
res, err := sh.Get(getPrm)
|
||||||
if hasWriteCache {
|
if hasWriteCache {
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
if errors.Is(err, object.ErrNotFound) {
|
if shard.IsErrNotFound(err) {
|
||||||
res, err = sh.Get(getPrm)
|
res, err = sh.Get(getPrm)
|
||||||
}
|
}
|
||||||
return !errors.Is(err, object.ErrNotFound)
|
return !shard.IsErrNotFound(err)
|
||||||
}, time.Second, time.Millisecond*100)
|
}, time.Second, time.Millisecond*100)
|
||||||
}
|
}
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package shard
|
package shard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
)
|
)
|
||||||
|
@ -51,6 +50,9 @@ func (r *HeadRes) Object() *objectSDK.Object {
|
||||||
// Head reads header of the object from the shard.
|
// Head reads header of the object from the shard.
|
||||||
//
|
//
|
||||||
// Returns any error encountered.
|
// Returns any error encountered.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if object is missing in Shard.
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if requested object has been marked as removed in shard.
|
||||||
func (s *Shard) Head(prm *HeadPrm) (*HeadRes, error) {
|
func (s *Shard) Head(prm *HeadPrm) (*HeadRes, error) {
|
||||||
// object can be saved in write-cache (if enabled) or in metabase
|
// object can be saved in write-cache (if enabled) or in metabase
|
||||||
|
|
||||||
|
@ -61,7 +63,7 @@ func (s *Shard) Head(prm *HeadPrm) (*HeadRes, error) {
|
||||||
return &HeadRes{
|
return &HeadRes{
|
||||||
obj: header,
|
obj: header,
|
||||||
}, nil
|
}, nil
|
||||||
} else if !errors.Is(err, object.ErrNotFound) {
|
} else if !writecache.IsErrNotFound(err) {
|
||||||
// in this case we think that object is presented in write-cache, but corrupted
|
// in this case we think that object is presented in write-cache, but corrupted
|
||||||
return nil, fmt.Errorf("could not read header from write-cache: %w", err)
|
return nil, fmt.Errorf("could not read header from write-cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,10 @@ func testHead(t *testing.T, sh *shard.Shard, headPrm *shard.HeadPrm, hasWriteCac
|
||||||
res, err := sh.Head(headPrm)
|
res, err := sh.Head(headPrm)
|
||||||
if hasWriteCache {
|
if hasWriteCache {
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
if errors.Is(err, object.ErrNotFound) {
|
if shard.IsErrNotFound(err) {
|
||||||
res, err = sh.Head(headPrm)
|
res, err = sh.Head(headPrm)
|
||||||
}
|
}
|
||||||
return !errors.Is(err, object.ErrNotFound)
|
return !shard.IsErrNotFound(err)
|
||||||
}, time.Second, time.Millisecond*100)
|
}, time.Second, time.Millisecond*100)
|
||||||
}
|
}
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -49,5 +50,5 @@ func testShardInhume(t *testing.T, hasWriteCache bool) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = sh.Get(getPrm)
|
_, err = sh.Get(getPrm)
|
||||||
require.EqualError(t, err, object.ErrAlreadyRemoved.Error())
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ func (r *RngRes) HasMeta() bool {
|
||||||
// did not allow to completely read the object part.
|
// did not allow to completely read the object part.
|
||||||
//
|
//
|
||||||
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
// Returns ErrRangeOutOfBounds if requested object range is out of bounds.
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing.
|
||||||
|
// Returns apistatus.ObjectAlreadyRemoved if requested object has been marked as removed in shard.
|
||||||
func (s *Shard) GetRange(prm *RngPrm) (*RngRes, error) {
|
func (s *Shard) GetRange(prm *RngPrm) (*RngRes, error) {
|
||||||
var big, small storFetcher
|
var big, small storFetcher
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,16 @@ package writecache
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
||||||
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Delete removes object from write-cache.
|
// Delete removes object from write-cache.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound is object is missing in write-cache.
|
||||||
func (c *cache) Delete(addr *addressSDK.Address) error {
|
func (c *cache) Delete(addr *addressSDK.Address) error {
|
||||||
c.modeMtx.RLock()
|
c.modeMtx.RLock()
|
||||||
defer c.modeMtx.RUnlock()
|
defer c.modeMtx.RUnlock()
|
||||||
|
@ -58,7 +60,9 @@ func (c *cache) Delete(addr *addressSDK.Address) error {
|
||||||
|
|
||||||
err := c.fsTree.Delete(addr)
|
err := c.fsTree.Delete(addr)
|
||||||
if errors.Is(err, fstree.ErrFileNotFound) {
|
if errors.Is(err, fstree.ErrFileNotFound) {
|
||||||
err = object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
err = errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
13
pkg/local_object_storage/writecache/errors.go
Normal file
13
pkg/local_object_storage/writecache/errors.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package writecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrNotFound checks if error returned by Cache Get/Head/Delete method
|
||||||
|
// corresponds to missing object.
|
||||||
|
func IsErrNotFound(err error) bool {
|
||||||
|
return errors.As(err, new(apistatus.ObjectNotFound))
|
||||||
|
}
|
|
@ -1,13 +1,15 @@
|
||||||
package writecache
|
package writecache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get returns object from write-cache.
|
// Get returns object from write-cache.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing in write-cache.
|
||||||
func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
saddr := addr.String()
|
saddr := addr.String()
|
||||||
|
|
||||||
|
@ -30,7 +32,9 @@ func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
|
|
||||||
data, err := c.fsTree.Get(addr)
|
data, err := c.fsTree.Get(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := objectSDK.New()
|
obj := objectSDK.New()
|
||||||
|
@ -43,6 +47,8 @@ func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head returns object header from write-cache.
|
// Head returns object header from write-cache.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing in write-cache.
|
||||||
func (c *cache) Head(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
func (c *cache) Head(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
// TODO: #1149 easiest to implement solution is presented here, consider more efficient way, e.g.:
|
// TODO: #1149 easiest to implement solution is presented here, consider more efficient way, e.g.:
|
||||||
// - provide header as common object.Object to Put, but marked to prevent correlation with full object
|
// - provide header as common object.Object to Put, but marked to prevent correlation with full object
|
||||||
|
@ -61,6 +67,8 @@ func (c *cache) Head(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
|
|
||||||
// Get fetches object from the underlying database.
|
// Get fetches object from the underlying database.
|
||||||
// Key should be a stringified address.
|
// Key should be a stringified address.
|
||||||
|
//
|
||||||
|
// Returns apistatus.ObjectNotFound if requested object is missing in db.
|
||||||
func Get(db *bbolt.DB, key []byte) ([]byte, error) {
|
func Get(db *bbolt.DB, key []byte) ([]byte, error) {
|
||||||
var value []byte
|
var value []byte
|
||||||
err := db.View(func(tx *bbolt.Tx) error {
|
err := db.View(func(tx *bbolt.Tx) error {
|
||||||
|
@ -70,7 +78,9 @@ func Get(db *bbolt.DB, key []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
value = b.Get(key)
|
value = b.Get(key)
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return errNotFound
|
||||||
}
|
}
|
||||||
value = cloneBytes(value)
|
value = cloneBytes(value)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/hashicorp/golang-lru/simplelru"
|
"github.com/hashicorp/golang-lru/simplelru"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
|
||||||
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util"
|
"github.com/nspcc-dev/neofs-node/pkg/util"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -103,7 +103,9 @@ func (c *cache) deleteFromDB(keys [][]byte) error {
|
||||||
for i := range keys {
|
for i := range keys {
|
||||||
has := b.Get(keys[i])
|
has := b.Get(keys[i])
|
||||||
if has == nil {
|
if has == nil {
|
||||||
return object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return errNotFound
|
||||||
}
|
}
|
||||||
if err := b.Delete(keys[i]); err != nil {
|
if err := b.Delete(keys[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
|
@ -106,7 +107,9 @@ func newTestClient() *testClient {
|
||||||
func (c *testClient) getObject(exec *execCtx, _ client.NodeInfo) (*objectSDK.Object, error) {
|
func (c *testClient) getObject(exec *execCtx, _ client.NodeInfo) (*objectSDK.Object, error) {
|
||||||
v, ok := c.results[exec.address().String()]
|
v, ok := c.results[exec.address().String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.err != nil {
|
if v.err != nil {
|
||||||
|
@ -131,7 +134,9 @@ func (s *testStorage) get(exec *execCtx) (*objectSDK.Object, error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if _, ok = s.inhumed[sAddr]; ok {
|
if _, ok = s.inhumed[sAddr]; ok {
|
||||||
return nil, object.ErrAlreadyRemoved
|
var errRemoved apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
|
return nil, errRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
if info, ok := s.virtual[sAddr]; ok {
|
if info, ok := s.virtual[sAddr]; ok {
|
||||||
|
@ -142,7 +147,9 @@ func (s *testStorage) get(exec *execCtx) (*objectSDK.Object, error) {
|
||||||
return cutToRange(obj, exec.ctxRange()), nil
|
return cutToRange(obj, exec.ctxRange()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, object.ErrNotFound
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func cutToRange(o *objectSDK.Object, rng *objectSDK.Range) *objectSDK.Object {
|
func cutToRange(o *objectSDK.Object, rng *objectSDK.Range) *objectSDK.Object {
|
||||||
|
@ -309,19 +316,19 @@ func TestGetLocalOnly(t *testing.T) {
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
|
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
headPrm := newHeadPrm(false, nil)
|
headPrm := newHeadPrm(false, nil)
|
||||||
headPrm.WithAddress(addr)
|
headPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.Head(ctx, headPrm)
|
err = svc.Head(ctx, headPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(apistatus.ObjectAlreadyRemoved))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("404", func(t *testing.T) {
|
t.Run("404", func(t *testing.T) {
|
||||||
|
@ -336,20 +343,20 @@ func TestGetLocalOnly(t *testing.T) {
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
|
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
|
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
headPrm := newHeadPrm(false, nil)
|
headPrm := newHeadPrm(false, nil)
|
||||||
headPrm.WithAddress(addr)
|
headPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.Head(ctx, headPrm)
|
err = svc.Head(ctx, headPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("VIRTUAL", func(t *testing.T) {
|
t.Run("VIRTUAL", func(t *testing.T) {
|
||||||
|
@ -599,7 +606,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c1.addResult(addr, nil, errors.New("any error"))
|
c1.addResult(addr, nil, errors.New("any error"))
|
||||||
|
|
||||||
c2 := newTestClient()
|
c2 := newTestClient()
|
||||||
c2.addResult(addr, nil, object.ErrAlreadyRemoved)
|
c2.addResult(addr, nil, new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
svc := newSvc(builder, &testClientCache{
|
svc := newSvc(builder, &testClientCache{
|
||||||
clients: map[string]*testClient{
|
clients: map[string]*testClient{
|
||||||
|
@ -612,19 +619,19 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(*apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(*apistatus.ObjectAlreadyRemoved))
|
||||||
|
|
||||||
headPrm := newHeadPrm(false, nil)
|
headPrm := newHeadPrm(false, nil)
|
||||||
headPrm.WithAddress(addr)
|
headPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.Head(ctx, headPrm)
|
err = svc.Head(ctx, headPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrAlreadyRemoved))
|
require.ErrorAs(t, err, new(*apistatus.ObjectAlreadyRemoved))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("404", func(t *testing.T) {
|
t.Run("404", func(t *testing.T) {
|
||||||
|
@ -656,19 +663,19 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
headPrm := newHeadPrm(false, nil)
|
headPrm := newHeadPrm(false, nil)
|
||||||
headPrm.WithAddress(addr)
|
headPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.Head(ctx, headPrm)
|
err = svc.Head(ctx, headPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("VIRTUAL", func(t *testing.T) {
|
t.Run("VIRTUAL", func(t *testing.T) {
|
||||||
|
@ -700,11 +707,11 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
|
|
||||||
c1 := newTestClient()
|
c1 := newTestClient()
|
||||||
c1.addResult(addr, nil, errors.New("any error"))
|
c1.addResult(addr, nil, errors.New("any error"))
|
||||||
c1.addResult(splitAddr, nil, object.ErrNotFound)
|
c1.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
c2 := newTestClient()
|
c2 := newTestClient()
|
||||||
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
||||||
c2.addResult(splitAddr, nil, object.ErrNotFound)
|
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][]netmap.Nodes{
|
||||||
|
@ -726,13 +733,13 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("get chain element failure", func(t *testing.T) {
|
t.Run("get chain element failure", func(t *testing.T) {
|
||||||
|
@ -776,7 +783,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
||||||
c2.addResult(linkAddr, linkingObj, nil)
|
c2.addResult(linkAddr, linkingObj, nil)
|
||||||
c2.addResult(child1Addr, children[0], nil)
|
c2.addResult(child1Addr, children[0], nil)
|
||||||
c2.addResult(child2Addr, nil, object.ErrNotFound)
|
c2.addResult(child2Addr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][]netmap.Nodes{
|
||||||
|
@ -800,13 +807,13 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, NewSimpleObjectWriter(), 0, 1)
|
rngPrm := newRngPrm(false, NewSimpleObjectWriter(), 0, 1)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
@ -913,11 +920,11 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
|
|
||||||
c1 := newTestClient()
|
c1 := newTestClient()
|
||||||
c1.addResult(addr, nil, errors.New("any error"))
|
c1.addResult(addr, nil, errors.New("any error"))
|
||||||
c1.addResult(splitAddr, nil, object.ErrNotFound)
|
c1.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
c2 := newTestClient()
|
c2 := newTestClient()
|
||||||
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
c2.addResult(addr, nil, objectSDK.NewSplitInfoError(splitInfo))
|
||||||
c2.addResult(splitAddr, nil, object.ErrNotFound)
|
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][]netmap.Nodes{
|
||||||
|
@ -939,13 +946,13 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 0)
|
rngPrm := newRngPrm(false, nil, 0, 0)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("get chain element failure", func(t *testing.T) {
|
t.Run("get chain element failure", func(t *testing.T) {
|
||||||
|
@ -1000,19 +1007,19 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
testHeadVirtual(svc, addr, splitInfo)
|
testHeadVirtual(svc, addr, splitInfo)
|
||||||
|
|
||||||
headSvc := newTestClient()
|
headSvc := newTestClient()
|
||||||
headSvc.addResult(preRightAddr, nil, object.ErrNotFound)
|
headSvc.addResult(preRightAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
p := newPrm(false, NewSimpleObjectWriter())
|
p := newPrm(false, NewSimpleObjectWriter())
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
rngPrm := newRngPrm(false, nil, 0, 1)
|
rngPrm := newRngPrm(false, nil, 0, 1)
|
||||||
rngPrm.WithAddress(addr)
|
rngPrm.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rngPrm)
|
err = svc.GetRange(ctx, rngPrm)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
@ -1180,7 +1187,7 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
p.WithAddress(addr)
|
p.WithAddress(addr)
|
||||||
|
|
||||||
err := svc.Get(ctx, p)
|
err := svc.Get(ctx, p)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
commonPrm.SetNetmapLookupDepth(1)
|
commonPrm.SetNetmapLookupDepth(1)
|
||||||
|
|
||||||
|
@ -1203,7 +1210,7 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
rp.SetRange(r)
|
rp.SetRange(r)
|
||||||
|
|
||||||
err = svc.GetRange(ctx, rp)
|
err = svc.GetRange(ctx, rp)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
w = NewSimpleObjectWriter()
|
w = NewSimpleObjectWriter()
|
||||||
rp.SetChunkWriter(w)
|
rp.SetChunkWriter(w)
|
||||||
|
@ -1220,7 +1227,7 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
hp.WithAddress(addr)
|
hp.WithAddress(addr)
|
||||||
|
|
||||||
err = svc.Head(ctx, hp)
|
err = svc.Head(ctx, hp)
|
||||||
require.True(t, errors.Is(err, object.ErrNotFound))
|
require.ErrorAs(t, err, new(apistatus.ObjectNotFound))
|
||||||
|
|
||||||
w = NewSimpleObjectWriter()
|
w = NewSimpleObjectWriter()
|
||||||
hp.SetHeaderWriter(w)
|
hp.SetHeaderWriter(w)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -14,6 +15,7 @@ func (exec *execCtx) executeLocal() {
|
||||||
exec.collectedObject, err = exec.svc.localStorage.get(exec)
|
exec.collectedObject, err = exec.svc.localStorage.get(exec)
|
||||||
|
|
||||||
var errSplitInfo *objectSDK.SplitInfoError
|
var errSplitInfo *objectSDK.SplitInfoError
|
||||||
|
var errRemoved apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
|
@ -27,9 +29,9 @@ func (exec *execCtx) executeLocal() {
|
||||||
exec.status = statusOK
|
exec.status = statusOK
|
||||||
exec.err = nil
|
exec.err = nil
|
||||||
exec.writeCollectedObject()
|
exec.writeCollectedObject()
|
||||||
case errors.Is(err, object.ErrAlreadyRemoved):
|
case errors.As(err, &errRemoved):
|
||||||
exec.status = statusINHUMED
|
exec.status = statusINHUMED
|
||||||
exec.err = object.ErrAlreadyRemoved
|
exec.err = errRemoved
|
||||||
case errors.As(err, &errSplitInfo):
|
case errors.As(err, &errSplitInfo):
|
||||||
exec.status = statusVIRTUAL
|
exec.status = statusVIRTUAL
|
||||||
mergeSplitInfo(exec.splitInfo(), errSplitInfo.SplitInfo())
|
mergeSplitInfo(exec.splitInfo(), errSplitInfo.SplitInfo())
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -21,11 +21,14 @@ func (exec *execCtx) processNode(ctx context.Context, info client.NodeInfo) bool
|
||||||
obj, err := client.getObject(exec, info)
|
obj, err := client.getObject(exec, info)
|
||||||
|
|
||||||
var errSplitInfo *objectSDK.SplitInfoError
|
var errSplitInfo *objectSDK.SplitInfoError
|
||||||
|
var errRemoved *apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
|
var errNotFound apistatus.ObjectNotFound
|
||||||
|
|
||||||
exec.status = statusUndefined
|
exec.status = statusUndefined
|
||||||
exec.err = object.ErrNotFound
|
exec.err = errNotFound
|
||||||
|
|
||||||
exec.log.Debug("remote call failed",
|
exec.log.Debug("remote call failed",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -35,9 +38,9 @@ func (exec *execCtx) processNode(ctx context.Context, info client.NodeInfo) bool
|
||||||
exec.err = nil
|
exec.err = nil
|
||||||
exec.collectedObject = obj
|
exec.collectedObject = obj
|
||||||
exec.writeCollectedObject()
|
exec.writeCollectedObject()
|
||||||
case errors.Is(err, object.ErrAlreadyRemoved):
|
case errors.As(err, &errRemoved):
|
||||||
exec.status = statusINHUMED
|
exec.status = statusINHUMED
|
||||||
exec.err = object.ErrAlreadyRemoved
|
exec.err = errRemoved
|
||||||
case errors.As(err, &errSplitInfo):
|
case errors.As(err, &errSplitInfo):
|
||||||
exec.status = statusVIRTUAL
|
exec.status = statusVIRTUAL
|
||||||
mergeSplitInfo(exec.splitInfo(), errSplitInfo.SplitInfo())
|
mergeSplitInfo(exec.splitInfo(), errSplitInfo.SplitInfo())
|
||||||
|
|
|
@ -148,8 +148,8 @@ func (x GetObjectRes) Object() *object.Object {
|
||||||
//
|
//
|
||||||
// Returns any error prevented the operation from completing correctly in error return.
|
// Returns any error prevented the operation from completing correctly in error return.
|
||||||
// Returns:
|
// Returns:
|
||||||
// error of type *object.SplitInfoError if object if raw flag is set and requested object is virtual;
|
// error of type *object.SplitInfoError if object raw flag is set and requested object is virtual;
|
||||||
// object.ErrAlreadyRemoved error if requested object is marked to be removed.
|
// error of type *apistatus.ObjectAlreadyRemoved if requested object is marked to be removed.
|
||||||
func GetObject(prm GetObjectPrm) (*GetObjectRes, error) {
|
func GetObject(prm GetObjectPrm) (*GetObjectRes, error) {
|
||||||
if prm.tokenSession != nil {
|
if prm.tokenSession != nil {
|
||||||
prm.cliPrm.WithinSession(*prm.tokenSession)
|
prm.cliPrm.WithinSession(*prm.tokenSession)
|
||||||
|
@ -193,8 +193,6 @@ func GetObject(prm GetObjectPrm) (*GetObjectRes, error) {
|
||||||
return nil, fmt.Errorf("read payload: %w", err)
|
return nil, fmt.Errorf("read payload: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: #1158 object.ErrAlreadyRemoved never returns
|
|
||||||
|
|
||||||
obj.SetPayload(buf)
|
obj.SetPayload(buf)
|
||||||
|
|
||||||
return &GetObjectRes{
|
return &GetObjectRes{
|
||||||
|
@ -245,8 +243,8 @@ func (x HeadObjectRes) Header() *object.Object {
|
||||||
//
|
//
|
||||||
// Returns any error prevented the operation from completing correctly in error return.
|
// Returns any error prevented the operation from completing correctly in error return.
|
||||||
// Returns:
|
// Returns:
|
||||||
// error of type *object.SplitInfoError if object if raw flag is set and requested object is virtual;
|
// error of type *object.SplitInfoError if object raw flag is set and requested object is virtual;
|
||||||
// object.ErrAlreadyRemoved error if requested object is marked to be removed.
|
// error of type *apistatus.ObjectAlreadyRemoved if requested object is marked to be removed.
|
||||||
func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) {
|
func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) {
|
||||||
if prm.local {
|
if prm.local {
|
||||||
prm.cliPrm.MarkLocal()
|
prm.cliPrm.MarkLocal()
|
||||||
|
@ -272,8 +270,6 @@ func HeadObject(prm HeadObjectPrm) (*HeadObjectRes, error) {
|
||||||
return nil, fmt.Errorf("read object header from NeoFS: %w", err)
|
return nil, fmt.Errorf("read object header from NeoFS: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: #1158 object.ErrAlreadyRemoved never returns
|
|
||||||
|
|
||||||
var hdr object.Object
|
var hdr object.Object
|
||||||
|
|
||||||
if !cliRes.ReadHeader(&hdr) {
|
if !cliRes.ReadHeader(&hdr) {
|
||||||
|
@ -338,8 +334,8 @@ func (x PayloadRangeRes) PayloadRange() []byte {
|
||||||
//
|
//
|
||||||
// Returns any error prevented the operation from completing correctly in error return.
|
// Returns any error prevented the operation from completing correctly in error return.
|
||||||
// Returns:
|
// Returns:
|
||||||
// error of type *object.SplitInfoError if object if raw flag is set and requested object is virtual;
|
// error of type *object.SplitInfoError if object raw flag is set and requested object is virtual;
|
||||||
// object.ErrAlreadyRemoved error if requested object is marked to be removed.
|
// error of type *apistatus.ObjectAlreadyRemoved if requested object is marked to be removed.
|
||||||
func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) {
|
func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) {
|
||||||
if prm.local {
|
if prm.local {
|
||||||
prm.cliPrm.MarkLocal()
|
prm.cliPrm.MarkLocal()
|
||||||
|
@ -368,8 +364,6 @@ func PayloadRange(prm PayloadRangePrm) (*PayloadRangeRes, error) {
|
||||||
return nil, fmt.Errorf("read payload: %w", err)
|
return nil, fmt.Errorf("read payload: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: #1158 object.ErrAlreadyRemoved never returns
|
|
||||||
|
|
||||||
return &PayloadRangeRes{
|
return &PayloadRangeRes{
|
||||||
data: data,
|
data: data,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
Loading…
Reference in a new issue