diff --git a/snapshot/gc/gc.go b/snapshot/gc/gc.go index 433cbc998..66560c581 100644 --- a/snapshot/gc/gc.go +++ b/snapshot/gc/gc.go @@ -8,6 +8,7 @@ "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/internal/kopialogging" "github.com/kopia/kopia/internal/units" "github.com/kopia/kopia/repo" @@ -20,9 +21,11 @@ var log = kopialogging.Logger("kopia/snapshot/gc") -func findInUseContentIDs(ctx context.Context, rep *repo.Repository, used *sync.Map) error { - w := snapshotfs.NewTreeWalker() +func oidOf(entry fs.Entry) object.ID { + return entry.(object.HasObjectID).ObjectID() +} +func findInUseContentIDs(ctx context.Context, rep *repo.Repository, used *sync.Map) error { ids, err := snapshot.ListSnapshotManifests(ctx, rep, nil) if err != nil { return errors.Wrap(err, "unable to list snapshot manifest IDs") @@ -33,6 +36,8 @@ func findInUseContentIDs(ctx context.Context, rep *repo.Repository, used *sync.M return errors.Wrap(err, "unable to load manifest IDs") } + w := snapshotfs.NewTreeWalker() + w.EntryID = func(e fs.Entry) interface{} { return oidOf(e) } for _, m := range manifests { root, err := snapshotfs.SnapshotRoot(rep, m) if err != nil { diff --git a/snapshot/snapshotfs/snapshot_tree_walker.go b/snapshot/snapshotfs/snapshot_tree_walker.go index 38518eaa4..473ae2725 100644 --- a/snapshot/snapshotfs/snapshot_tree_walker.go +++ b/snapshot/snapshotfs/snapshot_tree_walker.go @@ -12,10 +12,15 @@ "github.com/kopia/kopia/repo/object" ) +// TreeWalker holds information for concurrently walking down FS trees specified +// by their roots type TreeWalker struct { Parallelism int RootEntries []fs.Entry ObjectCallback func(oid object.ID) error + // EntryID extracts or generates an id from an fs.Entry. + // It can be used to eliminate duplicate entries when in a FS + EntryID func(entry fs.Entry) interface{} enqueued sync.Map queue *parallelwork.Queue @@ -26,8 +31,8 @@ func oidOf(entry fs.Entry) object.ID { } func (w *TreeWalker) enqueueEntry(ctx context.Context, entry fs.Entry) { - oid := oidOf(entry) - if _, existing := w.enqueued.LoadOrStore(oid, w); existing { + eid := w.EntryID(entry) + if _, existing := w.enqueued.LoadOrStore(eid, w); existing { return } @@ -54,6 +59,7 @@ func (w *TreeWalker) processEntry(ctx context.Context, entry fs.Entry) error { return nil } +// Run walks the given tree roots func (w *TreeWalker) Run(ctx context.Context) error { for _, root := range w.RootEntries { w.enqueueEntry(ctx, root)