comphead commented on code in PR #7316:
URL: https://github.com/apache/datafusion-comet/pull/7316#discussion_r4417471261


##########
native/core/src/execution/planner.rs:
##########
@@ -777,6 +805,7 @@ impl PhysicalPlanner {
                         }
                     }
                 };
+                self.note_scalar_bytes(&scalar_value);

Review Comment:
   Every item of an `In` list is planned through this arm, so its bytes count 
toward `scalar_bytes`, although list items are only compared and never expanded 
to the batch length. `CometInSet` turns a Spark `InSet` into this `In` message, 
so `col IN (<25,000 UUID strings>)` is about 900 KB of literals and lowers the 
batch size to about 1,165 rows for every operator in the task, with no overflow 
risk to justify it. Could the `In` arm plan its items without counting them?



##########
native/core/src/execution/jni_api.rs:
##########
@@ -1555,6 +1573,17 @@ fn execute_plan(
         exec_context.scans = scans;
         exec_context.shuffle_scans = shuffle_scans;
 
+        // The task context created below copies the session config, so every 
source and the
+        // JVM-fed leaves see the smaller batch size.
+        let batch_size = exec_context.session_ctx.copied_config().batch_size();
+        let rows = scalar_batch_rows(planner.scalar_bytes(), batch_size);
+        if rows < batch_size {
+            let state = exec_context.session_ctx.state_ref();
+            let mut state = state.write();
+            let config = state.config_mut();
+            *config = std::mem::take(config).with_batch_size(rows);

Review Comment:
   `FilterExec` keeps its own batch size, 8192 by default in DataFusion 55.2 
(`FILTER_EXEC_DEFAULT_BATCH_SIZE`), and coalesces its output up to it through 
`LimitedBatchCoalescer` without reading the session value at execute time. 
Comet builds it with `FilterExec::try_new`, so a filter under the expanding 
projection turns two capped 4096-row batches back into one 8192-row batch. I 
expect `SELECT concat((SELECT max(s) FROM wide), CAST(k AS STRING)) FROM ids 
WHERE k >= 0` to still hit the offset overflow. #7280 passes the session batch 
size into `FilterExecBuilder`, but at planning time, before this cap lowers it, 
so it would not cover this either. Could the cap reach filters, for example by 
computing the scalar bytes from the protobuf plan before the planner runs, and 
could the fixture add a query with a `WHERE`?



##########
native/core/src/execution/operators/scan.rs:
##########
@@ -302,6 +309,7 @@ impl ScanStream<'_> {
             baseline_metrics,
             cast_options: CastOptions::default(),
             cast_time,
+            slicer: BatchSlicer::new(batch_size),

Review Comment:
   The description says that with the default configuration nothing is sliced, 
but the slicer is installed with the session batch size whether or not the cap 
lowered it. `Utils.coalesceBroadcastBatches` deliberately merges a broadcast 
into few large batches, so a broadcast build side can arrive here as one batch 
of millions of rows and is now cut into 8192-row slices. `HashJoinExec` then 
rebuilds the build side with `concat_batches`, which copies every slice, where 
a single input batch took arrow's zero-copy path. Could the slicer be installed 
only when the cap actually lowered the batch size? I have not confirmed at 
runtime that a broadcast reaches `ScanExec` as one batch.



-- 
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