Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(share): Implement ODSreader #1377

Merged
merged 11 commits into from
Nov 28, 2022
18 changes: 6 additions & 12 deletions share/eds/ods.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import (
"github.com/ipld/go-car/util"
)

var errNilReader = errors.New("ods-reader: can't create ODSReader over nil reader")

// bufferedODSReader will read odsSquareSize amount of leaves from reader into the buffer.
// It exposes the buffer to be read by io.Reader interface implementation
type bufferedODSReader struct {
Expand All @@ -27,13 +25,13 @@ type bufferedODSReader struct {

// ODSReader reads CARv1 encoded data from io.ReadCloser and limits the reader to the CAR header
// and first quadrant (ODS)
func ODSReader(carReader io.ReadCloser) (io.Reader, error) {
func ODSReader(carReader io.Reader) (io.Reader, error) {
if carReader == nil {
return nil, errNilReader
return nil, errors.New("eds: can't create ODSReader over nil reader")
}

odsR := &bufferedODSReader{
carReader: bufio.NewReaderSize(carReader, 4),
carReader: bufio.NewReader(carReader),
buf: new(bytes.Buffer),
}

Expand All @@ -59,12 +57,9 @@ func ODSReader(carReader io.ReadCloser) (io.Reader, error) {
}

func (r *bufferedODSReader) Read(p []byte) (n int, err error) {
// provided slice could be fully filled from buffer without extra reads
if r.buf.Len() > len(p) {
return r.buf.Read(p)
}

if r.current < r.odsSquareSize && r.buf.Len() < len(p) {
// read leafs to the buffer until it has sufficient data to fill provided container or full eds is
walldiss marked this conversation as resolved.
Show resolved Hide resolved
// read
for r.current < r.odsSquareSize && r.buf.Len() < len(p) {
if err := r.readLeaf(); err != nil {
return 0, err
}
Expand Down Expand Up @@ -99,6 +94,5 @@ func (r *bufferedODSReader) readLeaf() error {
r.buf.Write(buf[:n])

_, err = r.buf.ReadFrom(io.LimitReader(r.carReader, int64(l)))

return err
}
32 changes: 32 additions & 0 deletions share/eds/ods_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,35 @@ func TestODSReader(t *testing.T) {
_, err = carReader.Next()
assert.Error(t, io.EOF, err)
}

// TestODSReaderReconstruction ensures that the reader returned from ODSReader provides sufficient
// data for EDS reconstruction
func TestODSReaderReconstruction(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

// launch eds store
edsStore, err := newStore(t)
require.NoError(t, err)
err = edsStore.Start(ctx)
require.NoError(t, err)

// generate random eds data and put it into the store
eds, dah := randomEDS(t)
err = edsStore.Put(ctx, dah, eds)
require.NoError(t, err)

// get CAR reader from store
r, err := edsStore.GetCAR(ctx, dah)
assert.NoError(t, err)

// create ODSReader wrapper based on car reader to limit reads to ODS only
odsR, err := ODSReader(r)
assert.NoError(t, err)

// reconstruct EDS from ODSReader
loaded, err := ReadEDS(ctx, odsR, dah)
assert.NoError(t, err)
require.Equal(t, eds.RowRoots(), loaded.RowRoots())
require.Equal(t, eds.ColRoots(), loaded.ColRoots())
}