package types import ( "github.com/samber/lo" "gitlink.org.cn/cloudream/common/pkgs/types" "gitlink.org.cn/cloudream/common/utils/math2" "gitlink.org.cn/cloudream/common/utils/serder" ) type Redundancy interface { GetRedundancyType() string } var RedundancyUnion = serder.UseTypeUnionInternallyTagged(types.Ref(types.NewTypeUnion[Redundancy]( (*NoneRedundancy)(nil), (*RepRedundancy)(nil), (*ECRedundancy)(nil), (*LRCRedundancy)(nil), (*SegmentRedundancy)(nil), (*MultipartUploadRedundancy)(nil), )), "type") type NoneRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"none"` Type string `json:"type"` } func NewNoneRedundancy() *NoneRedundancy { return &NoneRedundancy{ Type: "none", } } var DefaultRepRedundancy = *NewRepRedundancy(2) type RepRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"rep"` Type string `json:"type"` RepCount int `json:"repCount"` } func NewRepRedundancy(repCount int) *RepRedundancy { return &RepRedundancy{ Type: "rep", RepCount: repCount, } } var DefaultECRedundancy = *NewECRedundancy(2, 3, 1024*1024*5) type ECRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"ec"` Type string `json:"type"` K int `json:"k"` N int `json:"n"` ChunkSize int `json:"chunkSize"` } func NewECRedundancy(k int, n int, chunkSize int) *ECRedundancy { return &ECRedundancy{ Type: "ec", K: k, N: n, ChunkSize: chunkSize, } } func (b *ECRedundancy) StripSize() int64 { return int64(b.ChunkSize) * int64(b.K) } var DefaultLRCRedundancy = *NewLRCRedundancy(2, 4, []int{2}, 1024*1024*5) type LRCRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"lrc"` Type string `json:"type"` K int `json:"k"` N int `json:"n"` Groups []int `json:"groups"` ChunkSize int `json:"chunkSize"` } func NewLRCRedundancy(k int, n int, groups []int, chunkSize int) *LRCRedundancy { return &LRCRedundancy{ Type: "lrc", K: k, N: n, Groups: groups, ChunkSize: chunkSize, } } // 判断指定块属于哪个组。如果都不属于,则返回-1。 func (b *LRCRedundancy) FindGroup(idx int) int { if idx >= b.N-len(b.Groups) { return idx - (b.N - len(b.Groups)) } for i, group := range b.Groups { if idx < group { return i } idx -= group } return -1 } // M = N - len(Groups),即数据块+校验块的总数,不包括组校验块。 func (b *LRCRedundancy) M() int { return b.N - len(b.Groups) } func (b *LRCRedundancy) GetGroupElements(grp int) []int { var idxes []int grpStart := 0 for i := 0; i < grp; i++ { grpStart += b.Groups[i] } for i := 0; i < b.Groups[grp]; i++ { idxes = append(idxes, grpStart+i) } idxes = append(idxes, b.N-len(b.Groups)+grp) return idxes } type SegmentRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"segment"` Type string `json:"type"` Segments []int64 `json:"segments"` // 每一段的大小 } func NewSegmentRedundancy(totalSize int64, segmentCount int) *SegmentRedundancy { return &SegmentRedundancy{ Type: "segment", Segments: math2.SplitN(totalSize, segmentCount), } } func (r *SegmentRedundancy) SegmentCount() int { return len(r.Segments) } func (r *SegmentRedundancy) CalcSegmentStart(index int) int64 { return lo.Sum(r.Segments[:index]) } // 计算指定位置取整到最近的段的起始位置。 func (r *SegmentRedundancy) FloorSegmentPosition(pos int64) int64 { fpos := int64(0) for _, segLen := range r.Segments { segEnd := fpos + segLen if pos < segEnd { break } fpos += segLen } return fpos } // 计算指定范围内的段索引范围,参数和返回值所代表的范围都是左闭右开的。 // 如果end == -1,则代表计算从start到最后一个字节的范围。 func (b *SegmentRedundancy) CalcSegmentRange(start int64, end *int64) (segIdxStart int, segIdxEnd int) { segIdxStart = len(b.Segments) segIdxEnd = len(b.Segments) // 找到第一个包含start的段索引 segStart := int64(0) for i, segLen := range b.Segments { segEnd := segStart + segLen if start < segEnd { segIdxStart = i break } segStart += segLen } if end != nil { // 找到第一个包含end的段索引 segStart = int64(0) for i, segLen := range b.Segments { segEnd := segStart + segLen if *end <= segEnd { segIdxEnd = i + 1 break } segStart += segLen } } return } type MultipartUploadRedundancy struct { Redundancy `json:"-"` serder.Metadata `union:"multipartUpload"` Type string `json:"type"` } func NewMultipartUploadRedundancy() *MultipartUploadRedundancy { return &MultipartUploadRedundancy{ Type: "multipartUpload", } }