git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/erasurecode/constructor.go (about) 1 package erasurecode 2 3 import ( 4 "errors" 5 6 objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 7 "github.com/klauspost/reedsolomon" 8 ) 9 10 var ( 11 // ErrMalformedSlice is returned when a slice of EC chunks is inconsistent. 12 ErrMalformedSlice = errors.New("inconsistent EC headers") 13 // ErrInvShardNum is returned from NewConstructor when the number of shards is invalid. 14 ErrInvShardNum = reedsolomon.ErrInvShardNum 15 // ErrMaxShardNum is returned from NewConstructor when the number of shards is too big. 16 ErrMaxShardNum = reedsolomon.ErrMaxShardNum 17 ) 18 19 // MaxShardCount is the maximum number of shards. 20 const MaxShardCount = 256 21 22 // Constructor is a wrapper around encoder allowing to reconstruct objects. 23 // It's methods are not thread-safe. 24 type Constructor struct { 25 enc reedsolomon.Encoder 26 headerLength uint32 27 payloadShards [][]byte 28 headerShards [][]byte 29 } 30 31 // NewConstructor returns new constructor instance. 32 func NewConstructor(dataCount int, parityCount int) (*Constructor, error) { 33 // The library supports up to 65536 shards with some restrictions. 34 // This can easily result in OOM or panic, thus SDK declares it's own restriction. 35 if dataCount+parityCount > MaxShardCount { 36 return nil, ErrMaxShardNum 37 } 38 39 enc, err := reedsolomon.New(dataCount, parityCount) 40 if err != nil { 41 return nil, err 42 } 43 return &Constructor{enc: enc}, nil 44 } 45 46 // clear clears internal state of the constructor, so it can be reused. 47 func (c *Constructor) clear() { 48 c.headerLength = 0 49 c.payloadShards = nil 50 c.headerShards = nil 51 } 52 53 func (c *Constructor) fillHeader(parts []*objectSDK.Object) error { 54 shards := make([][]byte, len(parts)) 55 headerLength := 0 56 for i := range parts { 57 if parts[i] == nil { 58 continue 59 } 60 61 var err error 62 headerLength, err = validatePart(parts, i, headerLength) 63 if err != nil { 64 return err 65 } 66 67 shards[i] = parts[i].GetECHeader().Header() 68 } 69 70 c.headerLength = uint32(headerLength) 71 c.headerShards = shards 72 return nil 73 } 74 75 // fillPayload fills the payload shards. 76 // Currently there is no case when it can be called without reconstructing header, 77 // thus fillHeader() must be called before and this function performs no validation. 78 func (c *Constructor) fillPayload(parts []*objectSDK.Object) { 79 shards := make([][]byte, len(parts)) 80 for i := range parts { 81 if parts[i] == nil { 82 continue 83 } 84 shards[i] = parts[i].Payload() 85 } 86 c.payloadShards = shards 87 }