Skip to content

Commit

Permalink
Merge pull request #3095 from ipfs/fix/unixfs-relative-seek-expand
Browse files Browse the repository at this point in the history
unixfs: fix relative seek not expanding file properly
  • Loading branch information
whyrusleeping authored Aug 17, 2016
2 parents 740a094 + 9f9ca6c commit 411f9d6
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 9 deletions.
4 changes: 4 additions & 0 deletions unixfs/io/dagreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ func (dr *DagReader) Close() error {
return nil
}

func (dr *DagReader) Offset() int64 {
return dr.offset
}

// Seek implements io.Seeker, and will seek to a given offset in the file
// interface matches standard unix seek
// TODO: check if we can do relative seeks, to reduce the amount of dagreader
Expand Down
13 changes: 6 additions & 7 deletions unixfs/mod/dagmodifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ import (
"io"
"os"

mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"

key "github.com/ipfs/go-ipfs/blocks/key"
chunk "github.com/ipfs/go-ipfs/importer/chunk"
help "github.com/ipfs/go-ipfs/importer/helpers"
trickle "github.com/ipfs/go-ipfs/importer/trickle"
mdag "github.com/ipfs/go-ipfs/merkledag"
ft "github.com/ipfs/go-ipfs/unixfs"
uio "github.com/ipfs/go-ipfs/unixfs/io"

logging "gx/ipfs/QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR/go-log"
mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
)

var ErrSeekFail = errors.New("failed to seek properly")
var ErrSeekEndNotImpl = errors.New("SEEK_END currently not implemented")
var ErrUnrecognizedWhence = errors.New("unrecognized whence")

// 2MB
Expand Down Expand Up @@ -378,8 +377,8 @@ func (dm *DagModifier) Seek(offset int64, whence int) (int64, error) {
return 0, ErrUnrecognizedWhence
}

if offset > fisize {
if err := dm.expandSparse(offset - fisize); err != nil {
if int64(newoffset) > fisize {
if err := dm.expandSparse(int64(newoffset) - fisize); err != nil {
return 0, err
}
}
Expand Down
149 changes: 147 additions & 2 deletions unixfs/mod/dagmodifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import (
mdag "github.com/ipfs/go-ipfs/merkledag"
ft "github.com/ipfs/go-ipfs/unixfs"
uio "github.com/ipfs/go-ipfs/unixfs/io"
"gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore/sync"
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"

ds "gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore"
"gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore/sync"
u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
)

Expand Down Expand Up @@ -548,6 +548,151 @@ func TestSeekPastEndWrite(t *testing.T) {
}
}

func TestRelativeSeek(t *testing.T) {
dserv := getMockDagServ(t)
_, n := getNode(t, dserv, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
if err != nil {
t.Fatal(err)
}

for i := 0; i < 64; i++ {
dagmod.Write([]byte{byte(i)})
if _, err := dagmod.Seek(1, os.SEEK_CUR); err != nil {
t.Fatal(err)
}
}

out, err := ioutil.ReadAll(dagmod)
if err != nil {
t.Fatal(err)
}

for i, v := range out {
if v != 0 && i/2 != int(v) {
t.Errorf("expected %d, at index %d, got %d", i/2, i, v)
}
}
}

func TestInvalidSeek(t *testing.T) {
dserv := getMockDagServ(t)

_, n := getNode(t, dserv, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
if err != nil {
t.Fatal(err)
}
_, err = dagmod.Seek(10, -10)

if err != ErrUnrecognizedWhence {
t.Fatal(err)
}
}

func TestEndSeek(t *testing.T) {
dserv := getMockDagServ(t)

_, n := getNode(t, dserv, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
if err != nil {
t.Fatal(err)
}

_, err = dagmod.Write(make([]byte, 100))
if err != nil {
t.Fatal(err)
}

offset, err := dagmod.Seek(0, os.SEEK_CUR)
if offset != 100 {
t.Fatal("expected the relative seek 0 to return current location")
}

offset, err = dagmod.Seek(0, os.SEEK_SET)
if offset != 0 {
t.Fatal("expected the absolute seek to set offset at 0")
}

offset, err = dagmod.Seek(0, os.SEEK_END)
if offset != 100 {
t.Fatal("expected the end seek to set offset at end")
}
}

func TestReadAndSeek(t *testing.T) {
dserv := getMockDagServ(t)

_, n := getNode(t, dserv, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

dagmod, err := NewDagModifier(ctx, n, dserv, sizeSplitterGen(512))
if err != nil {
t.Fatal(err)
}

writeBuf := []byte{0, 1, 2, 3, 4, 5, 6, 7}
dagmod.Write(writeBuf)

readBuf := make([]byte, 4)
offset, err := dagmod.Seek(0, os.SEEK_SET)
if offset != 0 {
t.Fatal("expected offset to be 0")
}
if err != nil {
t.Fatal(err)
}

// read 0,1,2,3
c, err := dagmod.Read(readBuf)
if err != nil {
t.Fatal(err)
}
if c != 4 {
t.Fatalf("expected length of 4 got %d", c)
}

for i := byte(0); i < 4; i++ {
if readBuf[i] != i {
t.Fatalf("wrong value %d [at index %d]", readBuf[i], i)
}
}

// skip 4
_, err = dagmod.Seek(1, os.SEEK_CUR)
if err != nil {
t.Fatalf("error: %s, offset %d, reader offset %d", err, dagmod.curWrOff, dagmod.read.Offset())
}

//read 5,6,7
readBuf = make([]byte, 3)
c, err = dagmod.Read(readBuf)
if err != nil {
t.Fatal(err)
}
if c != 3 {
t.Fatalf("expected length of 3 got %d", c)
}

for i := byte(0); i < 3; i++ {
if readBuf[i] != i+5 {
t.Fatalf("wrong value %d [at index %d]", readBuf[i], i)
}

}

}

func BenchmarkDagmodWrite(b *testing.B) {
b.StopTimer()
dserv := getMockDagServ(b)
Expand Down

0 comments on commit 411f9d6

Please sign in to comment.