2016-08-01 16:31:44 +00:00
|
|
|
package restic
|
|
|
|
|
2020-11-07 00:12:07 +00:00
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
|
2020-11-07 13:16:04 +00:00
|
|
|
"github.com/restic/restic/internal/ui/progress"
|
2020-11-07 00:12:07 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
)
|
2017-06-04 09:16:55 +00:00
|
|
|
|
2022-06-12 12:38:19 +00:00
|
|
|
// Loader loads a blob from a repository.
|
|
|
|
type Loader interface {
|
|
|
|
LoadBlob(context.Context, BlobType, ID, []byte) ([]byte, error)
|
2024-05-19 12:54:50 +00:00
|
|
|
LookupBlobSize(tpe BlobType, id ID) (uint, bool)
|
2021-08-07 22:38:17 +00:00
|
|
|
Connections() uint
|
2020-02-22 20:21:09 +00:00
|
|
|
}
|
|
|
|
|
2024-05-20 09:47:53 +00:00
|
|
|
type FindBlobSet interface {
|
2022-08-28 10:17:20 +00:00
|
|
|
Has(bh BlobHandle) bool
|
|
|
|
Insert(bh BlobHandle)
|
|
|
|
}
|
|
|
|
|
2016-08-15 15:58:32 +00:00
|
|
|
// FindUsedBlobs traverses the tree ID and adds all seen blobs (trees and data
|
2020-02-01 20:09:52 +00:00
|
|
|
// blobs) to the set blobs. Already seen tree blobs will not be visited again.
|
2024-05-20 09:47:53 +00:00
|
|
|
func FindUsedBlobs(ctx context.Context, repo Loader, treeIDs IDs, blobs FindBlobSet, p *progress.Counter) error {
|
2020-11-07 00:12:07 +00:00
|
|
|
var lock sync.Mutex
|
2016-08-01 16:40:08 +00:00
|
|
|
|
2020-11-07 00:12:07 +00:00
|
|
|
wg, ctx := errgroup.WithContext(ctx)
|
2020-11-07 13:16:04 +00:00
|
|
|
treeStream := StreamTrees(ctx, wg, repo, treeIDs, func(treeID ID) bool {
|
2020-11-07 00:12:07 +00:00
|
|
|
// locking is necessary the goroutine below concurrently adds data blobs
|
|
|
|
lock.Lock()
|
|
|
|
h := BlobHandle{ID: treeID, Type: TreeBlob}
|
|
|
|
blobReferenced := blobs.Has(h)
|
|
|
|
// noop if already referenced
|
|
|
|
blobs.Insert(h)
|
|
|
|
lock.Unlock()
|
|
|
|
return blobReferenced
|
2020-11-07 13:16:04 +00:00
|
|
|
}, p)
|
2016-08-01 16:40:08 +00:00
|
|
|
|
2020-11-07 00:12:07 +00:00
|
|
|
wg.Go(func() error {
|
|
|
|
for tree := range treeStream {
|
|
|
|
if tree.Error != nil {
|
|
|
|
return tree.Error
|
2016-08-01 16:40:08 +00:00
|
|
|
}
|
2020-11-07 00:12:07 +00:00
|
|
|
|
|
|
|
lock.Lock()
|
|
|
|
for _, node := range tree.Nodes {
|
|
|
|
switch node.Type {
|
2024-07-09 17:51:44 +00:00
|
|
|
case NodeTypeFile:
|
2020-11-07 00:12:07 +00:00
|
|
|
for _, blob := range node.Content {
|
|
|
|
blobs.Insert(BlobHandle{ID: blob, Type: DataBlob})
|
|
|
|
}
|
|
|
|
}
|
2016-08-01 16:40:08 +00:00
|
|
|
}
|
2020-11-07 00:12:07 +00:00
|
|
|
lock.Unlock()
|
2016-08-01 16:40:08 +00:00
|
|
|
}
|
2020-11-07 00:12:07 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return wg.Wait()
|
2016-08-01 16:40:08 +00:00
|
|
|
}
|