232 lines
5.1 KiB
Go
232 lines
5.1 KiB
Go
package jcstypes
|
||
|
||
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 {
|
||
serder.Metadata `union:"none"`
|
||
Type string `json:"type"`
|
||
}
|
||
|
||
func (r *NoneRedundancy) GetRedundancyType() string {
|
||
return "none"
|
||
}
|
||
|
||
func NewNoneRedundancy() *NoneRedundancy {
|
||
return &NoneRedundancy{
|
||
Type: "none",
|
||
}
|
||
}
|
||
|
||
var DefaultRepRedundancy = *NewRepRedundancy(2)
|
||
|
||
type RepRedundancy struct {
|
||
serder.Metadata `union:"rep"`
|
||
Type string `json:"type"`
|
||
RepCount int `json:"repCount"`
|
||
}
|
||
|
||
func (r *RepRedundancy) GetRedundancyType() string {
|
||
return "rep"
|
||
}
|
||
|
||
func NewRepRedundancy(repCount int) *RepRedundancy {
|
||
return &RepRedundancy{
|
||
Type: "rep",
|
||
RepCount: repCount,
|
||
}
|
||
}
|
||
|
||
var DefaultECRedundancy = *NewECRedundancy(2, 3, 1024*1024*5)
|
||
|
||
type ECRedundancy struct {
|
||
serder.Metadata `union:"ec"`
|
||
Type string `json:"type"`
|
||
K int `json:"k"`
|
||
N int `json:"n"`
|
||
ChunkSize int `json:"chunkSize"`
|
||
}
|
||
|
||
func (b *ECRedundancy) GetRedundancyType() string {
|
||
return "ec"
|
||
}
|
||
|
||
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 {
|
||
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 (b *LRCRedundancy) GetRedundancyType() string {
|
||
return "lrc"
|
||
}
|
||
|
||
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 {
|
||
serder.Metadata `union:"segment"`
|
||
Type string `json:"type"`
|
||
Segments []int64 `json:"segments"` // 每一段的大小
|
||
}
|
||
|
||
func (r *SegmentRedundancy) GetRedundancyType() string {
|
||
return "segment"
|
||
}
|
||
|
||
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 {
|
||
serder.Metadata `union:"multipartUpload"`
|
||
Type string `json:"type"`
|
||
}
|
||
|
||
func (r *MultipartUploadRedundancy) GetRedundancyType() string {
|
||
return "multipartUpload"
|
||
}
|
||
|
||
func NewMultipartUploadRedundancy() *MultipartUploadRedundancy {
|
||
return &MultipartUploadRedundancy{
|
||
Type: "multipartUpload",
|
||
}
|
||
}
|