frostfs-s3-gw/api/data/tree.go
Denis Kirillov 056f168d77 [#448] multipart: Support removing duplicated parts
Previously after tree split we can have duplicated parts
(several objects and tree node referred to the same part number).
Some of them couldn't be deleted after abort or compete action.

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
2024-09-03 13:20:38 +00:00

209 lines
4.6 KiB
Go

package data
import (
"strconv"
"time"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
const (
UnversionedObjectVersionID = "null"
)
// NodeVersion represent node from tree service.
type NodeVersion struct {
BaseNodeVersion
IsUnversioned bool
IsCombined bool
}
// ExtendedNodeVersion contains additional node info to be able to sort versions by timestamp.
type ExtendedNodeVersion struct {
NodeVersion *NodeVersion
IsLatest bool
DirName string
}
func (e ExtendedNodeVersion) Version() string {
if e.NodeVersion.IsUnversioned {
return UnversionedObjectVersionID
}
return e.NodeVersion.OID.EncodeToString()
}
func (e ExtendedNodeVersion) Name() string {
if e.DirName != "" {
return e.DirName
}
return e.NodeVersion.FilePath
}
// ExtendedObjectInfo contains additional node info to be able to sort versions by timestamp.
type ExtendedObjectInfo struct {
ObjectInfo *ObjectInfo
NodeVersion *NodeVersion
IsLatest bool
}
func (e ExtendedObjectInfo) Version() string {
if e.NodeVersion.IsUnversioned {
return UnversionedObjectVersionID
}
return e.ObjectInfo.ID.EncodeToString()
}
// BaseNodeVersion is minimal node info from tree service.
// Basically used for "system" object.
type BaseNodeVersion struct {
ID uint64
ParenID uint64
OID oid.ID
Timestamp uint64
Size uint64
ETag string
MD5 string
FilePath string
Created *time.Time
Owner *user.ID
IsDeleteMarker bool
CreationEpoch uint64
}
func (v *BaseNodeVersion) GetETag(md5Enabled bool) string {
if md5Enabled && len(v.MD5) > 0 {
return v.MD5
}
return v.ETag
}
// IsFilledExtra returns true is node was created by version of gate v0.29.x and later.
func (v BaseNodeVersion) IsFilledExtra() bool {
return v.Created != nil && v.Owner != nil
}
func (v *BaseNodeVersion) FillExtra(owner *user.ID, created *time.Time, realSize uint64) {
v.Owner = owner
v.Created = created
v.Size = realSize
}
type ObjectTaggingInfo struct {
CnrID cid.ID
ObjName string
VersionID string
}
// MultipartInfo is multipart upload information.
type MultipartInfo struct {
// ID is node id in tree service.
// It's ignored when creating a new multipart upload.
ID uint64
Key string
UploadID string
Owner user.ID
Created time.Time
Meta map[string]string
CopiesNumbers []uint32
Finished bool
CreationEpoch uint64
}
// PartInfo is upload information about part.
type PartInfo struct {
Key string `json:"key"`
UploadID string `json:"uploadId"`
Number int `json:"number"`
OID oid.ID `json:"oid"`
Size uint64 `json:"size"`
ETag string `json:"etag"`
MD5 string `json:"md5"`
Created time.Time `json:"created"`
}
type PartInfoExtended struct {
PartInfo
// Timestamp is used to find the latest version of part info in case of tree split
// when there are multiple nodes for the same part.
Timestamp uint64
}
// ToHeaderString form short part representation to use in S3-Completed-Parts header.
func (p *PartInfo) ToHeaderString() string {
// ETag value contains SHA256 checksum which is used while getting object parts attributes.
return strconv.Itoa(p.Number) + "-" + strconv.FormatUint(p.Size, 10) + "-" + p.ETag
}
func (p *PartInfo) GetETag(md5Enabled bool) string {
if md5Enabled && len(p.MD5) > 0 {
return p.MD5
}
return p.ETag
}
// LockInfo is lock information to create appropriate tree node.
type LockInfo struct {
id uint64
legalHoldOID oid.ID
setLegalHold bool
retentionOID oid.ID
setRetention bool
untilDate string
isCompliance bool
}
func NewLockInfo(id uint64) *LockInfo {
return &LockInfo{id: id}
}
func (l LockInfo) ID() uint64 {
return l.id
}
func (l *LockInfo) SetLegalHold(objID oid.ID) {
l.legalHoldOID = objID
l.setLegalHold = true
}
func (l *LockInfo) ResetLegalHold() {
l.setLegalHold = false
}
func (l LockInfo) LegalHold() oid.ID {
return l.legalHoldOID
}
func (l LockInfo) IsLegalHoldSet() bool {
return l.setLegalHold
}
func (l *LockInfo) SetRetention(objID oid.ID, until string, isCompliance bool) {
l.retentionOID = objID
l.setRetention = true
l.untilDate = until
l.isCompliance = isCompliance
}
func (l LockInfo) IsRetentionSet() bool {
return l.setRetention
}
func (l LockInfo) Retention() oid.ID {
return l.retentionOID
}
func (l LockInfo) UntilDate() string {
return l.untilDate
}
func (l LockInfo) IsCompliance() bool {
return l.isCompliance
}