Commit eb2035cb authored by Kevin Atkinson's avatar Kevin Atkinson

Check for multiple pinned blocks in a single pass.

Provide a new method, Pinner.CheckIfPinned(), which will check if
any of the arguments are pinned.  Previously IsPinned would need to be
called once for each block.  The new method will speed up the checking
of multiple pinned blocks from O(p*n) to O(p) (where p is the number
of pinned blocks and n is the number of blocks to be check)

Use the new method in "block rm".

License: MIT
Signed-off-by: default avatarKevin Atkinson <k@kevina.org>
parent a519e711
......@@ -75,6 +75,10 @@ type Pinner interface {
Pin(context.Context, *mdag.Node, bool) error
Unpin(context.Context, key.Key, bool) error
// Check if a set of keys are pinned, more efficient than
// calling IsPinned for each key
CheckIfPinned(keys ...key.Key) ([]Pinned, error)
// PinWithMode is for manually editing the pin structure. Use with
// care! If used improperly, garbage collection may not be
// successful.
......@@ -90,6 +94,12 @@ type Pinner interface {
InternalPins() []key.Key
}
type Pinned struct {
Key key.Key
Mode PinMode
Via key.Key
}
// pinner implements the Pinner interface
type pinner struct {
lock sync.RWMutex
......@@ -255,6 +265,70 @@ func (p *pinner) isPinnedWithType(k key.Key, mode PinMode) (string, bool, error)
return "", false, nil
}
func (p *pinner) CheckIfPinned(keys ...key.Key) ([]Pinned, error) {
p.lock.RLock()
defer p.lock.RUnlock()
pinned := make([]Pinned, 0, len(keys))
toCheck := make(map[key.Key]struct{})
// First check for non-Indirect pins directly
for _, k := range keys {
if p.recursePin.HasKey(k) {
pinned = append(pinned, Pinned{Key: k, Mode: Recursive})
} else if p.directPin.HasKey(k) {
pinned = append(pinned, Pinned{Key: k, Mode: Direct})
} else if p.isInternalPin(k) {
pinned = append(pinned, Pinned{Key: k, Mode: Internal})
} else {
toCheck[k] = struct{}{}
}
}
// Now walk all recursive pins to check for indirect pins
var checkChildren func(key.Key, key.Key) error
checkChildren = func(rk key.Key, parentKey key.Key) error {
parent, err := p.dserv.Get(context.Background(), parentKey)
if err != nil {
return err
}
for _, lnk := range parent.Links {
k := key.Key(lnk.Hash)
if _, found := toCheck[k]; found {
pinned = append(pinned,
Pinned{Key: k, Mode: Indirect, Via: rk})
delete(toCheck, k)
}
err := checkChildren(rk, k)
if err != nil {
return err
}
if len(toCheck) == 0 {
return nil
}
}
return nil
}
for _, rk := range p.recursePin.GetKeys() {
err := checkChildren(rk, rk)
if err != nil {
return nil, err
}
if len(toCheck) == 0 {
break
}
}
// Anything left in toCheck is not pinned
for k, _ := range toCheck {
pinned = append(pinned, Pinned{Key: k, Mode: NotPinned})
}
return pinned, nil
}
func (p *pinner) RemovePinWithMode(key key.Key, mode PinMode) {
p.lock.Lock()
defer p.lock.Unlock()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment