Skip to content

Commit b95e00c

Browse files
committed
Make pin rm not try to find pinned ancestors by default
Also make a switch to pin rm to allow old behavior. Trying to look up pins which interfere with requested unpin can be an extremely costly operation and typically is not required by user. License: MIT Signed-off-by: Iaroslav Gridin <voker57@gmail.com>
1 parent 1e9a638 commit b95e00c

File tree

8 files changed

+74
-25
lines changed

8 files changed

+74
-25
lines changed

core/commands/pin.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
195195
},
196196
Options: []cmdkit.Option{
197197
cmdkit.BoolOption(pinRecursiveOptionName, "r", "Recursively unpin the object linked to by the specified object(s).").WithDefault(true),
198+
cmdkit.BoolOption("explain", "e", "Check for other pinned objects which could cause specified object(s) to be indirectly pinned").WithDefault(false),
198199
},
199200
Type: PinOutput{},
200201
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
@@ -213,9 +214,14 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
213214

214215
if err := req.ParseBodyArgs(); err != nil {
215216
return err
217+
218+
explain, _, err := req.Option("explain").Bool()
219+
if err != nil {
220+
res.SetError(err, cmdkit.ErrNormal)
221+
return
216222
}
217223

218-
removed, err := corerepo.Unpin(n.Pinning, api, req.Context, req.Arguments, recursive)
224+
removed, err := corerepo.Unpin(n.Pinning, api, req.Context, req.Arguments, recursive, explain)
219225
if err != nil {
220226
return err
221227
}

core/coreapi/pin.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreif
5353
}
5454

5555
func (api *PinAPI) Rm(ctx context.Context, p coreiface.Path) error {
56-
_, err := corerepo.Unpin(api.pinning, api.core(), ctx, []string{p.String()}, true)
56+
_, err := corerepo.Unpin(api.pinning, api.core(), ctx, []string{p.String()}, true, true)
5757
if err != nil {
5858
return err
5959
}
6060

61-
return api.pinning.Flush()
61+
return nil
6262
}
6363

