You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/06/01 19:38:02 UTC

(datafusion) 01/01: test: make push_down_filter_regression dynamic filter content deterministic (#22621) (#22643)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-22643-217fd956cf77dfa7ff4611729459110177ef6f87
in repository https://gitbox.apache.org/repos/asf/datafusion.git

commit d070a8b1f1a3c2afe53043cefd11b0af7c818116
Author: Diego Perez Giordán <di...@gmail.com>
AuthorDate: Mon Jun 1 16:37:38 2026 -0300

    test: make push_down_filter_regression dynamic filter content deterministic (#22621) (#22643)
    
    ## Which issue does this PR close?
    
    - Closes #22621.
    
    ## Rationale for this change
    
    `push_down_filter_regression.slt` (added in #22150) asserts the exact
    `DynamicFilter` content rendered by `EXPLAIN ANALYZE` on the `agg_dyn_*`
    fixtures. That content is **not** deterministic: the filter threshold
    tightens
    as each `AggregateExec(mode=Partial)` publishes its running `min`/`max`,
    and the
    `EXPLAIN ANALYZE` snapshot can be taken while the filter is still
    converging.
    
    For `agg_dyn_single`, `file_0` holds the global `min` (1) and `file_1` a
    larger
    partial `min` (3). If the snapshot lands after `file_1` publishes `3`
    but before
    `file_0` publishes `1`, the filter reads `a < 3` instead of the final `a
    < 1` —
    exactly the intermittent CI failure reported in #22621. The fixture's
    comment
    incorrectly claimed the filter *content* was deterministic and only the
    pruning
    *counts* raced.
    
    ## What changes are included in this PR?
    
    Make the filter content independent of publish order by giving **every
    file the
    same per-file min/max**, so any snapshot equals the fully converged
    filter:
    
    - `agg_dyn_single` — both files `(1), (8)` → each file `min=1, max=8`.
    - `agg_dyn_two_col` — each file `min(a)=1, max(b)=9`.
    - `agg_dyn_mixed` — each file `min(a)=1, max(a)=8, max(b)=12`.
    
    `agg_dyn_two_col` and `agg_dyn_mixed` were not in the reported failure
    but shared
    the same latent race (differing per-file extremes), so they are fixed
    too.
    `agg_dyn_nulls` is left untouched — its filter is always `true` and
    never races.
    
    The expected plan text is **unchanged**; only the input data and the
    misleading
    comments are modified. The alternative of forcing a single partition was
    rejected: dynamic aggregate filters are only emitted in `Partial+Final`
    mode
    (`target_partitions >= 2`), so a single partition would emit no filter
    at all.
    
    ## Are these changes tested?
    
    Yes — the modified `push_down_filter_regression.slt` itself is the test.
    It
    passes, and because the asserted filter content no longer depends on
    partition
    scheduling, it is stable across runs (verified by running it repeatedly
    locally).
    
    ## Are there any user-facing changes?
    
    No. Test-only change.
    
    Co-authored-by: Andrew Lamb <an...@nerdnetworks.org>
---
 .../test_files/push_down_filter_regression.slt     | 31 +++++++++++++++-------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/datafusion/sqllogictest/test_files/push_down_filter_regression.slt b/datafusion/sqllogictest/test_files/push_down_filter_regression.slt
index 923a51afc8..b86bd2c51d 100644
--- a/datafusion/sqllogictest/test_files/push_down_filter_regression.slt
+++ b/datafusion/sqllogictest/test_files/push_down_filter_regression.slt
@@ -275,17 +275,25 @@ drop table agg_dyn_e2e;
 statement ok
 set datafusion.execution.target_partitions = 2;
 
-# --- single-column fixture ([5, 1, 3, 8]) split across 2 files ---
+# --- single-column fixture ([1, 8, 1, 8]) split across 2 files ---
+#
+# Every file shares the same per-file min (1) and max (8). This makes the
+# DynamicFilter content deterministic under parallel execution: no matter the
+# order in which the Partial aggregates publish their bounds, every partition
+# contributes the same min/max, so any snapshot taken by `EXPLAIN ANALYZE`
+# equals the fully converged filter. Using files with differing per-file
+# extremes (e.g. min 1 vs 3) makes the snapshot race-dependent, which is what
+# caused the flakiness reported in #22621.
 
 statement ok
 COPY (
-  SELECT * FROM (VALUES (5), (1)) AS v(a)
+  SELECT * FROM (VALUES (1), (8)) AS v(a)
 ) TO 'test_files/scratch/push_down_filter_regression/agg_dyn_single/file_0.parquet'
 STORED AS PARQUET;
 
 statement ok
 COPY (
-  SELECT * FROM (VALUES (3), (8)) AS v(a)
+  SELECT * FROM (VALUES (1), (8)) AS v(a)
 ) TO 'test_files/scratch/push_down_filter_regression/agg_dyn_single/file_1.parquet'
 STORED AS PARQUET;
 
@@ -296,10 +304,11 @@ LOCATION 'test_files/scratch/push_down_filter_regression/agg_dyn_single/';
 
 # Use `analyze_level = summary` + `analyze_categories = 'none'` so metrics
 # render empty; we only care that the `predicate=DynamicFilter [ ... ]` text
-# matches. Pruning metrics here are subject to a parallel-execution race
+# matches. The pruning *counts* are still subject to a parallel-execution race
 # (the order in which Partial aggregates publish filter updates vs. when the
-# scan reads each partition), so the filter *content* is deterministic but
-# the pruning counts are not.
+# scan reads each partition), which is why metrics are suppressed. The filter
+# *content* is kept deterministic by giving every file the same per-file
+# min/max (see the fixture comment above).
 statement ok
 set datafusion.explain.analyze_level = summary;
 
@@ -350,16 +359,18 @@ statement ok
 drop table agg_dyn_single;
 
 # --- two-column fixture: MIN(a) + MAX(b) across columns ---
+# Every file shares the same per-file min(a)=1 and max(b)=9 so the DynamicFilter
+# content is deterministic regardless of publish order (see #22621).
 
 statement ok
 COPY (
-  SELECT * FROM (VALUES (5, 7), (1, 2)) AS v(a, b)
+  SELECT * FROM (VALUES (1, 5), (4, 9)) AS v(a, b)
 ) TO 'test_files/scratch/push_down_filter_regression/agg_dyn_two_col/file_0.parquet'
 STORED AS PARQUET;
 
 statement ok
 COPY (
-  SELECT * FROM (VALUES (3, 4), (8, 9)) AS v(a, b)
+  SELECT * FROM (VALUES (1, 6), (2, 9)) AS v(a, b)
 ) TO 'test_files/scratch/push_down_filter_regression/agg_dyn_two_col/file_1.parquet'
 STORED AS PARQUET;
 
@@ -384,10 +395,12 @@ drop table agg_dyn_two_col;
 # --- mixed expressions: MIN(a), MAX(a), MAX(b), MIN(c+1) ---
 # Supported aggregates (MIN(a), MAX(a), MAX(b)) should drive a filter;
 # MIN(c+1) is unsupported and must not contribute.
+# Every file shares the same per-file min(a)=1, max(a)=8 and max(b)=12 so the
+# DynamicFilter content is deterministic regardless of publish order (see #22621).
 
 statement ok
 COPY (
-  SELECT * FROM (VALUES (5, 10, 100), (1, 4, 70)) AS v(a, b, c)
+  SELECT * FROM (VALUES (1, 12, 100), (8, 4, 70)) AS v(a, b, c)
 ) TO 'test_files/scratch/push_down_filter_regression/agg_dyn_mixed/file_0.parquet'
 STORED AS PARQUET;
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org