[#1523] shard: Store generic storage ID in metabase

Allow to extend blobstor with more storage sub-systems. Currently
objects stored in the FSTree have empty byte slice descriptor and object
from blobovnicza tree have the same id as earlier. Each such change in
the identifier formation should be accompanied with metabase version
increase.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-07-06 17:09:50 +03:00 committed by fyrchik
parent 9eb018672c
commit 73f8bb3e5f
27 changed files with 220 additions and 251 deletions

View file

@ -11,3 +11,7 @@ func NewIDFromBytes(v []byte) *ID {
func (id ID) String() string {
return string(id)
}
func (id ID) Bytes() []byte {
return id
}

View file

@ -204,7 +204,7 @@ func (b *Blobovniczas) Put(prm common.PutPrm) (common.PutRes, error) {
return common.PutRes{}, errPutFailed
}
return common.PutRes{BlobovniczaID: id}, nil
return common.PutRes{StorageID: id.Bytes()}, nil
}
// Get reads object from blobovnicza tree.
@ -215,8 +215,9 @@ func (b *Blobovniczas) Get(prm common.GetPrm) (res common.GetRes, err error) {
var bPrm blobovnicza.GetPrm
bPrm.SetAddress(prm.Address)
if prm.BlobovniczaID != nil {
blz, err := b.openBlobovnicza(prm.BlobovniczaID.String())
if prm.StorageID != nil {
id := blobovnicza.NewIDFromBytes(prm.StorageID)
blz, err := b.openBlobovnicza(id.String())
if err != nil {
return res, err
}
@ -265,8 +266,9 @@ func (b *Blobovniczas) Delete(prm common.DeletePrm) (res common.DeleteRes, err e
var bPrm blobovnicza.DeletePrm
bPrm.SetAddress(prm.Address)
if prm.BlobovniczaID != nil {
blz, err := b.openBlobovnicza(prm.BlobovniczaID.String())
if prm.StorageID != nil {
id := blobovnicza.NewIDFromBytes(prm.StorageID)
blz, err := b.openBlobovnicza(id.String())
if err != nil {
return res, err
}
@ -318,8 +320,9 @@ func (b *Blobovniczas) Delete(prm common.DeletePrm) (res common.DeleteRes, err e
// If blobocvnicza ID is specified, only this blobovnicza is processed.
// Otherwise, all Blobovniczas are processed descending weight.
func (b *Blobovniczas) GetRange(prm common.GetRangePrm) (res common.GetRangeRes, err error) {
if prm.BlobovniczaID != nil {
blz, err := b.openBlobovnicza(prm.BlobovniczaID.String())
if prm.StorageID != nil {
id := blobovnicza.NewIDFromBytes(prm.StorageID)
blz, err := b.openBlobovnicza(id.String())
if err != nil {
return common.GetRangeRes{}, err
}
@ -573,7 +576,7 @@ func (b *Blobovniczas) deleteObject(blz *blobovnicza.Blobovnicza, prm blobovnicz
storagelog.Write(b.log,
storagelog.AddressField(dp.Address),
storagelog.OpField("Blobovniczas DELETE"),
zap.Stringer("blobovnicza ID", dp.BlobovniczaID),
zap.Stringer("blobovnicza ID", blobovnicza.NewIDFromBytes(dp.StorageID)),
)
return common.DeleteRes{}, nil

View file

@ -78,7 +78,7 @@ func TestBlobovniczas(t *testing.T) {
// get w/ blobovnicza ID
var prm common.GetPrm
prm.BlobovniczaID = pRes.BlobovniczaID
prm.StorageID = pRes.StorageID
prm.Address = addr
res, err := b.Get(prm)
@ -86,7 +86,7 @@ func TestBlobovniczas(t *testing.T) {
require.Equal(t, obj, res.Object)
// get w/o blobovnicza ID
prm.BlobovniczaID = nil
prm.StorageID = nil
res, err = b.Get(prm)
require.NoError(t, err)
@ -94,7 +94,7 @@ func TestBlobovniczas(t *testing.T) {
// get range w/ blobovnicza ID
var rngPrm common.GetRangePrm
rngPrm.BlobovniczaID = pRes.BlobovniczaID
rngPrm.StorageID = pRes.StorageID
rngPrm.Address = addr
payload := obj.Payload()
@ -109,7 +109,7 @@ func TestBlobovniczas(t *testing.T) {
require.Equal(t, payload[off:off+ln], rngRes.Data)
// get range w/o blobovnicza ID
rngPrm.BlobovniczaID = nil
rngPrm.StorageID = nil
rngRes, err = b.GetRange(rngPrm)
require.NoError(t, err)

View file

@ -1,14 +1,13 @@
package common
import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
// DeletePrm groups the parameters of Delete operation.
type DeletePrm struct {
Address oid.Address
BlobovniczaID *blobovnicza.ID
Address oid.Address
StorageID []byte
}
// DeleteRes groups the resulting values of Delete operation.

View file

@ -1,14 +1,13 @@
package common
import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
type GetPrm struct {
Address oid.Address
BlobovniczaID *blobovnicza.ID
Address oid.Address
StorageID []byte
}
type GetRes struct {

View file

@ -1,15 +1,14 @@
package common
import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
type GetRangePrm struct {
Address oid.Address
Range objectSDK.Range
BlobovniczaID *blobovnicza.ID
Address oid.Address
Range objectSDK.Range
StorageID []byte
}
type GetRangeRes struct {

View file

@ -1,7 +1,6 @@
package common
import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
@ -15,5 +14,5 @@ type PutPrm struct {
// PutRes groups the resulting values of Put operation.
type PutRes struct {
BlobovniczaID *blobovnicza.ID
StorageID []byte
}

View file

@ -10,7 +10,7 @@ import (
)
func (b *BlobStor) Delete(prm common.DeletePrm) (common.DeleteRes, error) {
if prm.BlobovniczaID == nil {
if prm.StorageID == nil {
// Nothing specified, try everything.
res, err := b.deleteBig(prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) {
@ -18,7 +18,7 @@ func (b *BlobStor) Delete(prm common.DeletePrm) (common.DeleteRes, error) {
}
return b.deleteSmall(prm)
}
if *prm.BlobovniczaID == nil {
if len(prm.StorageID) == 0 {
return b.deleteBig(prm)
}
return b.deleteSmall(prm)

View file

@ -14,7 +14,7 @@ import (
// If the descriptor is present, only one sub-storage is tried,
// Otherwise, each sub-storage is tried in order.
func (b *BlobStor) Get(prm common.GetPrm) (common.GetRes, error) {
if prm.BlobovniczaID == nil {
if prm.StorageID == nil {
// Nothing specified, try everything.
res, err := b.getBig(prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) {
@ -22,7 +22,7 @@ func (b *BlobStor) Get(prm common.GetPrm) (common.GetRes, error) {
}
return b.getSmall(prm)
}
if *prm.BlobovniczaID == nil {
if len(prm.StorageID) == 0 {
return b.getBig(prm)
}
return b.getSmall(prm)

View file

@ -14,7 +14,7 @@ import (
// If the descriptor is present, only one sub-storage is tried,
// Otherwise, each sub-storage is tried in order.
func (b *BlobStor) GetRange(prm common.GetRangePrm) (common.GetRangeRes, error) {
if prm.BlobovniczaID == nil {
if prm.StorageID == nil {
// Nothing specified, try everything.
res, err := b.getRangeBig(prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) {
@ -22,7 +22,7 @@ func (b *BlobStor) GetRange(prm common.GetRangePrm) (common.GetRangeRes, error)
}
return b.getRangeSmall(prm)
}
if *prm.BlobovniczaID == nil {
if len(prm.StorageID) == 0 {
return b.getRangeBig(prm)
}
return b.getRangeSmall(prm)

View file

@ -15,7 +15,7 @@ type IterationElement struct {
addr oid.Address
blzID *blobovnicza.ID
descriptor []byte
}
// ObjectData returns the stored object in a binary representation.
@ -23,10 +23,9 @@ func (x IterationElement) ObjectData() []byte {
return x.data
}
// BlobovniczaID returns the identifier of Blobovnicza in which object is stored.
// Returns nil if the object isn't in Blobovnicza.
func (x IterationElement) BlobovniczaID() *blobovnicza.ID {
return x.blzID
// Descriptor returns the identifier of storage part where x is stored.
func (x IterationElement) Descriptor() []byte {
return x.descriptor
}
// Address returns the object address.
@ -89,7 +88,7 @@ func (b *BlobStor) Iterate(prm IteratePrm) (IterateRes, error) {
}
elem.addr = addr
elem.blzID = blobovnicza.NewIDFromBytes([]byte(p))
elem.descriptor = []byte(p)
return prm.handler(elem)
})
@ -103,7 +102,7 @@ func (b *BlobStor) Iterate(prm IteratePrm) (IterateRes, error) {
return IterateRes{}, fmt.Errorf("blobovniczas iterator failure: %w", err)
}
elem.blzID = nil
elem.descriptor = []byte{}
var fsPrm fstree.IterationPrm
fsPrm.WithIgnoreErrors(prm.ignoreErrors)
@ -136,11 +135,11 @@ func (b *BlobStor) Iterate(prm IteratePrm) (IterateRes, error) {
// IterateBinaryObjects is a helper function which iterates over BlobStor and passes binary objects to f.
// Errors related to object reading and unmarshaling are logged and skipped.
func IterateBinaryObjects(blz *BlobStor, f func(addr oid.Address, data []byte, blzID *blobovnicza.ID) error) error {
func IterateBinaryObjects(blz *BlobStor, f func(addr oid.Address, data []byte, descriptor []byte) error) error {
var prm IteratePrm
prm.SetIterationHandler(func(elem IterationElement) error {
return f(elem.Address(), elem.ObjectData(), elem.BlobovniczaID())
return f(elem.Address(), elem.ObjectData(), elem.Descriptor())
})
prm.IgnoreErrors()
prm.SetErrorHandler(func(addr oid.Address, err error) error {

View file

@ -5,7 +5,6 @@ import (
"os"
"testing"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
@ -71,16 +70,16 @@ func TestIterateObjects(t *testing.T) {
require.NoError(t, err)
}
err := IterateBinaryObjects(blobStor, func(_ oid.Address, data []byte, blzID *blobovnicza.ID) error {
err := IterateBinaryObjects(blobStor, func(_ oid.Address, data []byte, descriptor []byte) error {
v, ok := mObjs[string(data)]
require.True(t, ok)
require.Equal(t, v.data, data)
if v.big {
require.Nil(t, blzID)
require.True(t, descriptor != nil && len(descriptor) == 0)
} else {
require.NotNil(t, blzID)
require.NotEmpty(t, descriptor)
}
delete(mObjs, string(data))

View file

@ -2,11 +2,7 @@
This file describes changes between the metabase versions.
## Version 0
- Container ID is encoded as base58 string
- Object ID is encoded as base58 string
- Address is encoded as container ID + "/" + object ID
## Current
### Primary buckets
- Graveyard bucket
@ -53,10 +49,10 @@ This file describes changes between the metabase versions.
- Name: container ID + `_TS`
- Key: object ID
- Value: marshaled object
- Buckets mapping objects to the blobovniczas they are stored in
- Buckets mapping objects to the storage ID they are stored in
- Name: container ID + `_small`
- Key: object ID
- Value: blobovnicza ID
- Value: storage ID
- Buckets for mapping parent object to the split info
- Name: container ID + `_root`
- Key: object ID
@ -85,3 +81,16 @@ This file describes changes between the metabase versions.
- Name: container ID + `_splitid`
- Key: split ID
- Value: list of object IDs
# History
## Version 1
- Metabase now stores generic storage id instead of blobovnicza ID.
## Version 0
- Container ID is encoded as base58 string
- Object ID is encoded as base58 string
- Address is encoded as container ID + "/" + object ID

View file

@ -254,7 +254,7 @@ func delUniqueIndexes(tx *bbolt.Tx, obj *objectSDK.Object, isParent bool) error
})
}
delUniqueIndexItem(tx, namedBucketItem{ // remove from small blobovnicza id index
delUniqueIndexItem(tx, namedBucketItem{ // remove from storage id index
name: smallBucketName(cnr),
key: objKey,
})

View file

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neofs-node/pkg/core/object"
objectCore "github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
storagelog "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/internal/log"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/util"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
@ -27,7 +26,7 @@ type (
type PutPrm struct {
obj *objectSDK.Object
id *blobovnicza.ID
id []byte
}
// PutRes groups the resulting values of Put operation.
@ -38,8 +37,8 @@ func (p *PutPrm) SetObject(obj *objectSDK.Object) {
p.obj = obj
}
// SetBlobovniczaID is a Put option to set blobovnicza ID to save.
func (p *PutPrm) SetBlobovniczaID(id *blobovnicza.ID) {
// SetStorageID is a Put option to set storage ID to save.
func (p *PutPrm) SetStorageID(id []byte) {
p.id = id
}
@ -50,7 +49,6 @@ var (
)
// Put saves object header in metabase. Object payload expected to be cut.
// Big objects have nil blobovniczaID.
//
// Returns an error of type apistatus.ObjectAlreadyRemoved if object has been placed in graveyard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired.
@ -73,7 +71,7 @@ func (db *DB) Put(prm PutPrm) (res PutRes, err error) {
}
func (db *DB) put(
tx *bbolt.Tx, obj *objectSDK.Object, id *blobovnicza.ID,
tx *bbolt.Tx, obj *objectSDK.Object, id []byte,
si *objectSDK.SplitInfo, currEpoch uint64) error {
cnr, ok := obj.ContainerID()
if !ok {
@ -93,11 +91,10 @@ func (db *DB) put(
// most right child and split header overlap parent so we have to
// check if object exists to not overwrite it twice
if exists {
// when storage engine moves small objects from one blobovniczaID
// to another, then it calls metabase.Put method with new blobovniczaID
// and this code should be triggered
// When storage engine moves objects between different sub-storages,
// it calls metabase.Put method with new storage ID, thus triggering this code.
if !isParent && id != nil {
return updateBlobovniczaID(tx, object.AddressOf(obj), id)
return updateStorageID(tx, object.AddressOf(obj), id)
}
// when storage already has last object in split hierarchy and there is
@ -152,7 +149,7 @@ func putUniqueIndexes(
tx *bbolt.Tx,
obj *objectSDK.Object,
si *objectSDK.SplitInfo,
id *blobovnicza.ID,
id []byte,
) error {
isParent := si != nil
addr := object.AddressOf(obj)
@ -190,12 +187,12 @@ func putUniqueIndexes(
return err
}
// index blobovniczaID if it is present
// index storageID if it is present
if id != nil {
err = putUniqueIndexItem(tx, namedBucketItem{
name: smallBucketName(cnr),
key: objKey,
val: *id,
val: id,
})
if err != nil {
return err
@ -423,15 +420,15 @@ func getVarUint(data []byte) (uint64, int, error) {
}
}
// updateBlobovniczaID for existing objects if they were moved from from
// one blobovnicza to another.
func updateBlobovniczaID(tx *bbolt.Tx, addr oid.Address, id *blobovnicza.ID) error {
// updateStorageID for existing objects if they were moved from one
// storage location to another.
func updateStorageID(tx *bbolt.Tx, addr oid.Address, id []byte) error {
bkt, err := tx.CreateBucketIfNotExists(smallBucketName(addr.Container()))
if err != nil {
return err
}
return bkt.Put(objectKey(addr.Object()), *id)
return bkt.Put(objectKey(addr.Object()), id)
}
// updateSpliInfo for existing objects if storage filled with extra information

View file

@ -7,7 +7,6 @@ import (
"time"
"github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
"github.com/nspcc-dev/neofs-node/pkg/util/rand"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
@ -80,42 +79,42 @@ func TestDB_PutBlobovnicaUpdate(t *testing.T) {
db := newDB(t)
raw1 := generateObject(t)
blobovniczaID := blobovnicza.ID{1, 2, 3, 4}
storageID := []byte{1, 2, 3, 4}
// put one object with blobovniczaID
err := metaPut(db, raw1, &blobovniczaID)
// put one object with storageID
err := metaPut(db, raw1, storageID)
require.NoError(t, err)
fetchedBlobovniczaID, err := metaIsSmall(db, object.AddressOf(raw1))
fetchedStorageID, err := metaStorageID(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Equal(t, &blobovniczaID, fetchedBlobovniczaID)
require.Equal(t, storageID, fetchedStorageID)
t.Run("update blobovniczaID", func(t *testing.T) {
newID := blobovnicza.ID{5, 6, 7, 8}
t.Run("update storageID", func(t *testing.T) {
newID := []byte{5, 6, 7, 8}
err := metaPut(db, raw1, &newID)
err := metaPut(db, raw1, newID)
require.NoError(t, err)
fetchedBlobovniczaID, err := metaIsSmall(db, object.AddressOf(raw1))
fetchedBlobovniczaID, err := metaStorageID(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Equal(t, &newID, fetchedBlobovniczaID)
require.Equal(t, newID, fetchedBlobovniczaID)
})
t.Run("update blobovniczaID on bad object", func(t *testing.T) {
t.Run("update storageID on bad object", func(t *testing.T) {
raw2 := generateObject(t)
err := putBig(db, raw2)
require.NoError(t, err)
fetchedBlobovniczaID, err := metaIsSmall(db, object.AddressOf(raw2))
fetchedBlobovniczaID, err := metaStorageID(db, object.AddressOf(raw2))
require.NoError(t, err)
require.Nil(t, fetchedBlobovniczaID)
})
}
func metaPut(db *meta.DB, obj *objectSDK.Object, id *blobovnicza.ID) error {
func metaPut(db *meta.DB, obj *objectSDK.Object, id []byte) error {
var putPrm meta.PutPrm
putPrm.SetObject(obj)
putPrm.SetBlobovniczaID(id)
putPrm.SetStorageID(id)
_, err := db.Put(putPrm)

View file

@ -1,61 +0,0 @@
package meta
import (
"github.com/nspcc-dev/neo-go/pkg/util/slice"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.etcd.io/bbolt"
)
// IsSmallPrm groups the parameters of IsSmall operation.
type IsSmallPrm struct {
addr oid.Address
}
// IsSmallRes groups the resulting values of IsSmall operation.
type IsSmallRes struct {
id *blobovnicza.ID
}
// WithAddress is a IsSmall option to set the object address to check.
func (p *IsSmallPrm) WithAddress(addr oid.Address) {
if p != nil {
p.addr = addr
}
}
// BlobovniczaID returns blobovnicza identifier.
func (r IsSmallRes) BlobovniczaID() *blobovnicza.ID {
return r.id
}
// IsSmall returns blobovniczaID for small objects and nil for big objects.
// Small objects stored in blobovnicza instances. Big objects stored in FS by
// shallow path which is calculated from address and therefore it is not
// indexed in metabase.
func (db *DB) IsSmall(prm IsSmallPrm) (res IsSmallRes, err error) {
db.modeMtx.RLock()
defer db.modeMtx.RUnlock()
err = db.boltDB.View(func(tx *bbolt.Tx) error {
res.id, err = db.isSmall(tx, prm.addr)
return err
})
return
}
func (db *DB) isSmall(tx *bbolt.Tx, addr oid.Address) (*blobovnicza.ID, error) {
smallBucket := tx.Bucket(smallBucketName(addr.Container()))
if smallBucket == nil {
return nil, nil
}
blobovniczaID := smallBucket.Get(objectKey(addr.Object()))
if len(blobovniczaID) == 0 {
return nil, nil
}
return blobovnicza.NewIDFromBytes(slice.Copy(blobovniczaID)), nil
}

View file

@ -1,51 +0,0 @@
package meta_test
import (
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/object"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/stretchr/testify/require"
)
func TestDB_IsSmall(t *testing.T) {
db := newDB(t)
raw1 := generateObject(t)
raw2 := generateObject(t)
blobovniczaID := blobovnicza.ID{1, 2, 3, 4}
// check IsSmall from empty database
fetchedBlobovniczaID, err := metaIsSmall(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Nil(t, fetchedBlobovniczaID)
// put one object with blobovniczaID
err = metaPut(db, raw1, &blobovniczaID)
require.NoError(t, err)
// put one object without blobovniczaID
err = putBig(db, raw2)
require.NoError(t, err)
// check IsSmall for object without blobovniczaID
fetchedBlobovniczaID, err = metaIsSmall(db, object.AddressOf(raw2))
require.NoError(t, err)
require.Nil(t, fetchedBlobovniczaID)
// check IsSmall for object with blobovniczaID
fetchedBlobovniczaID, err = metaIsSmall(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Equal(t, &blobovniczaID, fetchedBlobovniczaID)
}
func metaIsSmall(db *meta.DB, addr oid.Address) (*blobovnicza.ID, error) {
var isSmallPrm meta.IsSmallPrm
isSmallPrm.WithAddress(addr)
r, err := db.IsSmall(isSmallPrm)
return r.BlobovniczaID(), err
}

View file

@ -0,0 +1,53 @@
package meta
import (
"github.com/nspcc-dev/neo-go/pkg/util/slice"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.etcd.io/bbolt"
)
// StorageIDPrm groups the parameters of StorageID operation.
type StorageIDPrm struct {
addr oid.Address
}
// StorageIDRes groups the resulting values of StorageID operation.
type StorageIDRes struct {
id []byte
}
// SetAddress is a StorageID option to set the object address to check.
func (p *StorageIDPrm) SetAddress(addr oid.Address) {
p.addr = addr
}
// StorageID returns storage ID.
func (r StorageIDRes) StorageID() []byte {
return r.id
}
// StorageID returns storage descriptor for objects from the blobstor.
// It is put together with the object can makes get/delete operation faster.
func (db *DB) StorageID(prm StorageIDPrm) (res StorageIDRes, err error) {
err = db.boltDB.View(func(tx *bbolt.Tx) error {
res.id, err = db.storageID(tx, prm.addr)
return err
})
return
}
func (db *DB) storageID(tx *bbolt.Tx, addr oid.Address) ([]byte, error) {
smallBucket := tx.Bucket(smallBucketName(addr.Container()))
if smallBucket == nil {
return nil, nil
}
storageID := smallBucket.Get(objectKey(addr.Object()))
if storageID == nil {
return nil, nil
}
return slice.Copy(storageID), nil
}

View file

@ -0,0 +1,50 @@
package meta_test
import (
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/object"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/stretchr/testify/require"
)
func TestDB_IsSmall(t *testing.T) {
db := newDB(t)
raw1 := generateObject(t)
raw2 := generateObject(t)
storageID := []byte{1, 2, 3, 4}
// check StorageID from empty database
fetchedStorageID, err := metaStorageID(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Nil(t, fetchedStorageID)
// put one object with storageID
err = metaPut(db, raw1, storageID)
require.NoError(t, err)
// put one object without storageID
err = putBig(db, raw2)
require.NoError(t, err)
// check StorageID for object without storageID
fetchedStorageID, err = metaStorageID(db, object.AddressOf(raw2))
require.NoError(t, err)
require.Nil(t, fetchedStorageID)
// check StorageID for object with storageID
fetchedStorageID, err = metaStorageID(db, object.AddressOf(raw1))
require.NoError(t, err)
require.Equal(t, storageID, fetchedStorageID)
}
func metaStorageID(db *meta.DB, addr oid.Address) ([]byte, error) {
var sidPrm meta.StorageIDPrm
sidPrm.SetAddress(addr)
r, err := db.StorageID(sidPrm)
return r.StorageID(), err
}

View file

@ -8,7 +8,7 @@ import (
)
// version contains current metabase version.
const version = 0
const version = 1
var versionKey = []byte("version")

View file

@ -5,7 +5,6 @@ import (
"fmt"
"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/blobstor"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard/mode"
@ -150,7 +149,7 @@ func (s *Shard) refillMetabase() error {
obj := objectSDK.New()
return blobstor.IterateBinaryObjects(s.blobStor, func(addr oid.Address, data []byte, blzID *blobovnicza.ID) error {
return blobstor.IterateBinaryObjects(s.blobStor, func(addr oid.Address, data []byte, descriptor []byte) error {
if err := obj.Unmarshal(data); err != nil {
s.log.Warn("could not unmarshal object",
zap.Stringer("address", addr),
@ -206,7 +205,7 @@ func (s *Shard) refillMetabase() error {
var mPrm meta.PutPrm
mPrm.SetObject(obj)
mPrm.SetBlobovniczaID(blzID)
mPrm.SetStorageID(descriptor)
_, err := s.metaBase.Put(mPrm)
if err != nil && !meta.IsErrRemoved(err) && !errors.Is(err, object.ErrObjectIsExpired) {

View file

@ -1,7 +1,6 @@
package shard
import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
@ -36,7 +35,7 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
ln := len(prm.addr)
smalls := make(map[oid.Address]*blobovnicza.ID, ln)
smalls := make(map[oid.Address][]byte, ln)
for i := range prm.addr {
if s.hasWriteCache() {
@ -46,10 +45,10 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
}
}
var sPrm meta.IsSmallPrm
sPrm.WithAddress(prm.addr[i])
var sPrm meta.StorageIDPrm
sPrm.SetAddress(prm.addr[i])
res, err := s.metaBase.IsSmall(sPrm)
res, err := s.metaBase.StorageID(sPrm)
if err != nil {
s.log.Debug("can't get blobovniczaID from metabase",
zap.Stringer("object", prm.addr[i]),
@ -58,8 +57,8 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
continue
}
if res.BlobovniczaID() != nil {
smalls[prm.addr[i]] = res.BlobovniczaID()
if res.StorageID() != nil {
smalls[prm.addr[i]] = res.StorageID()
}
}
@ -72,31 +71,14 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
}
for i := range prm.addr { // delete small object
if id, ok := smalls[prm.addr[i]]; ok {
var delSmallPrm common.DeletePrm
delSmallPrm.Address = prm.addr[i]
delSmallPrm.BlobovniczaID = id
var delPrm common.DeletePrm
delPrm.Address = prm.addr[i]
id := smalls[prm.addr[i]]
delPrm.StorageID = id
_, err = s.blobStor.Delete(delSmallPrm)
if err != nil {
s.log.Debug("can't remove small object from blobStor",
zap.Stringer("object_address", prm.addr[i]),
zap.String("error", err.Error()))
}
continue
}
var id blobovnicza.ID
// delete big object
var delBigPrm common.DeletePrm
delBigPrm.Address = prm.addr[i]
delBigPrm.BlobovniczaID = &id
_, err = s.blobStor.Delete(delBigPrm)
_, err = s.blobStor.Delete(delPrm)
if err != nil {
s.log.Debug("can't remove big object from blobStor",
s.log.Debug("can't remove small object from blobStor",
zap.Stringer("object_address", prm.addr[i]),
zap.String("error", err.Error()))
}

View file

@ -3,7 +3,6 @@ package shard
import (
"fmt"
"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/common"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
@ -16,7 +15,7 @@ import (
// storFetcher is a type to unify object fetching mechanism in `fetchObjectData`
// method. It represents generalization of `getSmall` and `getBig` methods.
type storFetcher = func(stor *blobstor.BlobStor, id *blobovnicza.ID) (*objectSDK.Object, error)
type storFetcher = func(stor *blobstor.BlobStor, id []byte) (*objectSDK.Object, error)
// GetPrm groups the parameters of Get operation.
type GetPrm struct {
@ -62,10 +61,10 @@ func (r GetRes) HasMeta() bool {
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) Get(prm GetPrm) (GetRes, error) {
cb := func(stor *blobstor.BlobStor, id *blobovnicza.ID) (*objectSDK.Object, error) {
cb := func(stor *blobstor.BlobStor, id []byte) (*objectSDK.Object, error) {
var getPrm common.GetPrm
getPrm.Address = prm.addr
getPrm.BlobovniczaID = id
getPrm.StorageID = id
res, err := stor.Get(getPrm)
if err != nil {
@ -131,21 +130,15 @@ func (s *Shard) fetchObjectData(addr oid.Address, skipMeta bool, cb storFetcher,
return nil, false, errNotFound
}
var mPrm meta.IsSmallPrm
mPrm.WithAddress(addr)
var mPrm meta.StorageIDPrm
mPrm.SetAddress(addr)
mRes, err := s.metaBase.IsSmall(mPrm)
mRes, err := s.metaBase.StorageID(mPrm)
if err != nil {
return nil, true, fmt.Errorf("can't fetch blobovnicza id from metabase: %w", err)
}
blobovniczaID := mRes.BlobovniczaID()
if blobovniczaID == nil {
var id blobovnicza.ID
blobovniczaID = &id
}
res, err = cb(s.blobStor, blobovniczaID)
res, err = cb(s.blobStor, mRes.StorageID())
return res, true, err
}

View file

@ -61,7 +61,7 @@ func (s *Shard) Put(prm PutPrm) (PutRes, error) {
if !m.NoMetabase() {
var pPrm meta.PutPrm
pPrm.SetObject(prm.obj)
pPrm.SetBlobovniczaID(res.BlobovniczaID)
pPrm.SetStorageID(res.StorageID)
if _, err := s.metaBase.Put(pPrm); err != nil {
// may we need to handle this case in a special way
// since the object has been successfully written to BlobStor

View file

@ -1,7 +1,6 @@
package shard
import (
"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/common"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
@ -67,12 +66,12 @@ func (r RngRes) HasMeta() bool {
// Returns an error of type apistatus.ObjectAlreadyRemoved if the requested object has been marked as removed in shard.
// Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) GetRange(prm RngPrm) (RngRes, error) {
cb := func(stor *blobstor.BlobStor, id *blobovnicza.ID) (*object.Object, error) {
cb := func(stor *blobstor.BlobStor, id []byte) (*object.Object, error) {
var getRngPrm common.GetRangePrm
getRngPrm.Address = prm.addr
getRngPrm.Range.SetOffset(prm.off)
getRngPrm.Range.SetLength(prm.ln)
getRngPrm.BlobovniczaID = id
getRngPrm.StorageID = id
res, err := stor.GetRange(getRngPrm)
if err != nil {

View file

@ -5,7 +5,6 @@ import (
"time"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/fstree"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
@ -228,7 +227,7 @@ func (c *cache) flushWorker(num int) {
// writeObject is used to write object directly to the main storage.
func (c *cache) writeObject(obj *object.Object, metaOnly bool) error {
var id *blobovnicza.ID
var descriptor []byte
if !metaOnly {
var prm common.PutPrm
@ -239,12 +238,12 @@ func (c *cache) writeObject(obj *object.Object, metaOnly bool) error {
return err
}
id = res.BlobovniczaID
descriptor = res.StorageID
}
var pPrm meta.PutPrm
pPrm.SetObject(obj)
pPrm.SetBlobovniczaID(id)
pPrm.SetStorageID(descriptor)
_, err := c.metabase.Put(pPrm)
return err