frostfs-s3-gw/internal/frostfs/crdt/gset.go

125 lines
2.3 KiB
Go

package crdt
import (
"sort"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
)
const (
versionsAddAttr = "S3-CRDT-Versions-Add"
)
type ObjectVersions struct {
name string
objects []*ObjectVersion
addList []string
isSorted bool
}
type ObjectVersion struct {
OjbID oid.ID
Headers map[string]string
CreationEpoch uint64
}
func (o *ObjectVersion) VersionID() string {
return o.OjbID.EncodeToString()
}
func NewObjectVersions(name string) *ObjectVersions {
return &ObjectVersions{name: name}
}
func NewObjectVersion(obj *object.Object) *ObjectVersion {
objID, _ := obj.ID()
headers := make(map[string]string)
for _, attr := range obj.Attributes() {
headers[attr.Key()] = attr.Value()
}
return &ObjectVersion{
OjbID: objID,
Headers: headers,
CreationEpoch: obj.CreationEpoch(),
}
}
func (v *ObjectVersions) Name() string {
return v.name
}
func (v *ObjectVersions) AppendVersion(ov *ObjectVersion) {
addVers := append(splitVersions(ov.Headers[versionsAddAttr]), ov.VersionID())
v.objects = append(v.objects, ov)
for _, add := range addVers {
if !contains(v.addList, add) {
v.addList = append(v.addList, add)
}
}
v.isSorted = false
}
func (v *ObjectVersions) GetCRDTHeaders() map[string]string {
if len(v.objects) == 0 {
return nil
}
headers := make(map[string]string, 2)
if len(v.addList) != 0 {
headers[versionsAddAttr] = v.getAddHeader()
}
return headers
}
func (v *ObjectVersions) GetLast() *ObjectVersion {
if len(v.objects) == 0 {
return nil
}
v.sort()
return v.objects[len(v.objects)-1]
}
func splitVersions(header string) []string {
if len(header) == 0 {
return nil
}
return strings.Split(header, ",")
}
func (v *ObjectVersions) sort() {
if !v.isSorted {
sort.Slice(v.objects, func(i, j int) bool {
return less(v.objects[i], v.objects[j])
})
v.isSorted = true
}
}
func (v *ObjectVersions) getAddHeader() string {
return strings.Join(v.addList, ",")
}
func less(ov1, ov2 *ObjectVersion) bool {
if ov1.CreationEpoch == ov2.CreationEpoch {
return ov1.VersionID() < ov2.VersionID()
}
return ov1.CreationEpoch < ov2.CreationEpoch
}
func contains(list []string, elem string) bool {
for _, item := range list {
if elem == item {
return true
}
}
return false
}