Skip to content

Commit 62f4a1c

Browse files
authored
Merge pull request #56 from ipfs/fix/file-seek
fix: large files support io.SeekCurrent
2 parents 09dd8c8 + 3cad2f7 commit 62f4a1c

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

file/file_test.go

+115
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import (
77
"io"
88
"testing"
99

10+
ipfsutil "github.com/ipfs/go-ipfs-util"
1011
"github.com/ipfs/go-unixfsnode"
12+
"github.com/ipfs/go-unixfsnode/data/builder"
1113
"github.com/ipfs/go-unixfsnode/directory"
1214
"github.com/ipfs/go-unixfsnode/file"
1315
"github.com/ipld/go-car/v2/blockstore"
1416
dagpb "github.com/ipld/go-codec-dagpb"
1517
"github.com/ipld/go-ipld-prime"
1618
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
19+
"github.com/ipld/go-ipld-prime/node/basicnode"
1720
)
1821

1922
func TestRootV0File(t *testing.T) {
@@ -61,6 +64,43 @@ func TestNamedV0File(t *testing.T) {
6164
}
6265
}
6366

67+
func TestFileSeeker(t *testing.T) {
68+
ls := cidlink.DefaultLinkSystem()
69+
storage := cidlink.Memory{}
70+
ls.StorageReadOpener = storage.OpenRead
71+
ls.StorageWriteOpener = storage.OpenWrite
72+
73+
// Make random file with 1024 bytes.
74+
buf := make([]byte, 1024)
75+
ipfsutil.NewSeededRand(0xdeadbeef).Read(buf)
76+
r := bytes.NewReader(buf)
77+
78+
// Build UnixFS File as a single chunk
79+
f, _, err := builder.BuildUnixFSFile(r, "size-1024", &ls)
80+
if err != nil {
81+
t.Fatal(err)
82+
}
83+
84+
// Load the file.
85+
fr, err := ls.Load(ipld.LinkContext{}, f, basicnode.Prototype.Bytes)
86+
if err != nil {
87+
t.Fatal(err)
88+
}
89+
90+
// Create it.
91+
ufn, err := file.NewUnixFSFile(context.Background(), fr, &ls)
92+
if err != nil {
93+
t.Fatal(err)
94+
}
95+
96+
rs, err := ufn.AsLargeBytes()
97+
if err != nil {
98+
t.Fatal(err)
99+
}
100+
101+
testSeekIn1024ByteFile(t, rs)
102+
}
103+
64104
func open(car string, t *testing.T) (ipld.Node, *ipld.LinkSystem) {
65105
baseStore, err := blockstore.OpenReadOnly(car)
66106
if err != nil {
@@ -88,3 +128,78 @@ func open(car string, t *testing.T) (ipld.Node, *ipld.LinkSystem) {
88128
}
89129
return root, &ls
90130
}
131+
132+
func testSeekIn1024ByteFile(t *testing.T, rs io.ReadSeeker) {
133+
// Seek from the start and try reading
134+
offset, err := rs.Seek(128, io.SeekStart)
135+
if err != nil {
136+
t.Fatal(err)
137+
}
138+
139+
if offset != 128 {
140+
t.Fatalf("expected offset %d, got %d", 484, offset)
141+
}
142+
143+
readBuf := make([]byte, 256)
144+
_, err = io.ReadFull(rs, readBuf)
145+
if err != nil {
146+
t.Fatal(err)
147+
}
148+
149+
// Validate we can detect the offset with SeekCurrent
150+
offset, err = rs.Seek(0, io.SeekCurrent)
151+
if err != nil {
152+
t.Fatal(err)
153+
}
154+
155+
if offset != 384 {
156+
t.Fatalf("expected offset %d, got %d", 384, offset)
157+
}
158+
159+
// Validate we can read after moving with SeekCurrent
160+
offset, err = rs.Seek(100, io.SeekCurrent)
161+
if err != nil {
162+
t.Fatal(err)
163+
}
164+
if offset != 484 {
165+
t.Fatalf("expected offset %d, got %d", 484, offset)
166+
}
167+
168+
_, err = io.ReadFull(rs, readBuf)
169+
if err != nil {
170+
t.Fatal(err)
171+
}
172+
173+
offset, err = rs.Seek(0, io.SeekCurrent)
174+
if err != nil {
175+
t.Fatal(err)
176+
}
177+
178+
if offset != 740 {
179+
t.Fatalf("expected offset %d, got %d", 740, offset)
180+
}
181+
182+
// Validate we can read after moving with SeekEnd
183+
offset, err = rs.Seek(-400, io.SeekEnd)
184+
if err != nil {
185+
t.Fatal(err)
186+
}
187+
188+
if offset != 624 {
189+
t.Fatalf("expected offset %d, got %d", 624, offset)
190+
}
191+
192+
_, err = io.ReadFull(rs, readBuf)
193+
if err != nil {
194+
t.Fatal(err)
195+
}
196+
197+
offset, err = rs.Seek(0, io.SeekCurrent)
198+
if err != nil {
199+
t.Fatal(err)
200+
}
201+
202+
if offset != 880 {
203+
t.Fatalf("expected offset %d, got %d", 880, offset)
204+
}
205+
}

file/large_file_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,43 @@ func TestLargeFileReader(t *testing.T) {
6868
}
6969
}
7070

71+
func TestLargeFileSeeker(t *testing.T) {
72+
ls := cidlink.DefaultLinkSystem()
73+
storage := cidlink.Memory{}
74+
ls.StorageReadOpener = storage.OpenRead
75+
ls.StorageWriteOpener = storage.OpenWrite
76+
77+
// Make random file with 1024 bytes.
78+
buf := make([]byte, 1024)
79+
ipfsutil.NewSeededRand(0xdeadbeef).Read(buf)
80+
r := bytes.NewReader(buf)
81+
82+
// Build UnixFS File chunked in 256 byte parts.
83+
f, _, err := builder.BuildUnixFSFile(r, "size-256", &ls)
84+
if err != nil {
85+
t.Fatal(err)
86+
}
87+
88+
// Load the file.
89+
fr, err := ls.Load(ipld.LinkContext{}, f, dagpb.Type.PBNode)
90+
if err != nil {
91+
t.Fatal(err)
92+
}
93+
94+
// Create it.
95+
ufn, err := file.NewUnixFSFile(context.Background(), fr, &ls)
96+
if err != nil {
97+
t.Fatal(err)
98+
}
99+
100+
rs, err := ufn.AsLargeBytes()
101+
if err != nil {
102+
t.Fatal(err)
103+
}
104+
105+
testSeekIn1024ByteFile(t, rs)
106+
}
107+
71108
func TestLargeFileReaderReadsOnlyNecessaryBlocks(t *testing.T) {
72109
tracker, ls := mockTrackingLinkSystem()
73110

file/shard.go

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ func (s *shardNodeReader) Read(p []byte) (int, error) {
174174
s.rdr = rdr
175175
}
176176
n, err := s.rdr.Read(p)
177+
s.offset += int64(n)
177178
return n, err
178179
}
179180

0 commit comments

Comments
 (0)