gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/siafile/rscode.go (about) 1 package siafile 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 8 "github.com/klauspost/reedsolomon" 9 10 "gitlab.com/SiaPrime/SiaPrime/modules" 11 ) 12 13 // RSCode is a Reed-Solomon encoder/decoder. It implements the 14 // modules.ErasureCoder interface. 15 type RSCode struct { 16 enc reedsolomon.Encoder 17 18 numPieces int 19 dataPieces int 20 } 21 22 // NumPieces returns the number of pieces returned by Encode. 23 func (rs *RSCode) NumPieces() int { return rs.numPieces } 24 25 // MinPieces return the minimum number of pieces that must be present to 26 // recover the original data. 27 func (rs *RSCode) MinPieces() int { return rs.dataPieces } 28 29 // Encode splits data into equal-length pieces, some containing the original 30 // data and some containing parity data. 31 func (rs *RSCode) Encode(data []byte) ([][]byte, error) { 32 pieces, err := rs.enc.Split(data) 33 if err != nil { 34 return nil, err 35 } 36 return rs.EncodeShards(pieces) 37 } 38 39 // EncodeShards creates the parity shards for an already sharded input. 40 func (rs *RSCode) EncodeShards(pieces [][]byte) ([][]byte, error) { 41 // Check that the caller provided the minimum amount of pieces. 42 if len(pieces) < rs.MinPieces() { 43 return nil, fmt.Errorf("invalid number of pieces given %v < %v", len(pieces), rs.MinPieces()) 44 } 45 // Since all the pieces should have the same length, get the pieceSize from 46 // the first one. 47 pieceSize := len(pieces[0]) 48 // Add the parity shards to pieces. 49 for len(pieces) < rs.NumPieces() { 50 pieces = append(pieces, make([]byte, pieceSize)) 51 } 52 err := rs.enc.Encode(pieces) 53 if err != nil { 54 return nil, err 55 } 56 return pieces, nil 57 } 58 59 // Identifier returns an identifier for an erasure coder which can be used to 60 // identify erasure coders of the same type, dataPieces and parityPieces. 61 func (rs *RSCode) Identifier() modules.ErasureCoderIdentifier { 62 t := rs.Type() 63 dataPieces := rs.MinPieces() 64 parityPieces := rs.NumPieces() - dataPieces 65 id := fmt.Sprintf("%v+%v+%v", binary.BigEndian.Uint32(t[:]), dataPieces, parityPieces) 66 return modules.ErasureCoderIdentifier(id) 67 } 68 69 // Reconstruct recovers the full set of encoded shards from the provided pieces, 70 // of which at least MinPieces must be non-nil. 71 func (rs *RSCode) Reconstruct(pieces [][]byte) error { 72 return rs.enc.Reconstruct(pieces) 73 } 74 75 // Recover recovers the original data from pieces and writes it to w. 76 // pieces should be identical to the slice returned by Encode (length and 77 // order must be preserved), but with missing elements set to nil. 78 func (rs *RSCode) Recover(pieces [][]byte, n uint64, w io.Writer) error { 79 err := rs.enc.ReconstructData(pieces) 80 if err != nil { 81 return err 82 } 83 return rs.enc.Join(w, pieces, int(n)) 84 } 85 86 // SupportsPartialEncoding returns false for the basic reed-solomon encoder. 87 func (rs *RSCode) SupportsPartialEncoding() bool { 88 return false 89 } 90 91 // Type returns the erasure coders type identifier. 92 func (rs *RSCode) Type() modules.ErasureCoderType { 93 return ecReedSolomon 94 } 95 96 // NewRSCode creates a new Reed-Solomon encoder/decoder using the supplied 97 // parameters. 98 func NewRSCode(nData, nParity int) (modules.ErasureCoder, error) { 99 return newRSCode(nData, nParity) 100 } 101 102 // newRSCode creates a new Reed-Solomon encoder/decoder using the supplied 103 // parameters. 104 func newRSCode(nData, nParity int) (*RSCode, error) { 105 enc, err := reedsolomon.New(nData, nParity) 106 if err != nil { 107 return nil, err 108 } 109 return &RSCode{ 110 enc: enc, 111 numPieces: nData + nParity, 112 dataPieces: nData, 113 }, nil 114 }