Skip to content

Commit 8e2aed3

Browse files
Merge pull request #3846 from ipfs/feat/pin-update
implement ipfs pin update
2 parents 630f9ae + 0d3a86e commit 8e2aed3

File tree

8 files changed

+430
-22
lines changed

8 files changed

+430
-22
lines changed

core/commands/object/diff.go

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77

88
cmds "github.com/ipfs/go-ipfs/commands"
99
core "github.com/ipfs/go-ipfs/core"
10-
dag "github.com/ipfs/go-ipfs/merkledag"
1110
dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
1211
path "github.com/ipfs/go-ipfs/path"
1312
)
@@ -86,19 +85,7 @@ Example:
8685
return
8786
}
8887

89-
pbobj_a, ok := obj_a.(*dag.ProtoNode)
90-
if !ok {
91-
res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
92-
return
93-
}
94-
95-
pbobj_b, ok := obj_b.(*dag.ProtoNode)
96-
if !ok {
97-
res.SetError(dag.ErrNotProtobuf, cmds.ErrNormal)
98-
return
99-
}
100-
101-
changes, err := dagutils.Diff(ctx, node.DAG, pbobj_a, pbobj_b)
88+
changes, err := dagutils.Diff(ctx, node.DAG, obj_a, obj_b)
10289
if err != nil {
10390
res.SetError(err, cmds.ErrNormal)
10491
return

core/commands/pin.go

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ var PinCmd = &cmds.Command{
2424
},
2525

2626
Subcommands: map[string]*cmds.Command{
27-
"add": addPinCmd,
28-
"rm": rmPinCmd,
29-
"ls": listPinCmd,
27+
"add": addPinCmd,
28+
"rm": rmPinCmd,
29+
"ls": listPinCmd,
30+
"update": updatePinCmd,
3031
},
3132
}
3233

@@ -332,6 +333,83 @@ Example:
332333
},
333334
}
334335

336+
var updatePinCmd = &cmds.Command{
337+
Helptext: cmds.HelpText{
338+
Tagline: "Update a recursive pin",
339+
ShortDescription: `
340+
Updates one pin to another, making sure that all objects in the new pin are
341+
local. Then removes the old pin. This is an optimized version of adding the
342+
new pin and removing the old one.
343+
`,
344+
},
345+
346+
Arguments: []cmds.Argument{
347+
cmds.StringArg("from-path", true, false, "Path to old object."),
348+
cmds.StringArg("to-path", true, false, "Path to new object to be pinned."),
349+
},
350+
Options: []cmds.Option{
351+
cmds.BoolOption("unpin", "Remove the old pin.").Default(true),
352+
},
353+
Type: PinOutput{},
354+
Run: func(req cmds.Request, res cmds.Response) {
355+
n, err := req.InvocContext().GetNode()
356+
if err != nil {
357+
res.SetError(err, cmds.ErrNormal)
358+
return
359+
}
360+
361+
unpin, _, err := req.Option("unpin").Bool()
362+
if err != nil {
363+
res.SetError(err, cmds.ErrNormal)
364+
return
365+
}
366+
367+
from, err := path.ParsePath(req.Arguments()[0])
368+
if err != nil {
369+
res.SetError(err, cmds.ErrNormal)
370+
return
371+
}
372+
373+
to, err := path.ParsePath(req.Arguments()[1])
374+
if err != nil {
375+
res.SetError(err, cmds.ErrNormal)
376+
return
377+
}
378+
379+
fromc, err := core.ResolveToCid(req.Context(), n, from)
380+
if err != nil {
381+
res.SetError(err, cmds.ErrNormal)
382+
return
383+
}
384+
385+
toc, err := core.ResolveToCid(req.Context(), n, to)
386+
if err != nil {
387+
res.SetError(err, cmds.ErrNormal)
388+
return
389+
}
390+
391+
err = n.Pinning.Update(req.Context(), fromc, toc, unpin)
392+
if err != nil {
393+
res.SetError(err, cmds.ErrNormal)
394+
return
395+
}
396+
397+
res.SetOutput(&PinOutput{Pins: []string{from.String(), to.String()}})
398+
},
399+
Marshalers: cmds.MarshalerMap{
400+
cmds.Text: func(res cmds.Response) (io.Reader, error) {
401+
added, ok := res.Output().(*PinOutput)
402+
if !ok {
403+
return nil, u.ErrCast()
404+
}
405+
406+
buf := new(bytes.Buffer)
407+
fmt.Fprintf(buf, "updated %s to %s\n", added.Pins[0], added.Pins[1])
408+
return buf, nil
409+
},
410+
},
411+
}
412+
335413
type RefKeyObject struct {
336414
Type string
337415
}

