storj.io/uplink@v1.13.0/private/storage/streams/segmentupload/encode.go (about) 1 // Copyright (C) 2023 Storj Labs, Inc. 2 // See LICENSE for copying information. 3 4 package segmentupload 5 6 import ( 7 "errors" 8 "io" 9 10 "github.com/zeebo/errs" 11 12 "storj.io/uplink/private/eestream" 13 ) 14 15 // EncodedReader provides a redundant piece for given reader. 16 type EncodedReader struct { 17 r io.Reader 18 rs eestream.RedundancyStrategy 19 num int 20 stripeBuf []byte 21 shareBuf []byte 22 available int 23 err error 24 } 25 26 // NewEncodedReader provides a reader that returns a redundant piece for the 27 // reader using the given redundancy strategy and piece number. 28 func NewEncodedReader(r io.Reader, rs eestream.RedundancyStrategy, num int) *EncodedReader { 29 return &EncodedReader{ 30 r: r, 31 rs: rs, 32 num: num, 33 stripeBuf: make([]byte, rs.StripeSize()), 34 shareBuf: make([]byte, rs.ErasureShareSize()), 35 } 36 } 37 38 // Read reads the redundant piece data. 39 func (er *EncodedReader) Read(p []byte) (n int, err error) { 40 // No need to trace this function because it's very fast and called many times. 41 if er.err != nil { 42 return 0, er.err 43 } 44 45 for len(p) > 0 { 46 if er.available == 0 { 47 // take the next stripe from the segment buffer 48 _, err := io.ReadFull(er.r, er.stripeBuf) 49 if errors.Is(err, io.EOF) { 50 er.err = io.EOF 51 break 52 } else if err != nil { 53 er.err = errs.Wrap(err) 54 return 0, er.err 55 } 56 57 // encode the num-th erasure share 58 err = er.rs.EncodeSingle(er.stripeBuf, er.shareBuf, er.num) 59 if err != nil { 60 er.err = err 61 return 0, err 62 } 63 64 er.available = len(er.shareBuf) 65 } 66 67 off := len(er.shareBuf) - er.available 68 nc := copy(p, er.shareBuf[off:]) 69 p = p[nc:] 70 er.available -= nc 71 n += nc 72 } 73 74 return n, er.err 75 }