Space keeps its scans and refreshes them: zfs diff, folder mtimes, resume after cancel

A scan is saved beside the config and read back after a restart. The next scan starts
from it: on a pool with snapshots zfs diff names what changed and only those folders are
read; elsewhere a folder whose mtime is unchanged keeps its list and only its kept files
are stat'ed again. A cancelled scan keeps what it walked and Resume reads the rest.
Forget drops the saved result. The treemap is every file a tile, grouped by folder, with
no nested boxes: the folder chains of a Linux system made a staircase of empty headers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-23 00:43:30 -07:00
co-authored by Claude Fable 5.1
parent c96d6facad
commit 53d1da08a5
11 changed files with 869 additions and 145 deletions
+9 -2
View File
@@ -11,7 +11,7 @@ import (
// a few bytes per node, decoded without reflection, so a million nodes take well under a
// second either way.
const codecMagic = "HLSPACE1"
const codecMagic = "HLSPACE2"
func Encode(w io.Writer, root *Node) error {
bw := bufio.NewWriterSize(w, 1<<20)
@@ -39,11 +39,15 @@ func Encode(w io.Writer, root *Node) error {
if n.Denied {
flags |= 4
}
if n.Partial {
flags |= 8
}
for _, f := range []func() error{
func() error { return putU(flags) },
func() error { return putI(n.Size) },
func() error { return putI(n.Apparent) },
func() error { return putI(n.MTime) },
func() error { return putI(n.MTimeNs) },
func() error { return putU(uint64(n.Files)) },
func() error { return putU(uint64(n.Dirs)) },
func() error { return putU(uint64(n.SmallN)) },
@@ -91,7 +95,7 @@ func Decode(r io.Reader) (*Node, error) {
if err != nil {
return nil, err
}
n.Dir, n.Mount, n.Denied = flags&1 != 0, flags&2 != 0, flags&4 != 0
n.Dir, n.Mount, n.Denied, n.Partial = flags&1 != 0, flags&2 != 0, flags&4 != 0, flags&8 != 0
if n.Size, err = binary.ReadVarint(br); err != nil {
return nil, err
}
@@ -101,6 +105,9 @@ func Decode(r io.Reader) (*Node, error) {
if n.MTime, err = binary.ReadVarint(br); err != nil {
return nil, err
}
if n.MTimeNs, err = binary.ReadVarint(br); err != nil {
return nil, err
}
u, err := binary.ReadUvarint(br)
if err != nil {
return nil, err