merkledag/merkledag.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (n *dagService) Remove(nd node.Node) error {
153153
// GetLinksDirect creates a function to get the links for a node, from
154154
// the node, bypassing the LinkService. If the node does not exist
155155
// locally (and can not be retrieved) an error will be returned.
156-
func GetLinksDirect(serv DAGService) GetLinks {
156+
func GetLinksDirect(serv node.NodeGetter) GetLinks {
157157
return func(ctx context.Context, c *cid.Cid) ([]*node.Link, error) {
158158
node, err := serv.Get(ctx, c)
159159
if err != nil {

merkledag/utils/diff.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package dagutils
22

33
import (
4+
"context"
45
"fmt"
56
"path"
67

78
dag "github.com/ipfs/go-ipfs/merkledag"
89

9-
context "context"
1010
cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid"
11+
node "gx/ipfs/Qmb3Hm9QDFmfYuET4pu7Kyg8JV78jFa1nvZx5vnCZsK4ck/go-ipld-format"
1112
)
1213

1314
const (
@@ -87,7 +88,8 @@ func ApplyChange(ctx context.Context, ds dag.DAGService, nd *dag.ProtoNode, cs [
8788
return e.Finalize(ds)
8889
}
8990

90-
func Diff(ctx context.Context, ds dag.DAGService, a, b *dag.ProtoNode) ([]*Change, error) {
91+
// Diff returns a set of changes that transform node 'a' into node 'b'
92+
func Diff(ctx context.Context, ds dag.DAGService, a, b node.Node) ([]*Change, error) {
9193
if len(a.Links()) == 0 && len(b.Links()) == 0 {
9294
return []*Change{
9395
&Change{
@@ -104,7 +106,7 @@ func Diff(ctx context.Context, ds dag.DAGService, a, b *dag.ProtoNode) ([]*Chang
104106

105107
// strip out unchanged stuff
106108
for _, lnk := range a.Links() {
107-
l, err := b.GetNodeLink(lnk.Name)
109+
l, _, err := b.ResolveLink([]string{lnk.Name})
108110
if err == nil {
109111
if l.Cid.Equals(lnk.Cid) {
110112
// no change... ignore it

merkledag/utils/diffenum.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package dagutils
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
mdag "github.com/ipfs/go-ipfs/merkledag"
8+
9+
cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid"
10+
node "gx/ipfs/Qmb3Hm9QDFmfYuET4pu7Kyg8JV78jFa1nvZx5vnCZsK4ck/go-ipld-format"
11+
)
12+
13+
// DiffEnumerate fetches every object in the graph pointed to by 'to' that is
14+
// not in 'from'. This can be used to more efficiently fetch a graph if you can
15+
// guarantee you already have the entirety of 'from'
16+
func DiffEnumerate(ctx context.Context, dserv node.NodeGetter, from, to *cid.Cid) error {
17+
fnd, err := dserv.Get(ctx, from)
18+
if err != nil {
19+
return fmt.Errorf("get %s: %s", from, err)
20+
}
21+
22+
tnd, err := dserv.Get(ctx, to)
23+
if err != nil {
24+
return fmt.Errorf("get %s: %s", to, err)
25+
}
26+
27+
diff := getLinkDiff(fnd, tnd)
28+
29+
sset := cid.NewSet()
30+
for _, c := range diff {
31+
// Since we're already assuming we have everything in the 'from' graph,
32+
// add all those cids to our 'already seen' set to avoid potentially
33+
// enumerating them later
34+
if c.bef != nil {
35+
sset.Add(c.bef)
36+
}
37+
}
38+
for _, c := range diff {
39+
if c.bef == nil {
40+
if sset.Has(c.aft) {
41+
continue
42+
}
43+
err := mdag.EnumerateChildrenAsync(ctx, mdag.GetLinksDirect(dserv), c.aft, sset.Visit)
44+
if err != nil {
45+
return err
46+
}
47+
} else {
48+
err := DiffEnumerate(ctx, dserv, c.bef, c.aft)
49+
if err != nil {
50+
return err
51+
}
52+
}
53+
}
54+
55+
return nil
56+
}
57+
58+
// if both bef and aft are not nil, then that signifies bef was replaces with aft.
59+
// if bef is nil and aft is not, that means aft was newly added
60+
// if aft is nil and bef is not, that means bef was deleted
61+
type diffpair struct {
62+
bef, aft *cid.Cid
63+
}
64+
65+
// getLinkDiff returns a changeset between nodes 'a' and 'b'. Currently does
66+
// not log deletions as our usecase doesnt call for this.
67+
func getLinkDiff(a, b node.Node) []diffpair {
68+
have := make(map[string]*node.Link)
69+
names := make(map[string]*node.Link)
70+
for _, l := range a.Links() {
71+
have[l.Cid.KeyString()] = l
72+
names[l.Name] = l
73+
}
74+
75+
var out []diffpair
76+
77+
for _, l := range b.Links() {
78+
if have[l.Cid.KeyString()] != nil {
79+
continue
80+
}
81+
82+
match, ok := names[l.Name]
83+
if !ok {
84+
out = append(out, diffpair{aft: l.Cid})
85+
continue
86+
}
87+
88+
out = append(out, diffpair{bef: match.Cid, aft: l.Cid})
89+
}
90+
return out
91+
}

0 commit comments

Comments
 (0)