Fix wrong OSIOWaitMicroseconds for leaking stats#105246
Conversation
e896d74 to
a75dccf
Compare
d376e41 to
a958602
Compare
LLVM Coverage Report
Changed lines: 73.08% (19/26) · Uncovered code |
alexey-milovidov
left a comment
There was a problem hiding this comment.
Thanks, LGTM.
The only thing remained unclear - what was the reason they were throwing?
|
I tried to pin it down, but Although excluding other possible reasons, leaving only unreset Kernel side: ClickHouse side: Hypotheses we explicitly ruled out:
What we couldn't fully pin down, and why it doesn't change the fix: which specific call-site reaches Why this PR is the right fix. It eliminates the only remaining route by which |
Cherry pick #105246 to 26.3: Fix wrong `OSIOWaitMicroseconds` for leaking stats
Cherry pick #105246 to 26.4: Fix wrong `OSIOWaitMicroseconds` for leaking stats
Backport #105246 to 26.4: Fix wrong `OSIOWaitMicroseconds` for leaking stats
Backport #105246 to 26.3: Fix wrong `OSIOWaitMicroseconds` for leaking stats

Linked issues
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Fix
OSIOWaitMicrosecondsreporting thread lifetime I/O wait instead of query I/O waitDescription
Long-lived idle threads (e.g.
MergeTreeFetchThreadPoolworkers, globalThreadPoolworkers) legitimately accumulate largedelayacct_blkio_ticksfrom the kernel while sleeping inio_schedule_timeouton a futex. When such a thread is first enlisted into a query viaThreadGroupSwitcher,initPerformanceCounterscreates a freshTasksStatsCountersand callsreset()to establish the baselineprev. Ifreset()throws (e.g. transient read failure on/proc/thread-self/stat), the exception propagates throughThreadGroupSwitcher's constructor where it is silently swallowed — leavingprev.blkio_delay_total = 0(from the uninitialized::taskstats statsmember). The very nextupdateCounterscall then computessafeDiff(0, ~33_days_of_nanoseconds)and dumps it into the query'sOSIOWaitMicroseconds.Two fixes:
::taskstats stats{}inTasksStatsCountersso the member is zero rather than indeterminate ifreset()fails before populating it.(*taskstats).reset()call sites (initPerformanceCountersandresetPerformanceCountersLastUsage) in try/catch: on failure, log the exception and null outtaskstatsfor that thread, so it stops collecting rather than reporting garbage on the next counter update.Version info
26.5.1.79926.4.5.21,26.3.14.17