summaryrefslogtreecommitdiff
path: root/internal/streamrow
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-09 22:24:30 +0300
committerPaul Buetow <paul@buetow.org>2026-06-09 22:24:30 +0300
commitf601dc90fcef3f270c55a9612c5f0326dbd0f391 (patch)
treef77fb46bebc8263fdac31ae1f517dd82ed8ddf15 /internal/streamrow
parent7031211501884555139351bb676fc0592c9df14c (diff)
feat(parquet): export rename/link oldname + assert oldname capture end-to-end
rename-family (rename/renameat/renameat2) and link-family (link/linkat/ symlink/symlinkat) capture BOTH paths in BPF (name_event.oldname at args[1] for the AT-variants, after a dirfd, plus newname), but only newname reached any persisted output. event.Pair.FileName() resolves to oldnameNewnameFile.Name() == Newname, so the parquet `file` column, CSV, and flamegraph Path all carried newname; the captured oldname survived only in the TUI stream String() repr ("old:... ->new:..."). The oldname capture (and its args[1] index for the AT-variants) was therefore never validated end-to-end, and a wrong-oldname-index regression would surface in no persisted output or test. Surface oldname as one additive, backward-compatible column, mirroring the dedicated optional-column convention (address_space_bytes, requested_sleep_ns, epoll_*): - old_file (String): source/old path for rename/link syscalls; empty for every other syscall. The existing `file` column keeps its semantics (newname for rename/link). Data flows name_event.oldname -> event.Pair.Oldname (populated in handleNameExit alongside the existing File) -> streamrow.Row.OldName -> parquet.Record.OldFile. Docs (docs/parquet-querying.md) and the Magefile parquetValidate column list updated in lockstep. The new TestRenameRenameatOldnameInParquet integration test exercises the renameat AT-variant (oldname at args[1] after the olddfd dirfd) and asserts the parquet old_file column carries renameat-old.txt while file carries renameat-new.txt, and that old_file stays empty for non-rename/ link rows -- locking in the args[1] oldname capture end-to-end. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'internal/streamrow')
-rw-r--r--internal/streamrow/row.go7
1 files changed, 7 insertions, 0 deletions
diff --git a/internal/streamrow/row.go b/internal/streamrow/row.go
index c846346..7ed0520 100644
--- a/internal/streamrow/row.go
+++ b/internal/streamrow/row.go
@@ -37,6 +37,10 @@ type Row struct {
EpollOp string
EpollTargetFD int32
EpollEvents uint32
+ // OldName is the source/old path for rename-family (rename/renameat/
+ // renameat2) and link-family (link/linkat/symlink/symlinkat) syscalls;
+ // FileName carries the "new" path. Empty for every other syscall.
+ OldName string
}
func (r Row) SyscallValue() string {
@@ -124,6 +128,9 @@ func New(seq uint64, pair *event.Pair) Row {
AddressSpaceBytes: pair.AddressSpaceBytes,
RequestedSleepNs: pair.RequestedSleepNs,
FD: UnknownFD,
+ // OldName carries the rename/link source path; FileName is the new path.
+ // Empty for non-rename/link syscalls (pair.Oldname is zero there).
+ OldName: pair.Oldname,
}
if fd, ok := pair.FileDescriptor(); ok {
row.FD = fd