hhhizzz commented on code in PR #24354:
URL: https://github.com/apache/datafusion/pull/24354#discussion_r3781212472


##########
datafusion/datasource-parquet/src/push_decoder.rs:
##########
@@ -342,6 +342,15 @@ impl PushDecoderStreamState {
                 .as_ref()
                 .expect("decoder present")
                 .is_at_row_group_boundary();
+            // Before pruning/rebuilding, align `rg_plan` with the row group 
the
+            // decoder will actually emit next. arrow-rs silently finishes row
+            // groups whose post-predicate selection is empty without handing 
back
+            // a reader, so without this sync `rg_plan` trails the decoder by 
one
+            // and a later rebuild can re-read an already-delivered row group
+            // (#24352).
+            if at_boundary && let Err(e) = 
self.sync_rg_plan_to_decoder_frontier() {

Review Comment:
   
   Could we gate this synchronization on `self.row_group_pruner.is_some()`?
   
   `peek_next_row_group()` is not O(1): in parquet 59.2.0 it clones the 
remaining row-group indices and optional `RowSelection`, and documents a 
per-call cost of `O(remaining row groups + selectors)`. With the current 
`at_boundary`-only guard, ordinary Parquet scans also call it at every 
row-group boundary, adding O(R²) cloning and allocation for a file with R row 
groups, even though no decoder rebuild can occur.
   
   The `rg_plan` desynchronization is only observable when the plan is later 
used to rebuild the decoder, which requires `row_group_pruner` to be `Some`. 
Could we use:
   
   ```rust
   if at_boundary
       && self.row_group_pruner.is_some()
       && let Err(e) = self.sync_rg_plan_to_decoder_frontier()
   {
       return Some((Err(e), self));
   }
   ```
   
   This should preserve the #24352 fix while leaving ordinary Parquet scans 
unchanged. A high-row-group-count benchmark would also help validate this path.
   
   Arrow complexity reference: 
https://github.com/apache/arrow-rs/blob/59.2.0/parquet/src/arrow/push_decoder/remaining.rs#L319-L334



##########
datafusion/sqllogictest/test_files/dynamic_row_group_pruning.slt:
##########
@@ -110,3 +110,70 @@ RESET datafusion.execution.parquet.pushdown_filters;
 
 statement ok
 RESET datafusion.explain.analyze_level;
+
+# Regression test for #24352: TopK dynamic filter + `pushdown_filters` must not

Review Comment:
   Could this q26 regression explicitly enable both dynamic-filter settings and 
assert its own `dynamic_rg_pruning=eligible` plan or non-zero 
`row_groups_pruned_dynamic_filter` metric? It currently relies on defaults and 
final output, so a future optimizer/default change could let the test pass 
without exercising the prune/rebuild path that caused #24352.



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