zhouyuan opened a new pull request, #13337: URL: https://github.com/apache/gluten/pull/13337
## What changes are proposed in this pull request? The Velox shuffle reader hands deserialized Arrow buffers to Velox as `BufferView`s, without a copy (`convertToVeloxBuffer`). Velox may read up to `simd::kPadding` bytes past the end of a buffer with SIMD loads; its `AlignedBuffer` keeps those bytes addressable, but the shuffle buffers had no spare capacity beyond Arrow's 64-byte rounding. With the default 4096-row batches, a validity buffer is 512 bytes, so it had no spare capacity at all. Velox [#19292](https://github.com/facebookincubator/velox/pull/19292) (in the Velox bumps since `dft-2026_10_05`) gathers null bits through dictionary indices with `simd::gatherBits()`. On AVX2 that loads 4 bytes at each bit's byte offset, reading up to 3 bytes past the last byte of the nulls. When a shuffle-read nulls buffer ends at a page boundary, the executor dies: ``` SIGSEGV (0xb) ... Problematic frame: C [libvelox.so+0x415e1b2] facebook::velox::simd::gatherBits(unsigned long const*, folly::Range<int const*>, unsigned long*)+0x142 ``` We hit this intermittently on TPC-DS q78 and q97 at SF10000. The failing stages are shuffled hash joins whose probe side reads straight from the shuffle reader; `HashProbe` wraps those columns in dictionaries, and the following Filter/Project/aggregation decodes their nulls. Retries usually pass because the crash depends on memory layout, not data. This PR: - Adds `allocatePaddedBuffer()` and `resizeWithPadding()` to `shuffle/Utils`, which keep `kVeloxBufferPadding` (64 bytes, enough for AVX-512) of spare capacity after a buffer. - Uses them for every payload buffer that reaches Velox: deserialized uncompressed, compressed and type-aware-compressed buffers, `InMemoryPayload::merge()`, and `InMemoryPayload::copyBuffers()`. Compression scratch buffers are unchanged. - Makes `convertToVeloxBuffer()` copy into a Velox `AlignedBuffer` any buffer that still lacks `simd::kPadding` of spare capacity, instead of wrapping it. On the paths above this never happens; it covers any other source. A `static_assert` ties `kVeloxBufferPadding` to `simd::kPadding`. The cost is 64 bytes per shuffle buffer, and no extra copies. This keeps Velox's faster SIMD gather for shuffle data. A Velox-side fix that stops `DecodedVector` from reading past unpadded null buffers is also worth sending upstream, since other callers can pass `BufferView`s too. ## How was this patch tested? - New `cpp/core/tests/PayloadTest.cc` (`payload_test`): checks the helpers, and that buffers from `BlockPayload::deserialize()` (uncompressed and LZ4), `InMemoryPayload::merge()` and `InMemoryPayload::copyBuffers()` keep at least 64 bytes of spare capacity and the original data. On `main`, the deserialize, merge and copy cases fail with e.g. `size 512, capacity 512`; with this patch all 6 tests pass. I ran this in the `apache/gluten:centos-9-jdk17` image against Arrow 15, building only the payload sources rather than the full Gluten build. - `VeloxShuffleReader.cc` compile-checked (`-fsyntax-only`) against Velox `dft-2026_10_14` headers. - Not yet run end to end with this exact patch. The equivalent Velox-side fix was verified on our SF10000 TPC-DS runs, where q78/q97 stopped crashing. ## Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Code (claude-opus-5-5) 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- 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]
