brijrajk opened a new pull request, #12614:
URL: https://github.com/apache/gluten/pull/12614

   ## What changes are proposed in this pull request?
   
   Fixes #12613.
   
   `VeloxBloomFilterAggregate` (the JVM-side expression used for Velox bloom 
filters) and the
   native `bloom_filter_agg` Velox function size their internal bit array 
differently, even when
   given the identical `estimatedNumItems`/`numBits` arguments:
   
   - JVM `VeloxBloomFilterAggregate.createAggregationBuffer()` called
     `VeloxBloomFilter.empty(estimatedNumItems)`, sizing the buffer purely from 
the raw item
     count and ignoring `numBits` entirely.
   - Native `BloomFilterAggAggregate.cpp` computes `capacity_ = min(numBits, 
maxNumBits) / 16`
     and ignores the raw item count once `numBits` is known.
   
   For example, given `estimatedNumItems=1000000, numBits=8388608` (Spark's 
plain defaults),
   the JVM side allocated a 16,777,216-bit buffer while the native side 
allocated an
   8,388,608-bit buffer -- exactly 2x different, deterministically, for any 
query using this
   code path.
   
   ### Why this matters
   
   Two-phase aggregation runs the partial and final stages as separate physical 
operators,
   which can independently land on the JVM or on native Velox (e.g. via 
Gluten's whole-stage
   fallback policy, or via `spark.gluten.sql.columnar.hashagg.enabled=false`). 
When the partial
   aggregate runs on one engine and the final aggregate (which merges partial 
buffers) runs on
   the other, the merge combines two differently-sized bit arrays.
   
   Velox's `BloomFilter::merge` (`velox/common/base/BloomFilter.h`) guards the 
size match with
   `VELOX_DCHECK_EQ`, which is compiled out in release builds, so the 
mismatched merge proceeds
   silently instead of throwing. The result is silent data corruption: bits 
inserted relative
   to one array size are later queried relative to a different array size, 
causing bloom
   filter false negatives (values that were definitely inserted are reported as 
absent).
   
   ### The fix
   
   Make `VeloxBloomFilterAggregate`'s JVM-side buffer sizing use the same 
formula as the native
   side (derive capacity from `numBits`, not from raw `estimatedNumItems`), so 
both engines
   agree on capacity for the same input arguments regardless of which engine 
executes which
   stage.
   
   ## How was this patch tested?
   
   Added a regression test to `GlutenBloomFilterAggregateQuerySuite` that runs 
the same
   `bloom_filter_agg` query fully natively and fully on the JVM
   (`spark.gluten.sql.columnar.hashagg.enabled=false`), and asserts the two 
produce
   identically-sized serialized bytes.
   
   Verified the test actually catches the bug: reverting only the fix (keeping 
the new test)
   causes exactly this one test to fail, with 14 other tests in the same suite 
unaffected.
   With the fix, all 15 tests in `GlutenBloomFilterAggregateQuerySuite` pass.
   
   ## Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Sonnet 5 (Anthropic)
   


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