mirror of
https://github.com/octoleo/restic.git
synced 2024-11-25 22:27:35 +00:00
stats: fix hardlink tracking in a snapshot
inodes are only unique within a device. Use the HardlinkIndex from the restorer instead of the custom (broken) hashmap to correctly account for both inode and deviceID.
This commit is contained in:
parent
a8fdcf79b7
commit
731b3a4357
7
changelog/unreleased/pull-4503
Normal file
7
changelog/unreleased/pull-4503
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Bugfix: Correct hardlink handling in `stats` command
|
||||||
|
|
||||||
|
If files on different devices had the same inode id, then the `stats` command
|
||||||
|
did not correctly calculate the snapshot size. This has been fixed.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/pull/4503
|
||||||
|
https://forum.restic.net/t/possible-bug-in-stats/6461/8
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/restic/restic/internal/crypto"
|
"github.com/restic/restic/internal/crypto"
|
||||||
"github.com/restic/restic/internal/repository"
|
"github.com/restic/restic/internal/repository"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
|
"github.com/restic/restic/internal/restorer"
|
||||||
"github.com/restic/restic/internal/ui"
|
"github.com/restic/restic/internal/ui"
|
||||||
"github.com/restic/restic/internal/ui/table"
|
"github.com/restic/restic/internal/ui/table"
|
||||||
"github.com/restic/restic/internal/walker"
|
"github.com/restic/restic/internal/walker"
|
||||||
@ -201,8 +202,8 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
|
|||||||
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{})
|
hardLinkIndex := restorer.NewHardlinkIndex[struct{}]()
|
||||||
err := walker.Walk(ctx, repo, *snapshot.Tree, restic.NewIDSet(), statsWalkTree(repo, opts, stats, uniqueInodes))
|
err := walker.Walk(ctx, repo, *snapshot.Tree, restic.NewIDSet(), statsWalkTree(repo, opts, stats, hardLinkIndex))
|
||||||
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)
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func statsWalkTree(repo restic.Repository, opts StatsOptions, stats *statsContainer, uniqueInodes map[uint64]struct{}) walker.WalkFunc {
|
func statsWalkTree(repo restic.Repository, opts StatsOptions, stats *statsContainer, hardLinkIndex *restorer.HardlinkIndex[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
|
||||||
@ -269,8 +270,8 @@ func statsWalkTree(repo restic.Repository, opts StatsOptions, stats *statsContai
|
|||||||
|
|
||||||
// if inodes are present, only count each inode once
|
// if inodes are present, only count each inode once
|
||||||
// (hard links do not increase restore size)
|
// (hard links do not increase restore size)
|
||||||
if _, ok := uniqueInodes[node.Inode]; !ok || node.Inode == 0 {
|
if !hardLinkIndex.Has(node.Inode, node.DeviceID) || node.Inode == 0 {
|
||||||
uniqueInodes[node.Inode] = struct{}{}
|
hardLinkIndex.Add(node.Inode, node.DeviceID, struct{}{})
|
||||||
stats.TotalSize += node.Size
|
stats.TotalSize += node.Size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user