mirror of
https://github.com/ipfs/kubo.git
synced 2026-03-10 18:57:57 +08:00
181 lines
3.6 KiB
Go
181 lines
3.6 KiB
Go
package pin
|
|
|
|
import (
|
|
|
|
//ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
|
|
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
|
|
nsds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace"
|
|
"github.com/jbenet/go-ipfs/blocks/set"
|
|
mdag "github.com/jbenet/go-ipfs/merkledag"
|
|
"github.com/jbenet/go-ipfs/util"
|
|
)
|
|
|
|
var recursePinDatastoreKey = ds.NewKey("/local/pins/recursive/keys")
|
|
var directPinDatastoreKey = ds.NewKey("/local/pins/direct/keys")
|
|
var indirectPinDatastoreKey = ds.NewKey("/local/pins/indirect/keys")
|
|
|
|
type Pinner interface {
|
|
Pin(*mdag.Node, bool) error
|
|
Unpin(util.Key, bool) error
|
|
Flush() error
|
|
}
|
|
|
|
type pinner struct {
|
|
recursePin set.BlockSet
|
|
directPin set.BlockSet
|
|
indirPin *indirectPin
|
|
dserv *mdag.DAGService
|
|
dstore ds.Datastore
|
|
}
|
|
|
|
func NewPinner(dstore ds.Datastore, serv *mdag.DAGService) Pinner {
|
|
|
|
// Load set from given datastore...
|
|
rcds := nsds.Wrap(dstore, recursePinDatastoreKey)
|
|
rcset := set.NewDBWrapperSet(rcds, set.NewSimpleBlockSet())
|
|
|
|
dirds := nsds.Wrap(dstore, directPinDatastoreKey)
|
|
dirset := set.NewDBWrapperSet(dirds, set.NewSimpleBlockSet())
|
|
|
|
nsdstore := nsds.Wrap(dstore, indirectPinDatastoreKey)
|
|
return &pinner{
|
|
recursePin: rcset,
|
|
directPin: dirset,
|
|
indirPin: NewIndirectPin(nsdstore),
|
|
dserv: serv,
|
|
dstore: dstore,
|
|
}
|
|
}
|
|
|
|
func (p *pinner) Pin(node *mdag.Node, recurse bool) error {
|
|
k, err := node.Key()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if recurse {
|
|
if p.recursePin.HasKey(k) {
|
|
return nil
|
|
}
|
|
|
|
p.recursePin.AddBlock(k)
|
|
|
|
err := p.pinLinks(node)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
p.directPin.AddBlock(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *pinner) Unpin(k util.Key, recurse bool) error {
|
|
if recurse {
|
|
p.recursePin.RemoveBlock(k)
|
|
node, err := p.dserv.Get(k)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return p.unpinLinks(node)
|
|
} else {
|
|
p.directPin.RemoveBlock(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *pinner) unpinLinks(node *mdag.Node) error {
|
|
for _, l := range node.Links {
|
|
node, err := l.GetNode(p.dserv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
k, err := node.Key()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.recursePin.RemoveBlock(k)
|
|
|
|
err = p.unpinLinks(node)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *pinner) pinIndirectRecurse(node *mdag.Node) error {
|
|
k, err := node.Key()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.indirPin.Increment(k)
|
|
return p.pinLinks(node)
|
|
}
|
|
|
|
func (p *pinner) pinLinks(node *mdag.Node) error {
|
|
for _, l := range node.Links {
|
|
subnode, err := l.GetNode(p.dserv)
|
|
if err != nil {
|
|
// TODO: Maybe just log and continue?
|
|
return err
|
|
}
|
|
err = p.pinIndirectRecurse(subnode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *pinner) IsPinned(key util.Key) bool {
|
|
return p.recursePin.HasKey(key) ||
|
|
p.directPin.HasKey(key) ||
|
|
p.indirPin.HasKey(key)
|
|
}
|
|
|
|
func LoadPinner(d ds.Datastore) (Pinner, error) {
|
|
p := new(pinner)
|
|
|
|
var err error
|
|
p.recursePin, err = set.SetFromDatastore(d, recursePinDatastoreKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
p.directPin, err = set.SetFromDatastore(d, directPinDatastoreKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p.indirPin, err = loadIndirPin(d, indirectPinDatastoreKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (p *pinner) Flush() error {
|
|
recurse := p.recursePin.GetKeys()
|
|
err := p.dstore.Put(recursePinDatastoreKey, recurse)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
direct := p.directPin.GetKeys()
|
|
err = p.dstore.Put(directPinDatastoreKey, direct)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = p.dstore.Put(indirectPinDatastoreKey, p.indirPin.refCounts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|