diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-24 20:32:17 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-24 20:32:17 +0300 |
| commit | fadbf135d0b251387fd785083df79e27d1025cac (patch) | |
| tree | b97ae34ed88957a355022c8beedf39d4193a3f47 | |
| parent | 4595fa01693497682beb1b84641233ca4d214072 (diff) | |
fix task 38: plug profiling fd leak on setup failure paths
runTraceWithContext and runHeadlessParquet opened cpu/mem/exec-trace
profile files via setupProfiling, then relied on the shutdown watcher
goroutine (registered later) to close them. If any intervening step
(newEventLoop, recorder.Start) returned an error, the watcher was never
registered and the profile fds leaked until process exit. Add a
defer profiling.stop(logln) immediately after setupProfiling so the fds
are released on every return path. profiling.stop is idempotent via
sync.Once so the watcher and defer can both run harmlessly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| -rw-r--r-- | internal/ior.go | 5 | ||||
| -rw-r--r-- | internal/ior_parquet_sink.go | 5 |
2 files changed, 10 insertions, 0 deletions
diff --git a/internal/ior.go b/internal/ior.go index ab52299..e6e7233 100644 --- a/internal/ior.go +++ b/internal/ior.go @@ -400,6 +400,11 @@ func runTraceWithContext(parentCtx context.Context, cfg flags.Config, started ch if err != nil { return err } + // Guarantee the profiling file descriptors (cpu/mem/exec-trace profiles) are + // closed even if a later setup step fails before the shutdown watcher is + // registered. profiling.stop is idempotent via sync.Once, so double-calling + // it from the watcher goroutine and from this defer is safe. + defer profiling.stop(logln) signalTraceStarted(started) diff --git a/internal/ior_parquet_sink.go b/internal/ior_parquet_sink.go index eb187e8..83ca769 100644 --- a/internal/ior_parquet_sink.go +++ b/internal/ior_parquet_sink.go @@ -119,6 +119,11 @@ func runHeadlessParquet(cfg flags.Config) error { if err != nil { return err } + // Guarantee the profiling file descriptors (cpu/mem/exec-trace profiles) are + // closed even if a later setup step fails before the shutdown watcher is + // registered. profiling.stop is idempotent via sync.Once, so double-calling + // it from the watcher goroutine and from this defer is safe. + defer profiling.stop(logln) el, err := newEventLoop(newEventLoopConfig(cfg)) if err != nil { |