6464
func (api *PinAPI) Update(ctx context.Context, from coreiface.Path, to coreiface.Path, opts ...caopts.PinUpdateOption) error {

core/corerepo/pinning.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func Pin(pinning pin.Pinner, api iface.CoreAPI, ctx context.Context, paths []str
5151
return out, nil
5252
}
5353

54-
func Unpin(pinning pin.Pinner, api iface.CoreAPI, ctx context.Context, paths []string, recursive bool) ([]cid.Cid, error) {
54+
func Unpin(pinning pin.Pinner, api iface.CoreAPI, ctx context.Context, paths []string, recursive bool, explain bool) ([]cid.Cid, error) {
5555
unpinned := make([]cid.Cid, len(paths))
5656

5757
for i, p := range paths {
@@ -65,7 +65,7 @@ func Unpin(pinning pin.Pinner, api iface.CoreAPI, ctx context.Context, paths []s
6565
return nil, err
6666
}
6767

68-
err = pinning.Unpin(ctx, k.Cid(), recursive)
68+
err = pinning.Unpin(ctx, k.Cid(), recursive, explain)
6969
if err != nil {
7070
return nil, err
7171
}

core/coreunix/add.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func (adder *Adder) PinRoot() error {
179179
}
180180

181181
if adder.tempRoot.Defined() {
182-
err := adder.pinning.Unpin(adder.ctx, adder.tempRoot, true)
182+
err := adder.pinning.Unpin(adder.ctx, adder.tempRoot, true, false)
183183
if err != nil {
184184
return err
185185
}

pin/pin.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ type Pinner interface {
116116

117117
// Unpin the given cid. If recursive is true, removes either a recursive or
118118
// a direct pin. If recursive is false, only removes a direct pin.
119-
Unpin(ctx context.Context, cid cid.Cid, recursive bool) error
119+
Unpin(ctx context.Context, cid cid.Cid, recursive bool, explain bool) error
120120

121121
// Update updates a recursive pin from one cid to another
122122
// this is more efficient than simply pinning the new one and unpinning the
@@ -266,29 +266,59 @@ func (p *pinner) Pin(ctx context.Context, node ipld.Node, recurse bool) error {
266266
var ErrNotPinned = fmt.Errorf("not pinned")
267267

268268
// Unpin a given key
269-
func (p *pinner) Unpin(ctx context.Context, c cid.Cid, recursive bool) error {
269+
func (p *pinner) Unpin(ctx context.Context, c cid.Cid, recursive bool, explain bool) error {
270270
p.lock.Lock()
271271
defer p.lock.Unlock()
272-
reason, pinned, err := p.isPinnedWithType(c, Any)
272+
273+
var pinMode Mode
274+
if recursive {
275+
pinMode = Recursive
276+
} else {
277+
pinMode = Direct
278+
}
279+
_, pinned, err := p.isPinnedWithType(c, pinMode)
273280
if err != nil {
274281
return err
275282
}
276-
if !pinned {
277-
return ErrNotPinned
278-
}
279-
switch reason {
280-
case "recursive":
283+
if pinned {
281284
if recursive {
282285
p.recursePin.Remove(c)
283286
return nil
287+
} else {
288+
p.directPin.Remove(c)
289+
return nil
284290
}
285-
return fmt.Errorf("%s is pinned recursively", c)
286-
case "direct":
287-
p.directPin.Remove(c)
288-
return nil
289-
default:
290-
return fmt.Errorf("%s is pinned indirectly under %s", c, reason)
291+
} else if recursive {
292+
_, pinned, err := p.isPinnedWithType(c, Direct)
293+
if err != nil {
294+
return err
295+
}
296+
if pinned {
297+
p.directPin.Remove(c)
298+
return nil
299+
}
300+
}
301+
302+
if explain {
303+
reason, pinned, err := p.isPinnedWithType(c, Any)
304+
if err != nil {
305+
return err
306+
}
307+
if !pinned {
308+
return ErrNotPinned
309+
}
310+
switch reason {
311+
case "recursive":
312+
return fmt.Errorf("%s is pinned recursively", c)
313+
default:
314+
return fmt.Errorf("%s is pinned indirectly under %s", c, reason)
315+
}
316+
} else if recursive {
317+
return fmt.Errorf("%s is not pinned recursively or directly", c)
318+
} else {
319+
return fmt.Errorf("%s is not pinned directly", c)
291320
}
321+
292322
}
293323

294324
func (p *pinner) isInternalPin(c cid.Cid) bool {

pin/pin_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func TestPinnerBasic(t *testing.T) {
137137
assertPinned(t, p, dk, "pinned node not found.")
138138

139139
// Test recursive unpin
140-
err = p.Unpin(ctx, dk, true)
140+
err = p.Unpin(ctx, dk, true, false)
141141
if err != nil {
142142
t.Fatal(err)
143143
}
@@ -261,15 +261,15 @@ func TestIsPinnedLookup(t *testing.T) {
261261
assertPinned(t, p, bk, "B should be pinned")
262262

263263
// Unpin A5 recursively
264-
if err := p.Unpin(ctx, aKeys[5], true); err != nil {
264+
if err := p.Unpin(ctx, aKeys[5], true, false); err != nil {
265265
t.Fatal(err)
266266
}
267267

268268
assertPinned(t, p, aKeys[0], "A0 should still be pinned through B")
269269
assertUnpinned(t, p, aKeys[4], "A4 should be unpinned")
270270

271271
// Unpin B recursively
272-
if err := p.Unpin(ctx, bk, true); err != nil {
272+
if err := p.Unpin(ctx, bk, true, false); err != nil {
273273
t.Fatal(err)
274274
}
275275
assertUnpinned(t, p, bk, "B should be unpinned")

test/sharness/t0080-repo.sh

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,17 @@ test_expect_success "pinning directly should fail now" '
9393
'
9494

9595
test_expect_success "'ipfs pin rm -r=false <hash>' should fail" '
96-
echo "Error: $HASH is pinned recursively" >expected4 &&
96+
echo "Error: $HASH is not pinned directly" >expected4 &&
9797
test_must_fail ipfs pin rm -r=false "$HASH" 2>actual4 &&
9898
test_cmp expected4 actual4
9999
'
100100

101+
test_expect_success "'ipfs pin rm -e -r=false <hash>' should fail and explain why" '
102+
echo "Error: $HASH is pinned recursively" >expected11 &&
103+
test_must_fail ipfs pin rm -e -r=false "$HASH" 2>actual11 &&
104+
test_cmp expected11 actual11
105+
'
106+
101107
test_expect_success "remove recursive pin, add direct" '
102108
echo "unpinned $HASH" >expected5 &&
103109
ipfs pin rm -r "$HASH" >actual5 &&
@@ -107,6 +113,13 @@ test_expect_success "remove recursive pin, add direct" '
107113

108114
test_expect_success "remove direct pin" '
109115
echo "unpinned $HASH" >expected6 &&
116+
ipfs pin rm -r=false "$HASH" >actual6 &&
117+
test_cmp expected6 actual6
118+
'
119+
120+
test_expect_success "remove direct pin with pin rm -r" '
121+
echo "unpinned $HASH" >expected6 &&
122+
ipfs pin add -r=false "$HASH"
110123
ipfs pin rm "$HASH" >actual6 &&
111124
test_cmp expected6 actual6
112125
'

test/sharness/t0252-files-gc.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test_expect_success "gc okay after adding incomplete node -- prep" '
3434
ipfs repo gc && # will remove /adir/file1 and /adir/file2 but not /adir
3535
test_must_fail ipfs cat $FILE1_HASH &&
3636
ipfs files cp /ipfs/$ADIR_HASH /adir &&
37-
ipfs pin rm $ADIR_HASH
37+
ipfs pin rm -r=false $ADIR_HASH
3838
'
3939

4040
test_expect_success "gc okay after adding incomplete node" '

0 commit comments

Comments
 (0)