Skip to content

Commit

Permalink
Merge pull request #153 from sonroyaalmerol/nfs-adjust
Browse files Browse the repository at this point in the history
just straight up do xxhash on path + use relative path on handles
  • Loading branch information
sonroyaalmerol authored Feb 11, 2025
2 parents 4c0c51a + 1497556 commit 0446f88
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 83 deletions.
59 changes: 3 additions & 56 deletions internal/agent/nfs/vssfs/fileid_helpers.go
Original file line number Diff line number Diff line change
@@ -1,67 +1,14 @@
package vssfs

import (
"path/filepath"
"strings"

"github.com/zeebo/xxh3"
)

func generateFullPathID(path string) uint64 {
hash := xxh3.HashString(path)
depth := uint64(getPathDepth(path))
length := uint64(len(path))
ext := getExtensionHash(path)

return (depth&0x3f)<<58 | // 6 bits depth (max 63)
(length&0x3ff)<<48 | // 10 bits length (max 1023)
(uint64(ext)&0xff)<<40 | // 8 bits extension
(hash>>24)&0xffffffffff // 40 bits hash (upper 40 of 64)
return xxh3.HashString(path)
}

// quickMatch recomputes the hash and compares it.
func quickMatch(id uint64, path string) bool {
// Check length first (cheapest operation)
pathLen := uint64(len(path))
if (id >> 48 & 0x3ff) != pathLen {
return false
}

// Then check depth
depth := uint64(getPathDepth(path))
if (id >> 58) != depth {
return false
}

// Finally check partial hash (adjust bit positions to match generateFullPathID)
hash := xxh3.HashString(path)
return (id & 0xffffffffff) == ((hash >> 24) & 0xffffffffff)
}

func getPathDepth(path string) int {
// Count both types of separators for cross-platform support
return strings.Count(path, "/") + strings.Count(path, "\\")
}

func getParentPath(path string) string {
parent := filepath.Dir(path)
if parent == "." || parent == path {
return ""
}
return parent
}

func getFileName(path string) string {
return filepath.Base(path)
}

func getExtensionHash(path string) uint8 {
ext := filepath.Ext(path)
if ext == "" {
return 0
}
if ext[0] == '.' {
ext = ext[1:] // Remove leading dot
}
h := xxh3.HashString(ext)
return uint8(h>>56) ^ uint8(h>>48) ^ uint8(h>>40) ^ uint8(h>>32)
return generateFullPathID(path) == id
}
63 changes: 36 additions & 27 deletions internal/agent/nfs/vssfs/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,21 @@ const (
RootHandleID = uint64(0) // Reserved ID for root directory
)

// VSSIDHandler uses VSSFS's stable file IDs for handle management
// VSSIDHandler uses VSSFS's stable file IDs for handle management.
// It caches relative paths (from the filesystem root) and recreates the full
// path (by joining vssFS.Root()) when needed.
type VSSIDHandler struct {
nfs.Handler
vssFS *VSSFS
vssFS *VSSFS

activeHandlesMu sync.RWMutex
activeHandles map[uint64]string
// Maps fileID to the file's relative path.
activeHandles map[uint64]string
}

func NewVSSIDHandler(vssFS *VSSFS, underlyingHandler nfs.Handler) (*VSSIDHandler, error) {
func NewVSSIDHandler(vssFS *VSSFS, underlyingHandler nfs.Handler) (
*VSSIDHandler, error,
) {
return &VSSIDHandler{
Handler: underlyingHandler,
vssFS: vssFS,
Expand All @@ -38,15 +44,15 @@ func (h *VSSIDHandler) getHandle(key uint64) (string, bool) {
h.activeHandlesMu.RLock()
defer h.activeHandlesMu.RUnlock()

handle, ok := h.activeHandles[key]
return handle, ok
path, ok := h.activeHandles[key]
return path, ok
}

func (h *VSSIDHandler) storeHandle(key uint64, path string) {
func (h *VSSIDHandler) storeHandle(key uint64, relativePath string) {
h.activeHandlesMu.Lock()
defer h.activeHandlesMu.Unlock()

h.activeHandles[key] = path
h.activeHandles[key] = relativePath
}

func (h *VSSIDHandler) ToHandle(f billy.Filesystem, path []string) []byte {
Expand All @@ -55,32 +61,33 @@ func (h *VSSIDHandler) ToHandle(f billy.Filesystem, path []string) []byte {
return nil
}

// Handle root directory specially
// Special-case the root directory: store an empty relative path.
if len(path) == 0 || (len(path) == 1 && path[0] == "") {
return h.createHandle(RootHandleID, vssFS.Root())
return h.createHandle(RootHandleID, "")
}

// Convert NFS path to Windows format
winPath := filepath.Join(path...)
fullPath := filepath.Join(vssFS.Root(), winPath)
// Compute the relative path from the provided NFS path components.
relativePath := filepath.Join(path...)
// Build the full path by joining the filesystem root with the relative path.
fullPath := filepath.Join(vssFS.Root(), relativePath)

// Get or create stable ID
info, err := vssFS.Stat(winPath)
// vssFS methods require the full path.
info, err := vssFS.Stat(fullPath)
if err != nil {
return nil
}

fileID := info.(*VSSFileInfo).stableID
return h.createHandle(fileID, fullPath)
// Only store the relative path in the cache.
return h.createHandle(fileID, relativePath)
}

func (h *VSSIDHandler) createHandle(fileID uint64, fullPath string) []byte {
// Add to cache if not exists
func (h *VSSIDHandler) createHandle(fileID uint64, relativePath string) []byte {
if _, exists := h.getHandle(fileID); !exists {
h.storeHandle(fileID, fullPath)
h.storeHandle(fileID, relativePath)
}

// Convert ID to 8-byte handle
// Convert the 64-bit fileID to an 8-byte handle.
handle := make([]byte, 8)
binary.BigEndian.PutUint64(handle, fileID)
return handle
Expand All @@ -96,21 +103,23 @@ func (h *VSSIDHandler) FromHandle(handle []byte) (billy.Filesystem, []string, er
return h.vssFS, []string{}, nil
}

// Retrieve cached path
fullPath, exists := h.getHandle(fileID)
relativePath, exists := h.getHandle(fileID)
if !exists {
return nil, nil, &nfs.NFSStatusError{NFSStatus: nfs.NFSStatusStale}
}

// Convert Windows path to NFS components
relativePath := strings.TrimPrefix(
// Recreate the full path when needed.
fullPath := filepath.Join(h.vssFS.Root(), relativePath)

// Strip the filesystem root from the full path to get the NFS components.
nfsRelative := strings.TrimPrefix(
filepath.ToSlash(fullPath),
filepath.ToSlash(h.vssFS.Root())+"/",
)

var parts []string
if relativePath != "" {
parts = strings.Split(relativePath, "/")
if nfsRelative != "" {
parts = strings.Split(nfsRelative, "/")
}
return h.vssFS, parts, nil
}
Expand All @@ -120,7 +129,7 @@ func (h *VSSIDHandler) HandleLimit() int {
}

func (h *VSSIDHandler) InvalidateHandle(fs billy.Filesystem, handle []byte) error {
// No-op for read-only filesystem
// No-op for read-only filesystem.
return nil
}

Expand Down

0 comments on commit 0446f88

Please sign in to comment.