@cryptotaxi247 / kubo / commits / 31b0ff030

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 +}