mirror of
https://github.com/restic/restic.git
synced 2024-09-11 21:48:32 +02:00
Hard links to the same file now get the same inode within the FUSE mount. Also, inode generation is faster and, more importantly, no longer allocates. Benchmarked on Linux/amd64. Old means the benchmark with sink = fs.GenerateDynamicInode(1, sub.node.Name) instead of calling inodeFromNode. Results: name old time/op new time/op delta Inode/no_hard_links-8 137ns ± 4% 34ns ± 1% -75.20% (p=0.000 n=10+10) Inode/hard_link-8 33.6ns ± 1% 9.5ns ± 0% -71.82% (p=0.000 n=9+8) name old alloc/op new alloc/op delta Inode/no_hard_links-8 48.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10) Inode/hard_link-8 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta Inode/no_hard_links-8 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10) Inode/hard_link-8 0.00 0.00 ~ (all equal)
45 lines
1.2 KiB
Go
45 lines
1.2 KiB
Go
//go:build darwin || freebsd || linux
|
|
// +build darwin freebsd linux
|
|
|
|
package fuse
|
|
|
|
import (
|
|
"encoding/binary"
|
|
|
|
"github.com/cespare/xxhash/v2"
|
|
"github.com/restic/restic/internal/restic"
|
|
)
|
|
|
|
// inodeFromName generates an inode number for a file in a meta dir.
|
|
func inodeFromName(parent uint64, name string) uint64 {
|
|
inode := parent ^ xxhash.Sum64String(cleanupNodeName(name))
|
|
|
|
// Inode 0 is invalid and 1 is the root. Remap those.
|
|
if inode < 2 {
|
|
inode += 2
|
|
}
|
|
return inode
|
|
}
|
|
|
|
// inodeFromNode generates an inode number for a file within a snapshot.
|
|
func inodeFromNode(parent uint64, node *restic.Node) (inode uint64) {
|
|
if node.Links > 1 && node.Type != "dir" {
|
|
// If node has hard links, give them all the same inode,
|
|
// irrespective of the parent.
|
|
var buf [16]byte
|
|
binary.LittleEndian.PutUint64(buf[:8], node.DeviceID)
|
|
binary.LittleEndian.PutUint64(buf[8:], node.Inode)
|
|
inode = xxhash.Sum64(buf[:])
|
|
} else {
|
|
// Else, use the name and the parent inode.
|
|
// node.{DeviceID,Inode} may not even be reliable.
|
|
inode = parent ^ xxhash.Sum64String(cleanupNodeName(node.Name))
|
|
}
|
|
|
|
// Inode 0 is invalid and 1 is the root. Remap those.
|
|
if inode < 2 {
|
|
inode += 2
|
|
}
|
|
return inode
|
|
}
|