stats: pass StatsOptions via parameter

This commit is contained in:
Michael Eischer 2023-05-18 19:53:58 +02:00
parent 03b9764bce
commit a466e945d9

View file

@ -49,7 +49,7 @@ Exit status is 0 if the command was successful, and non-zero if there was any er
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runStats(cmd.Context(), globalOptions, args) return runStats(cmd.Context(), statsOptions, globalOptions, args)
}, },
} }
@ -70,8 +70,8 @@ func init() {
initMultiSnapshotFilter(f, &statsOptions.SnapshotFilter, true) initMultiSnapshotFilter(f, &statsOptions.SnapshotFilter, true)
} }
func runStats(ctx context.Context, gopts GlobalOptions, args []string) error { func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args []string) error {
err := verifyStatsInput(gopts, args) err := verifyStatsInput(opts)
if err != nil { if err != nil {
return err return err
} }
@ -111,8 +111,8 @@ func runStats(ctx context.Context, gopts GlobalOptions, args []string) error {
SnapshotsCount: 0, SnapshotsCount: 0,
} }
for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, &statsOptions.SnapshotFilter, args) { for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, &opts.SnapshotFilter, args) {
err = statsWalkSnapshot(ctx, sn, repo, stats) err = statsWalkSnapshot(ctx, sn, repo, opts, stats)
if err != nil { if err != nil {
return fmt.Errorf("error walking snapshot: %v", err) return fmt.Errorf("error walking snapshot: %v", err)
} }
@ -122,7 +122,7 @@ func runStats(ctx context.Context, gopts GlobalOptions, args []string) error {
return err return err
} }
if statsOptions.countMode == countModeRawData { if opts.countMode == countModeRawData {
// the blob handles have been collected, but not yet counted // the blob handles have been collected, but not yet counted
for blobHandle := range stats.blobs { for blobHandle := range stats.blobs {
pbs := repo.Index().Lookup(blobHandle) pbs := repo.Index().Lookup(blobHandle)
@ -156,7 +156,7 @@ func runStats(ctx context.Context, gopts GlobalOptions, args []string) error {
return nil return nil
} }
Printf("Stats in %s mode:\n", statsOptions.countMode) Printf("Stats in %s mode:\n", opts.countMode)
Printf(" Snapshots processed: %d\n", stats.SnapshotsCount) Printf(" Snapshots processed: %d\n", stats.SnapshotsCount)
if stats.TotalBlobCount > 0 { if stats.TotalBlobCount > 0 {
Printf(" Total Blob Count: %d\n", stats.TotalBlobCount) Printf(" Total Blob Count: %d\n", stats.TotalBlobCount)
@ -181,21 +181,21 @@ func runStats(ctx context.Context, gopts GlobalOptions, args []string) error {
return nil return nil
} }
func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo restic.Repository, stats *statsContainer) error { func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo restic.Repository, opts StatsOptions, stats *statsContainer) error {
if snapshot.Tree == nil { if snapshot.Tree == nil {
return fmt.Errorf("snapshot %s has nil tree", snapshot.ID().Str()) return fmt.Errorf("snapshot %s has nil tree", snapshot.ID().Str())
} }
stats.SnapshotsCount++ stats.SnapshotsCount++
if statsOptions.countMode == countModeRawData { if opts.countMode == countModeRawData {
// count just the sizes of unique blobs; we don't need to walk the tree // count just the sizes of unique blobs; we don't need to walk the tree
// ourselves in this case, since a nifty function does it for us // ourselves in this case, since a nifty function does it for us
return restic.FindUsedBlobs(ctx, repo, restic.IDs{*snapshot.Tree}, stats.blobs, nil) return restic.FindUsedBlobs(ctx, repo, restic.IDs{*snapshot.Tree}, stats.blobs, nil)
} }
uniqueInodes := make(map[uint64]struct{}) uniqueInodes := make(map[uint64]struct{})
err := walker.Walk(ctx, repo, *snapshot.Tree, restic.NewIDSet(), statsWalkTree(repo, stats, uniqueInodes)) err := walker.Walk(ctx, repo, *snapshot.Tree, restic.NewIDSet(), statsWalkTree(repo, opts, stats, uniqueInodes))
if err != nil { if err != nil {
return fmt.Errorf("walking tree %s: %v", *snapshot.Tree, err) return fmt.Errorf("walking tree %s: %v", *snapshot.Tree, err)
} }
@ -203,7 +203,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
return nil return nil
} }
func statsWalkTree(repo restic.Repository, stats *statsContainer, uniqueInodes map[uint64]struct{}) walker.WalkFunc { func statsWalkTree(repo restic.Repository, opts StatsOptions, stats *statsContainer, uniqueInodes map[uint64]struct{}) walker.WalkFunc {
return func(parentTreeID restic.ID, npath string, node *restic.Node, nodeErr error) (bool, error) { return func(parentTreeID restic.ID, npath string, node *restic.Node, nodeErr error) (bool, error) {
if nodeErr != nil { if nodeErr != nil {
return true, nodeErr return true, nodeErr
@ -212,19 +212,19 @@ func statsWalkTree(repo restic.Repository, stats *statsContainer, uniqueInodes m
return true, nil return true, nil
} }
if statsOptions.countMode == countModeUniqueFilesByContents || statsOptions.countMode == countModeBlobsPerFile { if opts.countMode == countModeUniqueFilesByContents || opts.countMode == countModeBlobsPerFile {
// only count this file if we haven't visited it before // only count this file if we haven't visited it before
fid := makeFileIDByContents(node) fid := makeFileIDByContents(node)
if _, ok := stats.uniqueFiles[fid]; !ok { if _, ok := stats.uniqueFiles[fid]; !ok {
// mark the file as visited // mark the file as visited
stats.uniqueFiles[fid] = struct{}{} stats.uniqueFiles[fid] = struct{}{}
if statsOptions.countMode == countModeUniqueFilesByContents { if opts.countMode == countModeUniqueFilesByContents {
// simply count the size of each unique file (unique by contents only) // simply count the size of each unique file (unique by contents only)
stats.TotalSize += node.Size stats.TotalSize += node.Size
stats.TotalFileCount++ stats.TotalFileCount++
} }
if statsOptions.countMode == countModeBlobsPerFile { if opts.countMode == countModeBlobsPerFile {
// count the size of each unique blob reference, which is // count the size of each unique blob reference, which is
// by unique file (unique by contents and file path) // by unique file (unique by contents and file path)
for _, blobID := range node.Content { for _, blobID := range node.Content {
@ -254,7 +254,7 @@ func statsWalkTree(repo restic.Repository, stats *statsContainer, uniqueInodes m
} }
} }
if statsOptions.countMode == countModeRestoreSize { if opts.countMode == countModeRestoreSize {
// as this is a file in the snapshot, we can simply count its // as this is a file in the snapshot, we can simply count its
// size without worrying about uniqueness, since duplicate files // size without worrying about uniqueness, since duplicate files
// will still be restored // will still be restored
@ -284,15 +284,15 @@ func makeFileIDByContents(node *restic.Node) fileID {
return sha256.Sum256(bb) return sha256.Sum256(bb)
} }
func verifyStatsInput(gopts GlobalOptions, args []string) error { func verifyStatsInput(opts StatsOptions) error {
// require a recognized counting mode // require a recognized counting mode
switch statsOptions.countMode { switch opts.countMode {
case countModeRestoreSize: case countModeRestoreSize:
case countModeUniqueFilesByContents: case countModeUniqueFilesByContents:
case countModeBlobsPerFile: case countModeBlobsPerFile:
case countModeRawData: case countModeRawData:
default: default:
return fmt.Errorf("unknown counting mode: %s (use the -h flag to get a list of supported modes)", statsOptions.countMode) return fmt.Errorf("unknown counting mode: %s (use the -h flag to get a list of supported modes)", opts.countMode)
} }
return nil return nil