Skip to content

Commit

Permalink
Checkpoint. "pin verify".
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Kevin Atkinson <k@kevina.org>
  • Loading branch information
kevina committed Mar 29, 2017
1 parent a8b56d3 commit 5e08cbb
Showing 1 changed file with 110 additions and 3 deletions.
113 changes: 110 additions & 3 deletions core/commands/pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ var PinCmd = &cmds.Command{
},

Subcommands: map[string]*cmds.Command{
"add": addPinCmd,
"rm": rmPinCmd,
"ls": listPinCmd,
"add": addPinCmd,
"rm": rmPinCmd,
"ls": listPinCmd,
"verify": verifyPinCmd,
},
}

Expand Down Expand Up @@ -332,6 +333,27 @@ Example:
},
}

var verifyPinCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Verify that recursive pins are complete.",
},
Run: func(req cmds.Request, res cmds.Response) {
n, _ := req.InvocContext().GetNode()

rdr, wtr := io.Pipe()
out := pinVerify(req.Context(), n)

go func() {
defer wtr.Close()
for r := range out {
r.Format(wtr)
}
}()

res.SetOutput(rdr)
},
}

type RefKeyObject struct {
Type string
}
Expand Down Expand Up @@ -414,6 +436,91 @@ func pinLsAll(typeStr string, ctx context.Context, n *core.IpfsNode) (map[string
return keys, nil
}

type pinStatus struct {
// use pointer to array slice to reduce memory usage
// the value should not be nil unless uninitialized
badNodes *[]badNode
}

type badNode struct {
cid *cid.Cid
err error
}

type pinVerifyRes struct {
cid *cid.Cid
pinStatus
}

func pinVerify(ctx context.Context, n *core.IpfsNode) <-chan pinVerifyRes {
visited := make(map[string]pinStatus)
getLinks := n.DAG.GetOfflineLinkService().GetLinks
emptySlice := &[]badNode{}
recPins := n.Pinning.RecursiveKeys()

var checkPin func(root *cid.Cid) pinStatus
checkPin = func(root *cid.Cid) pinStatus {
key := root.String()
if status, ok := visited[key]; ok {
if status.badNodes == nil {
return pinStatus{&[]badNode{badNode{
cid: root,
err: fmt.Errorf("Cycle Detected.")}}}
}
return status
}

links, err := getLinks(ctx, root)
if err != nil {
status := pinStatus{&[]badNode{badNode{cid: root, err: err}}}
visited[key] = status
return status
}

status := pinStatus{}
visited[key] = status // paranoid mode cycle detection
for _, lnk := range links {
res := checkPin(lnk.Cid)
if len(*res.badNodes) > 0 {
if status.badNodes == nil {
status.badNodes = res.badNodes
} else {
slice := append(*status.badNodes, *res.badNodes...)
status.badNodes = &slice
}
}
}
if status.badNodes == nil {
status.badNodes = emptySlice // prevent special cases
}

visited[key] = status
return status
}

out := make(chan pinVerifyRes)
go func() {
defer close(out)
for _, cid := range recPins {
pinStatus := checkPin(cid)
out <- pinVerifyRes{cid, pinStatus}
}
}()

return out
}

func (r pinVerifyRes) Format(out io.Writer) {
if len(*r.badNodes) == 0 {
fmt.Fprintf(out, "%s ok\n", r.cid)
} else {
fmt.Fprintf(out, "%s broken\n", r.cid)
for _, e := range *r.badNodes {
fmt.Fprintf(out, " %s: %s\n", e.cid, e.err)
}
}
}

func cidsToStrings(cs []*cid.Cid) []string {
out := make([]string, 0, len(cs))
for _, c := range cs {
Expand Down

0 comments on commit 5e08cbb

Please sign in to comment.