Skip to content

Commit fd2ea21

Browse files
jacktenggCopilot
andcommitted
[fix](be) Fix cross-thread CLOCK_THREAD_CPUTIME_ID read in scanner CPU timer
### What problem does this PR solve? Problem Summary: Scanner::_cpu_watch (ThreadCpuStopWatch using CLOCK_THREAD_CPUTIME_ID) was started via resume() on a scanner worker thread but read via pause() on the pipeline task thread. Since CLOCK_THREAD_CPUTIME_ID is a per-thread CPU clock, reading it on a different thread produces garbage/negative values, triggering the DCHECK: Check failed: _value.load() > -1L (-39943795 vs. -1) delta: -252570258 In the non-EOS path of _scanner_scan(), update_scanner_profile() (which calls pause()) was only called for the EOS path. The non-EOS path left _cpu_watch running and later ScannerScheduler::submit() called pause() from the pipeline task thread. Fix: 1. Always call update_scanner_profile() before push_back_scan_task() in _scanner_scan(), ensuring pause() runs on the scanner worker thread for both EOS and non-EOS paths. 2. Reinitialize _cpu_watch after reading in _update_scan_cpu_timer() so that any subsequent cross-thread pause() call in submit() safely reads 0. ### Release note None ### Check List (For Author) - Test: Manual test - verified the logic by code analysis - Behavior changed: No - Does this need documentation: No Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent edc0524 commit fd2ea21

File tree

2 files changed

+10
-3
lines changed

2 files changed

+10
-3
lines changed

be/src/exec/scan/scanner.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,11 @@ void Scanner::_collect_profile_before_close() {
279279

280280
void Scanner::_update_scan_cpu_timer() {
281281
int64_t cpu_time = _cpu_watch.elapsed_time();
282+
// Reinitialize _cpu_watch after reading. _cpu_watch uses CLOCK_THREAD_CPUTIME_ID
283+
// (per-thread CPU clock), so it must only be read on the thread that started it.
284+
// Reinitializing here prevents stale cross-thread reads if pause() is called again
285+
// from a different thread (e.g., in ScannerScheduler::submit() on the pipeline thread).
286+
_cpu_watch = ThreadCpuStopWatch();
282287
_scan_cpu_timer += cpu_time;
283288
if (_state && _state->get_query_ctx()) {
284289
_state->get_query_ctx()->resource_ctx()->cpu_context()->update_cpu_cost_ms(cpu_time);

be/src/exec/scan/scanner_scheduler.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,12 @@ void ScannerScheduler::_scanner_scan(std::shared_ptr<ScannerContext> ctx,
301301
eos = true;
302302
}
303303

304+
// Always update scanner profile (including pause()) on the scanner worker thread
305+
// before leaving. _cpu_watch uses CLOCK_THREAD_CPUTIME_ID which is per-thread,
306+
// so elapsed_time() must be read on the same thread that called resume()/start().
307+
update_scanner_profile();
308+
304309
if (eos) {
305-
// If eos, scanner will call _collect_profile_before_close to update profile,
306-
// so we need update_scanner_profile here
307-
update_scanner_profile();
308310
scanner->mark_to_need_to_close();
309311
scan_task->set_state(ScanTask::State::EOS);
310312
} else {

0 commit comments

Comments
 (0)