From 4427d7e8e31a6987d79f514b39362fee2f89217d Mon Sep 17 00:00:00 2001 From: Erik Ingenito Date: Wed, 1 May 2019 14:03:49 -0700 Subject: [PATCH] Test and fix GC/pin bug #6252 License: MIT Signed-off-by: Erik Ingenito --- core/coreunix/add.go | 7 --- core/coreunix/add_test.go | 110 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 7 deletions(-) diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 47676c142ef..1a348855b66 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -71,7 +71,6 @@ type Adder struct { Silent bool NoCopy bool Chunker string - root ipld.Node mroot *mfs.Root unlocker bstore.Unlocker tempRoot cid.Cid @@ -132,11 +131,6 @@ func (adder *Adder) add(reader io.Reader) (ipld.Node, error) { // RootNode returns the mfs root node func (adder *Adder) curRootNode() (ipld.Node, error) { - // for memoizing - if adder.root != nil { - return adder.root, nil - } - mr, err := adder.mfsRoot() if err != nil { return nil, err @@ -156,7 +150,6 @@ func (adder *Adder) curRootNode() (ipld.Node, error) { root = nd } - adder.root = root return root, err } diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index 95f244cff3d..f2fb0f46d9b 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -30,6 +30,116 @@ import ( const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe" +func TestAddMultipleGCLive(t *testing.T) { + r := &repo.Mock{ + C: config.Config{ + Identity: config.Identity{ + PeerID: testPeerID, // required by offline node + }, + }, + D: syncds.MutexWrap(datastore.NewMapDatastore()), + } + node, err := core.NewNode(context.Background(), &core.BuildCfg{Repo: r}) + if err != nil { + t.Fatal(err) + } + + out := make(chan interface{}, 10) + adder, err := NewAdder(context.Background(), node.Pinning, node.Blockstore, node.DAG) + if err != nil { + t.Fatal(err) + } + adder.Out = out + + // make two files with pipes so we can 'pause' the add for timing of the test + piper1, pipew1 := io.Pipe() + hangfile1 := files.NewReaderFile(piper1) + + piper2, pipew2 := io.Pipe() + hangfile2 := files.NewReaderFile(piper2) + + rfc := files.NewBytesFile([]byte("testfileA")) + + slf := files.NewMapDirectory(map[string]files.Node{ + "a": hangfile1, + "b": hangfile2, + "c": rfc, + }) + + go func() { + defer close(out) + adder.AddAllAndPin(slf) + // Ignore errors for clarity - the real bug would be gc'ing files while adding them, not this resultant error + }() + + // Start writing the first file but don't close the stream + if _, err := pipew1.Write([]byte("some data for file a")); err != nil { + t.Fatal(err) + } + + var gc1out <-chan gc.Result + gc1started := make(chan struct{}) + go func() { + defer close(gc1started) + gc1out = gc.GC(context.Background(), node.Blockstore, node.Repo.Datastore(), node.Pinning, nil) + }() + + // GC shouldn't get the lock until after the file is completely added + select { + case <-gc1started: + t.Fatal("gc shouldnt have started yet") + default: + } + + // finish write and unblock gc + pipew1.Close() + + // Should have gotten the lock at this point + <-gc1started + + removedHashes := make(map[string]struct{}) + for r := range gc1out { + if r.Error != nil { + t.Fatal(err) + } + removedHashes[r.KeyRemoved.String()] = struct{}{} + } + + if _, err := pipew2.Write([]byte("some data for file b")); err != nil { + t.Fatal(err) + } + + var gc2out <-chan gc.Result + gc2started := make(chan struct{}) + go func() { + defer close(gc2started) + gc2out = gc.GC(context.Background(), node.Blockstore, node.Repo.Datastore(), node.Pinning, nil) + }() + + select { + case <-gc2started: + t.Fatal("gc shouldnt have started yet") + default: + } + + pipew2.Close() + + <-gc2started + + for r := range gc2out { + if r.Error != nil { + t.Fatal(err) + } + removedHashes[r.KeyRemoved.String()] = struct{}{} + } + + for o := range out { + if _, ok := removedHashes[o.(*coreiface.AddEvent).Path.Cid().String()]; ok { + t.Fatal("gc'ed a hash we just added") + } + } +} + func TestAddGCLive(t *testing.T) { r := &repo.Mock{ C: config.Config{