forked from TrueCloudLab/frostfs-s3-gw
Denis Kirillov
056f168d77
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>
209 lines
4.6 KiB
Go
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
|
|
}
|