frostfs-node/pkg/local_object_storage/metabase/select_proto_access.go

262 lines
5.8 KiB
Go
Raw Normal View History

package meta
import (
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/util/logicerr"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/VictoriaMetrics/easyproto"
)
var errMalformedObject = errors.New("malformed object")
type protoAttribute struct {
found bool
value string
}
type protoHeader struct {
attribute protoAttribute
ecHeader protoECHeader
}
type protoECHeader struct {
parentID protoOID
attribute protoAttribute
}
type protoOID oid.ID
type protoIter struct {
fc easyproto.FieldContext
data []byte
failed bool
eof bool
}
func newProtoIter(data []byte, ok bool) protoIter {
return protoIter{data: data, failed: !ok}
}
func (p *protoIter) err() error {
if p.failed {
return errMalformedObject
}
return nil
}
func (p *protoIter) finished() bool {
return p.failed || p.eof
}
func (p *protoIter) next() {
if p.failed {
return
}
if len(p.data) == 0 {
p.eof = true
return
}
data, err := p.fc.NextField(p.data)
if err != nil {
p.failed = true
return
}
p.data = data
}
func (p *protoOID) fill(fc easyproto.FieldContext) error {
iter := newProtoIter(fc.MessageData())
for iter.next(); !iter.finished(); iter.next() {
if iter.fc.FieldNum == 1 { // Wire number for `id` field.
rawID, ok := iter.fc.Bytes()
if !ok {
return errMalformedObject
}
return (*oid.ID)(p).Decode(rawID)
}
}
return iter.err()
}
func (p *protoAttribute) fill(fc easyproto.FieldContext, attribute string) error {
var key, value string
iter := newProtoIter(fc.MessageData())
for iter.next(); !iter.finished(); iter.next() {
var ok bool
switch iter.fc.FieldNum {
case 1: // Wire number for `key` field.
key, ok = iter.fc.String()
case 2: // Wire number for `value` field.
value, ok = iter.fc.String()
default:
continue
}
if !ok {
return errMalformedObject
}
}
if key == attribute {
p.found = true
p.value = value
}
return iter.err()
}
func (p *protoECHeader) fill(fc easyproto.FieldContext, attribute string) error {
iter := newProtoIter(fc.MessageData())
for iter.next(); !iter.finished(); iter.next() {
var err error
switch iter.fc.FieldNum {
case 1: // Wire number for `parent` field.
err = p.parentID.fill(iter.fc)
case 8: // Wire number for `parent_attributes` field.
err = p.attribute.fill(iter.fc, attribute)
}
if err != nil {
return err
}
}
return iter.err()
}
func (p *protoHeader) fill(fc easyproto.FieldContext, attribute string) error {
iter := newProtoIter(fc.MessageData())
for iter.next(); !iter.finished(); iter.next() {
var err error
switch iter.fc.FieldNum {
case 10: // Wire number for `attributes` field.
err = p.attribute.fill(iter.fc, attribute)
case 12: // Wire number for `ec` field.
err = p.ecHeader.fill(iter.fc, attribute)
}
if err != nil {
return err
}
}
return iter.err()
}
type attributeMatchResult struct {
attribute protoAttribute
isEC bool
parentID oid.ID
}
func attributeValueRaw(src []byte, attribute string) (attributeMatchResult, error) {
iter := newProtoIter(src, true)
for iter.next(); !iter.finished(); iter.next() {
if iter.fc.FieldNum == 3 { // Wire number for `header` field.
var p protoHeader
if err := p.fill(iter.fc, attribute); err != nil {
return attributeMatchResult{}, err
}
if p.ecHeader.attribute.found {
return attributeMatchResult{
attribute: p.ecHeader.attribute,
isEC: true,
parentID: oid.ID(p.ecHeader.parentID),
}, nil
} else {
return attributeMatchResult{attribute: p.attribute}, nil
}
}
}
return attributeMatchResult{}, iter.err()
}
func parentFromChild(src []byte) ([]byte, error) {
iter := newProtoIter(src, true)
for iter.next(); !iter.finished(); iter.next() {
if iter.fc.FieldNum == 3 {
return parentFromChildHeader(iter.fc)
}
}
return nil, logicerr.Wrap(new(apistatus.ObjectNotFound))
}
func parentFromChildHeader(fc easyproto.FieldContext) ([]byte, error) {
iter := newProtoIter(fc.MessageData())
for iter.next(); !iter.finished(); iter.next() {
if iter.fc.FieldNum == 11 {
return parentFromSplitHeader(iter.fc)
}
}
return nil, logicerr.Wrap(new(apistatus.ObjectNotFound))
}
func parentFromSplitHeader(fc easyproto.FieldContext) ([]byte, error) {
iter := newProtoIter(fc.MessageData())
var parentID, parentSig, parentHdr []byte
for iter.next(); !iter.finished(); iter.next() {
var ok bool
switch iter.fc.FieldNum {
case 1: // parent id
parentID, ok = iter.fc.MessageData()
case 3: // parent signature
parentSig, ok = iter.fc.MessageData()
case 4: // parent header
parentHdr, ok = iter.fc.MessageData()
default:
continue
}
if !ok {
return nil, errMalformedObject
}
}
if parentSig == nil || parentHdr == nil {
return nil, logicerr.Wrap(new(apistatus.ObjectNotFound))
}
h := &header{
parentID: parentID,
parentSig: parentSig,
parentHdr: parentHdr,
}
return h.StableMarshal(make([]byte, h.StableSize())), nil
}
type (
header struct {
parentID bs
parentSig bs
parentHdr bs
}
)
func (o *header) StableSize() int {
var size int
size += proto.NestedStructureSize(1, &o.parentID)
size += proto.NestedStructureSize(2, &o.parentSig)
size += proto.NestedStructureSize(3, &o.parentHdr)
return size
}
func (o *header) StableMarshal(buf []byte) []byte {
var offset int
offset += proto.NestedStructureMarshal(1, buf[offset:], &o.parentID)
offset += proto.NestedStructureMarshal(2, buf[offset:], &o.parentSig)
offset += proto.NestedStructureMarshal(3, buf[offset:], &o.parentHdr)
return buf[:offset]
}
type bs []byte
func (b *bs) StableSize() int {
return len(*b)
}
func (b *bs) StableMarshal(dst []byte) []byte {
copy(dst, *b)
return dst[:len(*b)]
}