morningman commented on code in PR #68712:
URL: https://github.com/apache/doris/pull/68712#discussion_r4175919696


##########
be/src/exec/scan/scanner_context.cpp:
##########
@@ -166,14 +164,17 @@ int ScannerContext::_available_pickup_scanner_count() {
     P.adjust_scanners_last_timestamp = now;
     auto old_scanners = P.expected_scanners;
 
-    scanners = std::max(min_scanners, scanners);
-    scanners = std::min(max_scanners, scanners);
+    // The memory limiter is what adapts: its ceiling shrinks when blocks are 
estimated larger or
+    // the query's scan budget is shared by more scan nodes, and grows back 
when they are not. Take
+    // the whole ceiling. Clamping the previous value into [minimum, ceiling] 
instead never raises
+    // it above the minimum, since expected_scanners starts at zero, so every 
scan would keep a
+    // single scanner however much memory there is. The ceiling still wins 
over the minimum, and a
+    // scheduler without slack still holds the Context at its minimum in 
_get_margin() and
+    // can_admit_scan_task().

Review Comment:
   Agreed, and that is the order the description asks for (**Merge order**: 
merge this after #68710). There is no code dependency between the two, so 
nothing changes here; this PR waits for #68710.
   
   One correction to the framing, for the record: merging this first does not 
make the exit reachable, it makes it more likely. The exit is in the libraries 
-- fluss's `FatalExitExceptionHandler` and `ShutdownableThread`, paimon's 
`FatalExitExceptionHandler` -- and it fires whenever a fluss or paimon JNI read 
fills BE's JVM heap, at whatever concurrency got it there. On master today that 
includes `enable_adaptive_scan=false`, under which 
`_available_pickup_scanner_count()` returns `_max_scan_concurrency` and a 
one-instance scan runs the same 16 readers (the "adaptive scan off" column of 
the description); it was also the default concurrency before #61271. #68710 
removes the exit itself: after it, a read that runs the heap out fails its 
queries and BE stays up, with the residue #68710 lists under "Not in this PR".
   



##########
be/src/exec/scan/scanner_context.cpp:
##########
@@ -166,14 +164,17 @@ int ScannerContext::_available_pickup_scanner_count() {
     P.adjust_scanners_last_timestamp = now;
     auto old_scanners = P.expected_scanners;
 
-    scanners = std::max(min_scanners, scanners);
-    scanners = std::min(max_scanners, scanners);
+    // The memory limiter is what adapts: its ceiling shrinks when blocks are 
estimated larger or
+    // the query's scan budget is shared by more scan nodes, and grows back 
when they are not. Take
+    // the whole ceiling. Clamping the previous value into [minimum, ceiling] 
instead never raises
+    // it above the minimum, since expected_scanners starts at zero, so every 
scan would keep a
+    // single scanner however much memory there is. The ceiling still wins 
over the minimum, and a
+    // scheduler without slack still holds the Context at its minimum in 
_get_margin() and
+    // can_admit_scan_task().

Review Comment:
   Pre-existing, and untouched by this PR; I'd rather fix it on its own than 
here.
   
   The cap has counted only running tasks since it was added in #47462 
(`low_memory_mode_scanners() - _num_scheduled_scanners`; #61271 only renamed 
the counter), and the comment on it says that is the intent: it limits the 
running scanners "So that we will not submit too many scan tasks to scheduler". 
Sixteen completed blocks stay queued in low-memory mode on master today with 
`enable_adaptive_scan=false` -- `_get_margin()` runs the same arithmetic there, 
only without the adaptive cap -- and they did by default before #61271; that is 
the trade-off the description names ("the one before #61271"). Counting 
completed plus in-flight tasks, as `can_admit_scan_task()` does, would change 
low-memory behaviour for scans with adaptive scan off as well, which this PR 
does not touch.
   
   It also belongs with two other places where the scan side of low-memory mode 
no longer does what `scanner_context.h` describes ("at most 4 scanners running 
and every scanner will cache at most 1MB data"): `_scanner_scan()` sets 
`raw_bytes_threshold` to 1 MB in low-memory mode but no longer reads it, since 
a scan task reads one block, and its `try_reserve()` call sits on the branch 
after the first read, which a one-block task never takes. Counting queued 
blocks alone would hold an instance at four blocks of `batch_size` rows, not 
the 8 MB the comment promises. I'll take the three together in a follow-up and 
link it here.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to