// GC performs a mark and sweep garbage collection of the blocks in the blockstore // first, it creates a 'marked' set and adds to it the following: // - all recursively pinned blocks, plus all of their descendants (recursively) // - bestEffortRoots, plus all of its descendants (recursively) // - all directly pinned blocks // - all blocks utilized internally by the pinner // // The routine then iterates over every block in the blockstore and // deletes any block that is not found in the marked set. func GC(ctx context.Context, bs bstore.GCBlockstore, ls dag.LinkService, pn pin.Pinner, bestEffortRoots []*cid.Cid) (<-chan *cid.Cid, error) { unlocker := bs.GCLock() ls = ls.GetOfflineLinkService() gcs, err := ColoredSet(ctx, pn, ls, bestEffortRoots) if err != nil { return nil, err } keychan, err := bs.AllKeysChan(ctx) if err != nil { return nil, err } output := make(chan *cid.Cid) go func() { defer close(output) defer unlocker.Unlock() for { select { case k, ok := <-keychan: if !ok { return } if !gcs.Has(k) { err := bs.DeleteBlock(k) if err != nil { log.Debugf("Error removing key from blockstore: %s", err) return } select { case output <- k: case <-ctx.Done(): return } } case <-ctx.Done(): return } } }() return output, nil }
func hasChild(ds mdag.LinkService, root *cid.Cid, child *cid.Cid) (bool, error) { links, err := ds.GetLinks(context.Background(), root) if err != nil { return false, err } for _, lnk := range links { c := lnk.Cid if lnk.Cid.Equals(child) { return true, nil } has, err := hasChild(ds, c, child) if err != nil { return false, err } if has { return has, nil } } return false, nil }