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  }