Skip to content

Commit

Permalink
Seek to start before index generation in ReadOnly blockstore
Browse files Browse the repository at this point in the history
The blockstore reads the version of the given CAR payload to determine
whether to generate an index for the given payload or not. When the
payload represents a CARv1 and no index is specified, the backing reader
is passed on for index generation. But the version is already read from
the stream. Seek to the beginning of the backing reader before
generating the index so that the index generation mechanism receives the
complete CARv1.

Fixes #265
  • Loading branch information
masih committed Nov 18, 2021
1 parent 6d94b7b commit fa995b9
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 0 deletions.
4 changes: 4 additions & 0 deletions v2/blockstore/readonly.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ func generateIndex(at io.ReaderAt, opts ...carv2.Option) (index.Index, error) {
switch r := at.(type) {
case io.ReadSeeker:
rs = r
// The version may have been read from the given io.ReaderAt; therefore move back to the begining.
if _, err := rs.Seek(0, io.SeekStart); err != nil {
return nil, err
}
default:
rs = internalio.NewOffsetReadSeeker(r, 0)
}
Expand Down
28 changes: 28 additions & 0 deletions v2/blockstore/readonly_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package blockstore

import (
"bytes"
"context"
"io"
"io/ioutil"
"os"
"testing"
"time"
Expand Down Expand Up @@ -269,3 +271,29 @@ func TestReadOnlyErrorAfterClose(t *testing.T) {
// TODO: test that closing blocks if an AllKeysChan operation is
// in progress.
}

func TestNewReadOnly_CarV1WithoutIndexWorksAsExpected(t *testing.T) {
carV1Bytes, err := ioutil.ReadFile("../testdata/sample-v1.car")
require.NoError(t, err)

reader := bytes.NewReader(carV1Bytes)
v1r, err := carv1.NewCarReader(reader)
require.NoError(t, err)
require.Equal(t, uint64(1), v1r.Header.Version)

// Pick the first block in CARv1 as candidate to check `Get` works.
wantBlock, err := v1r.Next()
require.NoError(t, err)

// Seek back to the begining of the CARv1 payload.
_, err = reader.Seek(0, io.SeekStart)
require.NoError(t, err)

subject, err := NewReadOnly(reader, nil, UseWholeCIDs(true))
require.NoError(t, err)

// Require that the block is found via ReadOnly API and contetns are as expected.
gotBlock, err := subject.Get(wantBlock.Cid())
require.NoError(t, err)
require.Equal(t, wantBlock, gotBlock)
}

0 comments on commit fa995b9

Please sign in to comment.