add testing for pins
Jeromy committed
Oct 19, 2014 at 19:41 UTC
31b0ff0307c881bd1181dc08d5efe9f1ace42502
8 files changed
+198
-20
cmd/ipfs/ipfs.go
+1
@@ -68,6 +68,7 @@ Use "ipfs help <command>" for more information about a command.
68
cmdIpfsBlock,
69
cmdIpfsObject,
70
cmdIpfsLog,
71
+ cmdIpfsPin,
72
},
73
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
74
}
cmd/ipfs/pin.go
+25
-5
@@ -18,14 +18,34 @@ var cmdIpfsPin = &commander.Command{
18
Flag: *flag.NewFlagSet("ipfs-pin", flag.ExitOnError),
19
}
20
21
-func init() {
22
- cmdIpfsPin.Flag.Bool("r", false, "pin objects recursively")
23
- cmdIpfsPin.Flag.Int("d", 1, "recursive depth")
24
-}
25
-
21
var pinCmd = makeCommand(command{
22
name: "pin",
23
args: 1,
24
flags: []string{"r", "d"},
25
cmdFn: commands.Pin,
26
})
27
+
28
+var cmdIpfsUnpin = &commander.Command{
29
+ UsageLine: "unpin",
30
+ Short: "unpin an ipfs object from local storage.",
31
+ Long: `ipfs unpin <ipfs-path> - unpin ipfs object from local storage.
32
+
33
+ Removes the pin from the given object allowing it to be garbage
34
+ collected if needed.
35
+`,
36
+ Run: unpinCmd,
37
+ Flag: *flag.NewFlagSet("ipfs-unpin", flag.ExitOnError),
38
+}
39
+
40
+var unpinCmd = makeCommand(command{
41
+ name: "unpin",
42
+ args: 1,
43
+ flags: []string{"r", "d"},
44
+ cmdFn: commands.Unpin,
45
+})
46
+
47
+func init() {
48
+ cmdIpfsPin.Flag.Bool("r", false, "pin objects recursively")
49
+ cmdIpfsPin.Flag.Int("d", 1, "recursive depth")
50
+ cmdIpfsUnpin.Flag.Bool("r", false, "unpin objects recursively")
51
+}
core/commands/add.go
+2
-2
@@ -117,6 +117,6 @@ func addNode(n *core.IpfsNode, nd *dag.Node, fpath string, out io.Writer) error
117
// output that we've added this node
118
fmt.Fprintf(out, "added %s %s\n", k, fpath)
119
120
- // ensure we keep it. atm no-op
121
- return n.PinDagNodeRecursively(nd, -1)
120
+ // ensure we keep it
121
+ return n.Pinning.Pin(nd, true)
122
}
core/commands/pin.go
+21
-1
@@ -29,7 +29,27 @@ func Pin(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Wr
29
return fmt.Errorf("pin error: %v", err)
30
}
31
32
- err = n.PinDagNodeRecursively(dagnode, depth)
32
+ err = n.Pinning.Pin(dagnode, recursive)
33
+ if err != nil {
34
+ return fmt.Errorf("pin: %v", err)
35
+ }
36
+ }
37
+ return nil
38
+}
39
+
40
+func Unpin(n *core.IpfsNode, args []string, opts map[string]interface{}, out io.Writer) error {
41
+
42
+ // set recursive flag
43
+ recursive, _ := opts["r"].(bool) // false if cast fails.
44
+
45
+ for _, fn := range args {
46
+ dagnode, err := n.Resolver.ResolvePath(fn)
47
+ if err != nil {
48
+ return fmt.Errorf("pin error: %v", err)
49
+ }
50
+
51
+ k, _ := dagnode.Key()
52
+ err = n.Pinning.Unpin(k, recursive)
53
if err != nil {
54
return fmt.Errorf("pin: %v", err)
55
}
core/core.go
+9
-11
@@ -22,6 +22,7 @@ import (
22
netservice "github.com/jbenet/go-ipfs/net/service"
23
path "github.com/jbenet/go-ipfs/path"
24
peer "github.com/jbenet/go-ipfs/peer"
25
+ pin "github.com/jbenet/go-ipfs/pin"
26
routing "github.com/jbenet/go-ipfs/routing"
27
dht "github.com/jbenet/go-ipfs/routing/dht"
28
u "github.com/jbenet/go-ipfs/util"
@@ -67,6 +68,9 @@ type IpfsNode struct {
68
69
// the diagnostics service
70
Diagnostics *diag.Diagnostics
71
+
72
+ // the pinning manager
73
+ Pinning pin.Pinner
74
}
75
76
// NewIpfsNode constructs a new IpfsNode based on the given config.
@@ -159,6 +163,10 @@ func NewIpfsNode(cfg *config.Config, online bool) (*IpfsNode, error) {
163
164
dag := &merkledag.DAGService{Blocks: bs}
165
ns := namesys.NewNameSystem(route)
166
+ p, err := pin.LoadPinner(d, dag)
167
+ if err != nil {
168
+ p = pin.NewPinner(d, dag)
169
+ }
170
171
success = true
172
return &IpfsNode{
@@ -174,6 +182,7 @@ func NewIpfsNode(cfg *config.Config, online bool) (*IpfsNode, error) {
182
Namesys: ns,
183
Diagnostics: diagnostics,
184
Network: network,
185
+ Pinning: p,
186
}, nil
187
}
188
@@ -243,14 +252,3 @@ func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerst
252
}
253
}
254
}
246
-
247
-// PinDagNode ensures a given node is stored persistently locally
248
-func (n *IpfsNode) PinDagNode(nd *merkledag.Node) error {
249
- return n.PinDagNodeRecursively(nd, 1)
250
-}
251
-
252
-// PinDagNodeRecursively ensures a given node is stored persistently locally
253
-func (n *IpfsNode) PinDagNodeRecursively(nd *merkledag.Node, depth int) error {
254
- log.Debug("Pinning node recursively. Currently No-Op")
255
- return nil
256
-}
daemon/daemon.go
+2
@@ -139,6 +139,8 @@ func (dl *DaemonListener) handleConnection(conn manet.Conn) {
139
err = commands.BlockPut(dl.node, command.Args, command.Opts, conn)
140
case "log":
141
err = commands.Log(dl.node, command.Args, command.Opts, conn)
142
+ case "unpin":
143
+ err = commands.Unpin(dl.node, command.Args, command.Opts, conn)
144
default:
145
err = fmt.Errorf("Invalid Command: '%s'", command.Command)
146
}
pin/pin.go
+5
-1
@@ -15,6 +15,7 @@ var directPinDatastoreKey = ds.NewKey("/local/pins/direct/keys")
15
var indirectPinDatastoreKey = ds.NewKey("/local/pins/indirect/keys")
16
17
type Pinner interface {
18
+ IsPinned(util.Key) bool
19
Pin(*mdag.Node, bool) error
20
Unpin(util.Key, bool) error
21
Flush() error
@@ -138,7 +139,7 @@ func (p *pinner) IsPinned(key util.Key) bool {
139
p.indirPin.HasKey(key)
140
}
141
141
-func LoadPinner(d ds.Datastore) (Pinner, error) {
142
+func LoadPinner(d ds.Datastore, dserv *mdag.DAGService) (Pinner, error) {
143
p := new(pinner)
144
145
var err error
@@ -156,6 +157,9 @@ func LoadPinner(d ds.Datastore) (Pinner, error) {
157
return nil, err
158
}
159
160
+ p.dserv = dserv
161
+ p.dstore = d
162
+
163
return p, nil
164
}
165
pin/pin_test.go
new
+133
@@ -0,0 +1,133 @@
1
+package pin
2
+
3
+import (
4
+ "testing"
5
+
6
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
7
+ bs "github.com/jbenet/go-ipfs/blockservice"
8
+ mdag "github.com/jbenet/go-ipfs/merkledag"
9
+ "github.com/jbenet/go-ipfs/util"
10
+)
11
+
12
+func randNode() (*mdag.Node, util.Key) {
13
+ nd := new(mdag.Node)
14
+ nd.Data = make([]byte, 32)
15
+ util.NewFastRand().Read(nd.Data)
16
+ k, _ := nd.Key()
17
+ return nd, k
18
+}
19
+
20
+func TestPinnerBasic(t *testing.T) {
21
+ dstore := datastore.NewMapDatastore()
22
+ bserv, err := bs.NewBlockService(dstore, nil)
23
+ if err != nil {
24
+ t.Fatal(err)
25
+ }
26
+
27
+ dserv := &mdag.DAGService{bserv}
28
+
29
+ p := NewPinner(dstore, dserv)
30
+
31
+ a, ak := randNode()
32
+
33
+ // Pin A{}
34
+ err = p.Pin(a, false)
35
+ if err != nil {
36
+ t.Fatal(err)
37
+ }
38
+
39
+ if !p.IsPinned(ak) {
40
+ t.Fatal("Failed to find key")
41
+ }
42
+
43
+ b, _ := randNode()
44
+ err = b.AddNodeLink("child", a)
45
+ if err != nil {
46
+ t.Fatal(err)
47
+ }
48
+
49
+ c, ck := randNode()
50
+ err = b.AddNodeLink("otherchild", c)
51
+ if err != nil {
52
+ t.Fatal(err)
53
+ }
54
+
55
+ // recursively pin B{A,C}
56
+ err = p.Pin(b, true)
57
+ if err != nil {
58
+ t.Fatal(err)
59
+ }
60
+
61
+ if !p.IsPinned(ck) {
62
+ t.Fatal("Child of recursively pinned node not found")
63
+ }
64
+
65
+ bk, _ := b.Key()
66
+ if !p.IsPinned(bk) {
67
+ t.Fatal("Recursively pinned node not found..")
68
+ }
69
+
70
+ d, _ := randNode()
71
+ d.AddNodeLink("a", a)
72
+ d.AddNodeLink("c", c)
73
+
74
+ e, ek := randNode()
75
+ d.AddNodeLink("e", e)
76
+
77
+ // Must be in dagserv for unpin to work
78
+ err = dserv.AddRecursive(d)
79
+ if err != nil {
80
+ t.Fatal(err)
81
+ }
82
+
83
+ // Add D{A,C,E}
84
+ err = p.Pin(d, true)
85
+ if err != nil {
86
+ t.Fatal(err)
87
+ }
88
+
89
+ if !p.IsPinned(ek) {
90
+ t.Fatal(err)
91
+ }
92
+
93
+ dk, _ := d.Key()
94
+ if !p.IsPinned(dk) {
95
+ t.Fatal("pinned node not found.")
96
+ }
97
+
98
+ // Test recursive unpin
99
+ err = p.Unpin(dk, true)
100
+ if err != nil {
101
+ t.Fatal(err)
102
+ }
103
+
104
+ // c should still be pinned under b
105
+ if !p.IsPinned(ck) {
106
+ t.Fatal("Recursive unpin fail.")
107
+ }
108
+
109
+ err = p.Flush()
110
+ if err != nil {
111
+ t.Fatal(err)
112
+ }
113
+
114
+ np, err := LoadPinner(dstore, dserv)
115
+ if err != nil {
116
+ t.Fatal(err)
117
+ }
118
+
119
+ // Test directly pinned
120
+ if !np.IsPinned(ak) {
121
+ t.Fatal("Could not find pinned node!")
122
+ }
123
+
124
+ // Test indirectly pinned
125
+ if !np.IsPinned(ck) {
126
+ t.Fatal("could not find indirectly pinned node")
127
+ }
128
+
129
+ // Test recursively pinned
130
+ if !np.IsPinned(bk) {
131
+ t.Fatal("could not find recursively pinned node")
132
+ }
133
+}