From a8df3a22a07b5f6e47fac3b7f74a894632a843ad Mon Sep 17 00:00:00 2001 From: Jeromy <jeromyj@gmail.com> Date: Thu, 30 Mar 2017 18:20:36 -0700 Subject: [PATCH] implement ipfs pin update License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com> --- pin.go | 27 +++++++++++++++++++++++++++ pin_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/pin.go b/pin.go index 8c742d1..8de1780 100644 --- a/pin.go +++ b/pin.go @@ -10,6 +10,7 @@ import ( "time" mdag "github.com/ipfs/go-ipfs/merkledag" + dutils "github.com/ipfs/go-ipfs/merkledag/utils" ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore" logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" @@ -86,6 +87,11 @@ type Pinner interface { Pin(context.Context, node.Node, bool) error Unpin(context.Context, *cid.Cid, bool) error + // Update updates a recursive pin from one cid to another + // this is more efficient than simply pinning the new one and unpinning the + // old one + Update(context.Context, *cid.Cid, *cid.Cid, bool) error + // Check if a set of keys are pinned, more efficient than // calling IsPinned for each key CheckIfPinned(cids ...*cid.Cid) ([]Pinned, error) @@ -94,6 +100,7 @@ type Pinner interface { // care! If used improperly, garbage collection may not be // successful. PinWithMode(*cid.Cid, PinMode) + // RemovePinWithMode is for manually editing the pin structure. // Use with care! If used improperly, garbage collection may not // be successful. @@ -447,6 +454,26 @@ func (p *pinner) RecursiveKeys() []*cid.Cid { return p.recursePin.Keys() } +func (p *pinner) Update(ctx context.Context, from, to *cid.Cid, unpin bool) error { + p.lock.Lock() + defer p.lock.Unlock() + + if !p.recursePin.Has(from) { + return fmt.Errorf("'from' cid was not recursively pinned already") + } + + err := dutils.DiffEnumerate(ctx, p.dserv, from, to) + if err != nil { + return err + } + + p.recursePin.Add(to) + if unpin { + p.recursePin.Remove(from) + } + return nil +} + // Flush encodes and writes pinner keysets to the datastore func (p *pinner) Flush() error { p.lock.Lock() diff --git a/pin_test.go b/pin_test.go index cbf89c6..bb90ea0 100644 --- a/pin_test.go +++ b/pin_test.go @@ -1,6 +1,7 @@ package pin import ( + "context" "testing" "time" @@ -9,7 +10,6 @@ import ( "github.com/ipfs/go-ipfs/exchange/offline" mdag "github.com/ipfs/go-ipfs/merkledag" - context "context" ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore" dssync "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore/sync" "gx/ipfs/QmWbjfz3u6HkAdPh34dgPchGbQjob6LXLhAeCGii2TX69n/go-ipfs-util" @@ -367,3 +367,36 @@ func TestPinRecursiveFail(t *testing.T) { t.Fatal(err) } } + +func TestPinUpdate(t *testing.T) { + dstore := dssync.MutexWrap(ds.NewMapDatastore()) + bstore := blockstore.NewBlockstore(dstore) + bserv := bs.New(bstore, offline.Exchange(bstore)) + + dserv := mdag.NewDAGService(bserv) + p := NewPinner(dstore, dserv, dserv) + n1, c1 := randNode() + n2, c2 := randNode() + + dserv.Add(n1) + dserv.Add(n2) + + ctx := context.Background() + if err := p.Pin(ctx, n1, true); err != nil { + t.Fatal(err) + } + + if err := p.Update(ctx, c1, c2, true); err != nil { + t.Fatal(err) + } + + assertPinned(t, p, c2, "c2 should be pinned now") + assertUnpinned(t, p, c1, "c1 should no longer be pinned") + + if err := p.Update(ctx, c2, c1, false); err != nil { + t.Fatal(err) + } + + assertPinned(t, p, c2, "c2 should be pinned still") + assertPinned(t, p, c1, "c1 should be pinned now") +} -- GitLab