From eb72b06fe8e62cb77af73f6dc558d384a5a5fe80 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 19 Sep 2025 22:52:48 +0300 Subject: fix --- internal/stats/stats.go | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'internal/stats') diff --git a/internal/stats/stats.go b/internal/stats/stats.go index 3a9a9ab..a8390ef 100644 --- a/internal/stats/stats.go +++ b/internal/stats/stats.go @@ -14,7 +14,6 @@ import ( "path/filepath" "strconv" "sync/atomic" - "syscall" "time" ) @@ -27,6 +26,8 @@ const ( var windowSeconds int64 = int64(defaultWindow.Seconds()) +var errLockWouldBlock = errors.New("stats: lock would block") + // SetWindow sets the sliding window used for pruning and aggregation. func SetWindow(d time.Duration) { if d < time.Second { @@ -88,19 +89,11 @@ func Update(ctx context.Context, provider, model string, sentBytes, recvBytes in return err } defer f.Close() - // Acquire exclusive flock; best-effort ctx support via polling - for { - if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err == nil { - defer syscall.Flock(int(f.Fd()), syscall.LOCK_UN) - break - } - // Wait a bit or exit if context canceled - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(5 * time.Millisecond): - } + unlock, err := acquireFileLock(ctx, f) + if err != nil { + return err } + defer func() { _ = unlock() }() // Read existing file (if any) path := filepath.Join(dir, fileName) var sf File @@ -158,6 +151,25 @@ func Update(ctx context.Context, provider, model string, sentBytes, recvBytes in return nil } +func acquireFileLock(ctx context.Context, f *os.File) (func() error, error) { + fd := f.Fd() + for { + err := tryLockFile(fd) + if err == nil { + return func() error { return unlockFile(fd) }, nil + } + if errors.Is(err, errLockWouldBlock) { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(5 * time.Millisecond): + } + continue + } + return nil, err + } +} + // Snapshot reads and aggregates events within the configured window. func TakeSnapshot() (Snapshot, error) { dir, err := CacheDir() -- cgit v1.2.3