frostfs-node/pkg/local_object_storage/metabase/get.go
Evgenii Stratonikov f58234aa2f [#1559] metabase: Remove public functions
Reduce public interface of this package. Later each result will contain
an additional status, so it makes more sense to use the same functions
and result processing everywhere.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
2022-07-21 17:56:06 +03:00

173 lines
4 KiB
Go

package meta
import (
"fmt"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.etcd.io/bbolt"
)
// GetPrm groups the parameters of Get operation.
type GetPrm struct {
addr oid.Address
raw bool
}
// GetRes groups the resulting values of Get operation.
type GetRes struct {
hdr *objectSDK.Object
}
// WithAddress is a Get option to set the address of the requested object.
//
// Option is required.
func (p *GetPrm) WithAddress(addr oid.Address) {
if p != nil {
p.addr = addr
}
}
// WithRaw is a Get option to set raw flag value. If flag is unset, then Get
// returns header of virtual object, otherwise it returns SplitInfo of virtual
// object.
func (p *GetPrm) WithRaw(raw bool) {
if p != nil {
p.raw = raw
}
}
// Header returns the requested object header.
func (r GetRes) Header() *objectSDK.Object {
return r.hdr
}
// Get returns object header for specified address.
//
// Returns an error of type apistatus.ObjectNotFound if object is missing in DB.
// Returns an error of type apistatus.ObjectAlreadyRemoved if object has been placed in graveyard.
func (db *DB) Get(prm GetPrm) (res GetRes, err error) {
err = db.boltDB.View(func(tx *bbolt.Tx) error {
res.hdr, err = db.get(tx, prm.addr, true, prm.raw)
return err
})
return
}
func (db *DB) get(tx *bbolt.Tx, addr oid.Address, checkGraveyard, raw bool) (*objectSDK.Object, error) {
key := objectKey(addr.Object())
if checkGraveyard {
switch inGraveyard(tx, addr) {
case 1:
var errNotFound apistatus.ObjectNotFound
return nil, errNotFound
case 2:
var errRemoved apistatus.ObjectAlreadyRemoved
return nil, errRemoved
}
}
cnr := addr.Container()
obj := objectSDK.New()
// check in primary index
data := getFromBucket(tx, primaryBucketName(cnr), key)
if len(data) != 0 {
return obj, obj.Unmarshal(data)
}
// if not found then check in tombstone index
data = getFromBucket(tx, tombstoneBucketName(cnr), key)
if len(data) != 0 {
return obj, obj.Unmarshal(data)
}
// if not found then check in storage group index
data = getFromBucket(tx, storageGroupBucketName(cnr), key)
if len(data) != 0 {
return obj, obj.Unmarshal(data)
}
// if not found then check in locker index
data = getFromBucket(tx, bucketNameLockers(cnr), key)
if len(data) != 0 {
return obj, obj.Unmarshal(data)
}
// if not found then check if object is a virtual
return getVirtualObject(tx, cnr, key, raw)
}
func getFromBucket(tx *bbolt.Tx, name, key []byte) []byte {
bkt := tx.Bucket(name)
if bkt == nil {
return nil
}
return bkt.Get(key)
}
func getVirtualObject(tx *bbolt.Tx, cnr cid.ID, key []byte, raw bool) (*objectSDK.Object, error) {
if raw {
return nil, getSplitInfoError(tx, cnr, key)
}
parentBucket := tx.Bucket(parentBucketName(cnr))
if parentBucket == nil {
var errNotFound apistatus.ObjectNotFound
return nil, errNotFound
}
relativeLst, err := decodeList(parentBucket.Get(key))
if err != nil {
return nil, err
}
if len(relativeLst) == 0 { // this should never happen though
var errNotFound apistatus.ObjectNotFound
return nil, errNotFound
}
// pick last item, for now there is not difference which address to pick
// but later list might be sorted so first or last value can be more
// prioritized to choose
virtualOID := relativeLst[len(relativeLst)-1]
data := getFromBucket(tx, primaryBucketName(cnr), virtualOID)
child := objectSDK.New()
err = child.Unmarshal(data)
if err != nil {
return nil, fmt.Errorf("can't unmarshal child with parent: %w", err)
}
par := child.Parent()
if par == nil { // this should never happen though
var errNotFound apistatus.ObjectNotFound
return nil, errNotFound
}
return par, nil
}
func getSplitInfoError(tx *bbolt.Tx, cnr cid.ID, key []byte) error {
splitInfo, err := getSplitInfo(tx, cnr, key)
if err == nil {
return objectSDK.NewSplitInfoError(splitInfo)
}
var errNotFound apistatus.ObjectNotFound
return errNotFound
}