Skip to content

fix: Concatenate chunk bitmaps in a single pass - #223

Open
SamuelSchlesinger wants to merge 2 commits into
DataHaskell:mainfrom
SamuelSchlesinger:fix/concat-many-columns-linear
Open

fix: Concatenate chunk bitmaps in a single pass#223
SamuelSchlesinger wants to merge 2 commits into
DataHaskell:mainfrom
SamuelSchlesinger:fix/concat-many-columns-linear

Conversation

@SamuelSchlesinger

Copy link
Copy Markdown

The nullable path of concatManyColumns folded the per-chunk bitmaps pairwise and re-concatenated the data vectors at each step just to carry a running length, so it recopied the accumulator — the thing the function exists to avoid. Use concatValidity instead.

160 chunks of 10k nullable rows: forcing the bitmap goes from 449ms to 7.9ms. The test pins values and null positions across uneven chunks and checks allocation grows linearly.

concatManyColumns concatenates the data in one VB.concat, but the
nullable path folds the per-chunk bitmaps pairwise and carries the
running length by concatenating the data vectors again at every step:

    concatBms ((b1, v1) : (b2, v2) : rest') =
        let merged = go b1 (VB.length v1) b2 (VB.length v2)
         in concatBms ((merged, v1 <> v2) : rest')

That reinstates the accumulator recopy the function exists to avoid.
Allocation grows 15x for 4x the rows where linear would be 4x.

The second case is an oracle rather than a repro: uneven chunks that
straddle byte boundaries must keep every value and null position, which
is the property the new bitmap writes have to preserve.
The nullable path folded the per-chunk bitmaps pairwise and
concatenated the data vectors on every step just to carry a running
length, so it recopied the accumulator exactly the way the function's
one-pass design sets out to avoid. Take the lengths up front and splice
every chunk's bits into one preallocated destination with
concatValidity, the byte-level splice the Bitmap module already has.

For 160 chunks of 10k nullable rows: allocation growth drops from 15x to
4x per 4x the rows, and forcing the bitmap from 449ms to 7.9ms.
@SamuelSchlesinger
SamuelSchlesinger force-pushed the fix/concat-many-columns-linear branch from 41267d5 to 4a8209c Compare August 25, 2026 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant