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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,6 @@
package common package common
import ( import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object" objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" 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. // PutRes groups the resulting values of Put operation.
type PutRes struct { 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) { func (b *BlobStor) Delete(prm common.DeletePrm) (common.DeleteRes, error) {
if prm.BlobovniczaID == nil { if prm.StorageID == nil {
// Nothing specified, try everything. // Nothing specified, try everything.
res, err := b.deleteBig(prm) res, err := b.deleteBig(prm)
if err == nil || !errors.As(err, new(apistatus.ObjectNotFound)) { 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) return b.deleteSmall(prm)
} }
if *prm.BlobovniczaID == nil { if len(prm.StorageID) == 0 {
return b.deleteBig(prm) return b.deleteBig(prm)
} }
return b.deleteSmall(prm) return b.deleteSmall(prm)

View file

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

View file

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

View file

@ -15,7 +15,7 @@ type IterationElement struct {
addr oid.Address addr oid.Address
blzID *blobovnicza.ID descriptor []byte
} }
// ObjectData returns the stored object in a binary representation. // ObjectData returns the stored object in a binary representation.
@ -23,10 +23,9 @@ func (x IterationElement) ObjectData() []byte {
return x.data return x.data
} }
// BlobovniczaID returns the identifier of Blobovnicza in which object is stored. // Descriptor returns the identifier of storage part where x is stored.
// Returns nil if the object isn't in Blobovnicza. func (x IterationElement) Descriptor() []byte {
func (x IterationElement) BlobovniczaID() *blobovnicza.ID { return x.descriptor
return x.blzID
} }
// Address returns the object address. // Address returns the object address.
@ -89,7 +88,7 @@ func (b *BlobStor) Iterate(prm IteratePrm) (IterateRes, error) {
} }
elem.addr = addr elem.addr = addr
elem.blzID = blobovnicza.NewIDFromBytes([]byte(p)) elem.descriptor = []byte(p)
return prm.handler(elem) 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) return IterateRes{}, fmt.Errorf("blobovniczas iterator failure: %w", err)
} }
elem.blzID = nil elem.descriptor = []byte{}
var fsPrm fstree.IterationPrm var fsPrm fstree.IterationPrm
fsPrm.WithIgnoreErrors(prm.ignoreErrors) 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. // 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. // 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 var prm IteratePrm
prm.SetIterationHandler(func(elem IterationElement) error { 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.IgnoreErrors()
prm.SetErrorHandler(func(addr oid.Address, err error) error { prm.SetErrorHandler(func(addr oid.Address, err error) error {

View file

@ -5,7 +5,6 @@ import (
"os" "os"
"testing" "testing"
"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/common"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test" oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
@ -71,16 +70,16 @@ func TestIterateObjects(t *testing.T) {
require.NoError(t, err) 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)] v, ok := mObjs[string(data)]
require.True(t, ok) require.True(t, ok)
require.Equal(t, v.data, data) require.Equal(t, v.data, data)
if v.big { if v.big {
require.Nil(t, blzID) require.True(t, descriptor != nil && len(descriptor) == 0)
} else { } else {
require.NotNil(t, blzID) require.NotEmpty(t, descriptor)
} }
delete(mObjs, string(data)) delete(mObjs, string(data))

View file

@ -2,11 +2,7 @@
This file describes changes between the metabase versions. This file describes changes between the metabase versions.
## Version 0 ## Current
- Container ID is encoded as base58 string
- Object ID is encoded as base58 string
- Address is encoded as container ID + "/" + object ID
### Primary buckets ### Primary buckets
- Graveyard bucket - Graveyard bucket
@ -53,10 +49,10 @@ This file describes changes between the metabase versions.
- Name: container ID + `_TS` - Name: container ID + `_TS`
- Key: object ID - Key: object ID
- Value: marshaled object - 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` - Name: container ID + `_small`
- Key: object ID - Key: object ID
- Value: blobovnicza ID - Value: storage ID
- Buckets for mapping parent object to the split info - Buckets for mapping parent object to the split info
- Name: container ID + `_root` - Name: container ID + `_root`
- Key: object ID - Key: object ID
@ -85,3 +81,16 @@ This file describes changes between the metabase versions.
- Name: container ID + `_splitid` - Name: container ID + `_splitid`
- Key: split ID - Key: split ID
- Value: list of object IDs - 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), name: smallBucketName(cnr),
key: objKey, key: objKey,
}) })

View file

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

View file

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

View file

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

View file

@ -1,7 +1,6 @@
package shard package shard
import ( import (
"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/common"
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" "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) ln := len(prm.addr)
smalls := make(map[oid.Address]*blobovnicza.ID, ln) smalls := make(map[oid.Address][]byte, ln)
for i := range prm.addr { for i := range prm.addr {
if s.hasWriteCache() { if s.hasWriteCache() {
@ -46,10 +45,10 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
} }
} }
var sPrm meta.IsSmallPrm var sPrm meta.StorageIDPrm
sPrm.WithAddress(prm.addr[i]) sPrm.SetAddress(prm.addr[i])
res, err := s.metaBase.IsSmall(sPrm) res, err := s.metaBase.StorageID(sPrm)
if err != nil { if err != nil {
s.log.Debug("can't get blobovniczaID from metabase", s.log.Debug("can't get blobovniczaID from metabase",
zap.Stringer("object", prm.addr[i]), zap.Stringer("object", prm.addr[i]),
@ -58,8 +57,8 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
continue continue
} }
if res.BlobovniczaID() != nil { if res.StorageID() != nil {
smalls[prm.addr[i]] = res.BlobovniczaID() smalls[prm.addr[i]] = res.StorageID()
} }
} }
@ -72,34 +71,17 @@ func (s *Shard) Delete(prm DeletePrm) (DeleteRes, error) {
} }
for i := range prm.addr { // delete small object for i := range prm.addr { // delete small object
if id, ok := smalls[prm.addr[i]]; ok { var delPrm common.DeletePrm
var delSmallPrm common.DeletePrm delPrm.Address = prm.addr[i]
delSmallPrm.Address = prm.addr[i] id := smalls[prm.addr[i]]
delSmallPrm.BlobovniczaID = id delPrm.StorageID = id
_, err = s.blobStor.Delete(delSmallPrm) _, err = s.blobStor.Delete(delPrm)
if err != nil { if err != nil {
s.log.Debug("can't remove small object from blobStor", s.log.Debug("can't remove small object from blobStor",
zap.Stringer("object_address", prm.addr[i]), zap.Stringer("object_address", prm.addr[i]),
zap.String("error", err.Error())) 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)
if err != nil {
s.log.Debug("can't remove big object from blobStor",
zap.Stringer("object_address", prm.addr[i]),
zap.String("error", err.Error()))
}
} }
return DeleteRes{}, nil return DeleteRes{}, nil

View file

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

View file

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

View file

@ -1,7 +1,6 @@
package shard package shard
import ( 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"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache" "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 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. // Returns the object.ErrObjectIsExpired if the object is presented but already expired.
func (s *Shard) GetRange(prm RngPrm) (RngRes, error) { 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 var getRngPrm common.GetRangePrm
getRngPrm.Address = prm.addr getRngPrm.Address = prm.addr
getRngPrm.Range.SetOffset(prm.off) getRngPrm.Range.SetOffset(prm.off)
getRngPrm.Range.SetLength(prm.ln) getRngPrm.Range.SetLength(prm.ln)
getRngPrm.BlobovniczaID = id getRngPrm.StorageID = id
res, err := stor.GetRange(getRngPrm) res, err := stor.GetRange(getRngPrm)
if err != nil { if err != nil {

View file

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