gc: add option to stream errors
License: MIT Signed-off-by: Kevin Atkinson <k@kevina.org>
Kevin Atkinson committed
Mar 2, 2017 at 14:53 UTC
f338520aa8dbee4c6804a63ea3f995988ac834d7
3 files changed
+53
-22
core/commands/repo.go
+46
-18
@@ -40,6 +40,11 @@ var RepoCmd = &cmds.Command{
40
},
41
}
42
43
+type GcResult struct {
44
+ Key *cid.Cid
45
+ Error string `json:",omitempty"`
46
+}
47
+
48
var repoGcCmd = &cmds.Command{
49
Helptext: cmds.HelpText{
50
Tagline: "Perform a garbage collection sweep on the repo.",
@@ -51,6 +56,7 @@ order to reclaim hard disk space.
56
},
57
Options: []cmds.Option{
58
cmds.BoolOption("quiet", "q", "Write minimal output.").Default(false),
59
+ cmds.BoolOption("stream-errors", "Stream errors.").Default(false),
60
},
61
Run: func(req cmds.Request, res cmds.Response) {
62
n, err := req.InvocContext().GetNode()
@@ -59,22 +65,41 @@ order to reclaim hard disk space.
65
return
66
}
67
68
+ streamErrors, _, _ := res.Request().Option("stream-errors").Bool()
69
+
70
gcOutChan := corerepo.GarbageCollectAsync(n, req.Context())
71
64
- outChan := make(chan interface{}, len(gcOutChan))
72
+ outChan := make(chan interface{}, cap(gcOutChan))
73
res.SetOutput((<-chan interface{})(outChan))
74
75
go func() {
76
defer close(outChan)
69
- err := corerepo.CollectResult(req.Context(), gcOutChan, func(k *cid.Cid) {
70
- outChan <- &corerepo.KeyRemoved{k}
71
- })
72
- if err != nil {
73
- res.SetError(err, cmds.ErrNormal)
77
+ unreportedError := false
78
+ var lastErr error
79
+ if streamErrors {
80
+ for res := range gcOutChan {
81
+ if unreportedError {
82
+ outChan <- &GcResult{Error: lastErr.Error()}
83
+ unreportedError = false
84
+ }
85
+ if res.Error != nil {
86
+ lastErr = res.Error
87
+ unreportedError = true
88
+ } else {
89
+ outChan <- &GcResult{Key: res.KeyRemoved}
90
+ }
91
+ }
92
+ } else {
93
+ lastErr = corerepo.CollectResult(req.Context(), gcOutChan, func(k *cid.Cid) {
94
+ outChan <- &GcResult{Key: k}
95
+ })
96
+ }
97
+ if lastErr != nil {
98
+ res.SetError(lastErr, cmds.ErrNormal)
99
}
100
}()
101
},
77
- Type: corerepo.KeyRemoved{},
102
+ Type: GcResult{},
103
Marshalers: cmds.MarshalerMap{
104
cmds.Text: func(res cmds.Response) (io.Reader, error) {
105
outChan, ok := res.Output().(<-chan interface{})
@@ -87,26 +112,29 @@ order to reclaim hard disk space.
112
return nil, err
113
}
114
90
- marshal := func(v interface{}) (io.Reader, error) {
91
- obj, ok := v.(*corerepo.KeyRemoved)
115
+ for v := range outChan {
116
+ obj, ok := v.(*GcResult)
117
if !ok {
118
return nil, u.ErrCast()
119
}
120
96
- buf := new(bytes.Buffer)
121
+ if obj.Error != "" {
122
+ fmt.Fprintf(res.Stderr(), "Error: %s\n", obj.Error)
123
+ continue
124
+ }
125
+
126
if quiet {
98
- buf = bytes.NewBufferString(obj.Key.String() + "\n")
127
+ fmt.Fprintf(res.Stdout(), "%s\n", obj.Key.String())
128
} else {
100
- buf = bytes.NewBufferString(fmt.Sprintf("removed %s\n", obj.Key))
129
+ fmt.Fprintf(res.Stdout(), "removed %s\n", obj.Key.String())
130
}
102
- return buf, nil
131
}
132
105
- return &cmds.ChannelMarshaler{
106
- Channel: outChan,
107
- Marshaler: marshal,
108
- Res: res,
109
- }, nil
133
+ if res.Error() != nil {
134
+ return nil, res.Error()
135
+ }
136
+
137
+ return nil, nil
138
},
139
},
140
}
core/corerepo/gc.go
-4
@@ -20,10 +20,6 @@ var log = logging.Logger("corerepo")
20
21
var ErrMaxStorageExceeded = errors.New("Maximum storage limit exceeded. Maybe unpin some files?")
22
23
-type KeyRemoved struct {
24
- Key *cid.Cid
25
-}
26
-
23
type GC struct {
24
Node *core.IpfsNode
25
Repo repo.Repo
test/sharness/t0087-repo-robust-gc.sh
+7
@@ -134,6 +134,13 @@ test_gc_robust_part2() {
134
grep -q "aborted" repo_gc_out
135
'
136
137
+ test_expect_success "'ipfs repo gc --stream-errors' should abort and report each error separately" '
138
+ test_must_fail ipfs repo gc --stream-errors 2>&1 | tee repo_gc_out &&
139
+ grep -q "Error: could not retrieve links for $LEAF1" repo_gc_out &&
140
+ grep -q "Error: could not retrieve links for $LEAF2" repo_gc_out &&
141
+ grep -q "Error: garbage collection aborted" repo_gc_out
142
+ '
143
+
144
test_expect_success "unpin 1MB file" '
145
ipfs pin rm $HASH2
146
'