pin.go 3.71 KB
Newer Older
1 2 3
package pin

import (
4 5

	//ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
6
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
7
	nsds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go/namespace"
8 9 10 11 12
	"github.com/jbenet/go-ipfs/blocks/set"
	mdag "github.com/jbenet/go-ipfs/merkledag"
	"github.com/jbenet/go-ipfs/util"
)

13 14 15 16
var recursePinDatastoreKey = ds.NewKey("/local/pins/recursive/keys")
var directPinDatastoreKey = ds.NewKey("/local/pins/direct/keys")
var indirectPinDatastoreKey = ds.NewKey("/local/pins/indirect/keys")

17
type Pinner interface {
Jeromy's avatar
Jeromy committed
18
	IsPinned(util.Key) bool
19 20
	Pin(*mdag.Node, bool) error
	Unpin(util.Key, bool) error
21
	Flush() error
22 23 24 25 26
}

type pinner struct {
	recursePin set.BlockSet
	directPin  set.BlockSet
27
	indirPin   *indirectPin
28
	dserv      *mdag.DAGService
29
	dstore     ds.Datastore
30 31 32
}

func NewPinner(dstore ds.Datastore, serv *mdag.DAGService) Pinner {
33 34

	// Load set from given datastore...
35 36
	rcds := nsds.Wrap(dstore, recursePinDatastoreKey)
	rcset := set.NewDBWrapperSet(rcds, set.NewSimpleBlockSet())
37

38 39 40 41
	dirds := nsds.Wrap(dstore, directPinDatastoreKey)
	dirset := set.NewDBWrapperSet(dirds, set.NewSimpleBlockSet())

	nsdstore := nsds.Wrap(dstore, indirectPinDatastoreKey)
42
	return &pinner{
43 44
		recursePin: rcset,
		directPin:  dirset,
45
		indirPin:   NewIndirectPin(nsdstore),
46
		dserv:      serv,
47
		dstore:     dstore,
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
	}
}

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 {
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	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
		}
	}
108 109 110 111 112 113 114 115 116
	return nil
}

func (p *pinner) pinIndirectRecurse(node *mdag.Node) error {
	k, err := node.Key()
	if err != nil {
		return err
	}

117
	p.indirPin.Increment(k)
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	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)
}
141

Jeromy's avatar
Jeromy committed
142
func LoadPinner(d ds.Datastore, dserv *mdag.DAGService) (Pinner, error) {
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	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
	}

Jeromy's avatar
Jeromy committed
160 161 162
	p.dserv = dserv
	p.dstore = d

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
	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
}