forked from TrueCloudLab/frostfs-api-go
[#372] object: Add object notification attributes
Also, add functions for parsing and setting object notifications. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
aabc2dd927
commit
4007aa86f4
1 changed files with 157 additions and 0 deletions
|
@ -1,5 +1,11 @@
|
||||||
package object
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// SysAttributePrefix is a prefix of key to system attribute.
|
// SysAttributePrefix is a prefix of key to system attribute.
|
||||||
const SysAttributePrefix = "__NEOFS__"
|
const SysAttributePrefix = "__NEOFS__"
|
||||||
|
|
||||||
|
@ -9,4 +15,155 @@ const (
|
||||||
|
|
||||||
// SysAttributeExpEpoch tells GC to delete object after that epoch.
|
// SysAttributeExpEpoch tells GC to delete object after that epoch.
|
||||||
SysAttributeExpEpoch = SysAttributePrefix + "EXPIRATION_EPOCH"
|
SysAttributeExpEpoch = SysAttributePrefix + "EXPIRATION_EPOCH"
|
||||||
|
|
||||||
|
// SysAttributeTickEpoch defines what epoch must produce object
|
||||||
|
// notification.
|
||||||
|
SysAttributeTickEpoch = SysAttributePrefix + "TICK_EPOCH"
|
||||||
|
|
||||||
|
// SysAttributeTickTopic defines what topic object notification
|
||||||
|
// must be sent to.
|
||||||
|
SysAttributeTickTopic = SysAttributePrefix + "TICK_TOPIC"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NotificationInfo groups information about object notification
|
||||||
|
// that can be written to object.
|
||||||
|
//
|
||||||
|
// Topic is an optional field.
|
||||||
|
type NotificationInfo struct {
|
||||||
|
epoch uint64
|
||||||
|
topic string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Epoch returns object notification tick
|
||||||
|
// epoch.
|
||||||
|
func (n NotificationInfo) Epoch() uint64 {
|
||||||
|
return n.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEpoch sets object notification tick
|
||||||
|
// epoch.
|
||||||
|
func (n *NotificationInfo) SetEpoch(epoch uint64) {
|
||||||
|
n.epoch = epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Topic return optional object notification
|
||||||
|
// topic.
|
||||||
|
func (n NotificationInfo) Topic() string {
|
||||||
|
return n.topic
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTopic sets optional object notification
|
||||||
|
// topic.
|
||||||
|
func (n *NotificationInfo) SetTopic(topic string) {
|
||||||
|
n.topic = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteNotificationInfo writes NotificationInfo to the Object via attributes. Object must not be nil.
|
||||||
|
//
|
||||||
|
// Existing notification attributes are expected to be key-unique, otherwise undefined behavior.
|
||||||
|
func WriteNotificationInfo(o *Object, ni NotificationInfo) {
|
||||||
|
h := o.GetHeader()
|
||||||
|
if h == nil {
|
||||||
|
h = new(Header)
|
||||||
|
o.SetHeader(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
attrs = h.GetAttributes()
|
||||||
|
|
||||||
|
epoch = strconv.FormatUint(ni.Epoch(), 10)
|
||||||
|
topic = ni.Topic()
|
||||||
|
|
||||||
|
changedEpoch bool
|
||||||
|
changedTopic bool
|
||||||
|
deleteIndex = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := range attrs {
|
||||||
|
switch attrs[i].GetKey() {
|
||||||
|
case SysAttributeTickEpoch:
|
||||||
|
attrs[i].SetValue(epoch)
|
||||||
|
changedEpoch = true
|
||||||
|
case SysAttributeTickTopic:
|
||||||
|
changedTopic = true
|
||||||
|
|
||||||
|
if topic == "" {
|
||||||
|
deleteIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs[i].SetValue(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
if changedEpoch && changedTopic {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if deleteIndex != -1 {
|
||||||
|
// approach without allocation/waste
|
||||||
|
// coping works since the attributes
|
||||||
|
// order is not important
|
||||||
|
attrs[deleteIndex] = attrs[len(attrs)-1]
|
||||||
|
attrs = attrs[:len(attrs)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyAttrs := make([]*Attribute, 0, 2)
|
||||||
|
|
||||||
|
if !changedEpoch {
|
||||||
|
eAttr := new(Attribute)
|
||||||
|
eAttr.SetKey(SysAttributeTickEpoch)
|
||||||
|
eAttr.SetValue(epoch)
|
||||||
|
|
||||||
|
notifyAttrs = append(notifyAttrs, eAttr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !changedTopic && topic != "" {
|
||||||
|
tAttr := new(Attribute)
|
||||||
|
tAttr.SetKey(SysAttributeTickTopic)
|
||||||
|
tAttr.SetValue(topic)
|
||||||
|
|
||||||
|
notifyAttrs = append(notifyAttrs, tAttr)
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs = append(attrs, notifyAttrs...)
|
||||||
|
|
||||||
|
h.SetAttributes(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNotificationNotSet means that object does not have notification.
|
||||||
|
var ErrNotificationNotSet = errors.New("notification for object is not set")
|
||||||
|
|
||||||
|
// GetNotificationInfo looks for object notification attributes. Object must not be nil.
|
||||||
|
// Returns ErrNotificationNotSet if no corresponding attributes
|
||||||
|
// were found.
|
||||||
|
//
|
||||||
|
// Existing notification attributes are expected to be key-unique, otherwise undefined behavior.
|
||||||
|
func GetNotificationInfo(o *Object) (*NotificationInfo, error) {
|
||||||
|
var (
|
||||||
|
foundEpoch bool
|
||||||
|
ni = new(NotificationInfo)
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, attr := range o.GetHeader().GetAttributes() {
|
||||||
|
switch key := attr.GetKey(); key {
|
||||||
|
case SysAttributeTickEpoch:
|
||||||
|
epoch, err := strconv.ParseUint(attr.GetValue(), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse epoch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ni.SetEpoch(epoch)
|
||||||
|
|
||||||
|
foundEpoch = true
|
||||||
|
case SysAttributeTickTopic:
|
||||||
|
ni.SetTopic(attr.GetValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundEpoch {
|
||||||
|
return nil, ErrNotificationNotSet
|
||||||
|
}
|
||||||
|
|
||||||
|
return ni, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue