Skip to content

GH-48701: [C++][Parquet] Add ALPpd encoding - #48345

Open
prtkgaur wants to merge 143 commits into
apache:mainfrom
prtkgaur:gh540-alp-pseudoDecimal-encoding
Open

GH-48701: [C++][Parquet] Add ALPpd encoding#48345
prtkgaur wants to merge 143 commits into
apache:mainfrom
prtkgaur:gh540-alp-pseudoDecimal-encoding

Conversation

@prtkgaur

@prtkgaur prtkgaur commented Dec 5, 2025

Copy link
Copy Markdown

Co-authored-by: dhirhan17@gmail.com

Rationale for this change

ALP significantly improves on the compression ratio and decompression speed over of float/double columns over other encoding/compression techniques.

Spec

Spec
This PR also contains a terse version of the spec in the file cpp/src/arrow/util/alp/ALP_Encoding_Specification_terse.md which can go in the Encodings.md

Parquet Format PR

Dataset PR (parquet-testing)

apache/parquet-testing#100

What changes are included in this PR?

This PR
Introduces ALP (pseudo-decimal) encoding into c++ arrow code.
We also provide benchmarks and dataset to prove the effectiveness of the above algorithm.

Adding above needed us to add following classes.

  • Alp h/cc : Houses core logic for encoding and decoding.
  • Sampler h/cc : Houses logic to sample and select parameters for encoding.
  • AlpWrapper h/cc : Binds together Alp and Sampler classes.

Integration of the above code was done in

  • Encoder/Decoder cc which exposes wrapper to encode buffer of data.

Are these changes tested?

  • We have added unit tests to test the code.
  • Also the benchmarks have been added that cover wide variety of floating point values from low precision to high precision.

Unit tests

  • alp_test.cc

Benchmark tests

  • encoding_benchmark.cc and encoding_alp_benchmark.cc

Are there any user-facing changes?

  • It's a new encoding so the only impact is query performance which we claim will only get better.

DuckDB

  • We did look at DuckDB's ALP implementation while we were implementing ALP and would like to give that team the desired credit.

@github-actions

github-actions Bot commented Dec 5, 2025

Copy link
Copy Markdown

Thanks for opening a pull request!

If this is not a minor PR. Could you open an issue for this pull request on GitHub? https://github.com/apache/arrow/issues/new/choose

Opening GitHub issues ahead of time contributes to the Openness of the Apache Arrow project.

Then could you also rename the pull request title in the following format?

GH-${GITHUB_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}

or

MINOR: [${COMPONENT}] ${SUMMARY}

See also:

@prtkgaur
prtkgaur force-pushed the gh540-alp-pseudoDecimal-encoding branch 3 times, most recently from 1b78a5c to d563ce0 Compare December 7, 2025 15:46
Comment thread cpp/src/arrow/util/alp/data/floatingpoint_data.tar.gz Outdated
Comment thread cpp/src/parquet/types.h
@alamb

alamb commented Dec 8, 2025

Copy link
Copy Markdown
Contributor

Thanks @prtkgaur -- it is super exciting to see this movement.

Unfortunately, I am not familiar with the C/C++ codebase to give this a realistic review.

I started the CI checks on this PR and had some comments about the testing.

@prtkgaur prtkgaur changed the title [Gh540] Add ALPpd encoding to parquet [Gh539] Add ALPpd encoding to parquet Dec 8, 2025
Comment thread cpp/src/arrow/util/alp/data/floatingpoint_data.tar.gz Outdated
std::string tarball_path = std::string(__FILE__);
tarball_path = tarball_path.substr(0, tarball_path.find_last_of("/\\"));
tarball_path = tarball_path.substr(0, tarball_path.find_last_of("/\\"));
tarball_path += "/arrow/cpp/submodules/parquet-testing/data/floatingpoint_data.tar.gz";

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Reviewer the data sits in the parquet-testing submodule
apache/parquet-testing#100

Comment thread cpp/src/arrow/util/small_vector.h Outdated

// Unsafe resize without initialization - use only when you will immediately
// overwrite the memory (e.g., before memcpy). Only safe for POD types.
void UnsafeResize(size_t n) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this over resize gave us around 2-3% performance improvement

@prtkgaur prtkgaur changed the title [Gh539] Add ALPpd encoding to parquet [Gh539][Encoding] Add ALPpd encoding to parquet Dec 8, 2025
@prtkgaur prtkgaur changed the title [Gh539][Encoding] Add ALPpd encoding to parquet [Gh-539][Encoding] Add ALPpd encoding to parquet Dec 8, 2025
@prtkgaur
prtkgaur force-pushed the gh540-alp-pseudoDecimal-encoding branch from 0c035b7 to 1cb0852 Compare December 8, 2025 23:48
@prtkgaur prtkgaur changed the title [Gh-539][Encoding] Add ALPpd encoding to parquet [Gh-539][ParquetEncoding][c++] Add ALPpd encoding to parquet Dec 9, 2025
@emkornfield

Copy link
Copy Markdown
Contributor

Talked offline and wanted to capture notes on high-level changes:

  1. For headers, lets try to reduce duplication with values already in the parquet header.
  2. For remaining items in headers, lets try to be parsimonious with values (i.e. 4 bytes is probably overkill for enums)
  3. Naming convention on files is off (use snake_case).
  4. Given description of ALP, we probably want a top level encoding enum value for the 2 different modes of ALP.

@prtkgaur
prtkgaur force-pushed the gh540-alp-pseudoDecimal-encoding branch from 35f1ad7 to 0908342 Compare December 15, 2025 21:28
@prtkgaur

Copy link
Copy Markdown
Author

Talked offline and wanted to capture notes on high-level changes:

  1. For headers, lets try to reduce duplication with values already in the parquet header.
  2. For remaining items in headers, lets try to be parsimonious with values (i.e. 4 bytes is probably overkill for enums)
  3. Naming convention on files is off (use snake_case).
  4. Given description of ALP, we probably want a top level encoding enum value for the 2 different modes of ALP.

Thanks for the feedback @emkornfield. We have addressed

  1. Reduce duplication of fields between page header and alp header
  2. Other fields have been updated to use 1 byte. Header is now just 8 bytes compared to 40 bytes earlier.
  3. Naming of files has been updated.
  4. We do have the top level enums describing the mode and layout structure.
    enum class AlpBitPackLayout { kNormal }; and enum class AlpMode { kAlp };

@prtkgaur prtkgaur changed the title [Gh-539][ParquetEncoding][c++] Add ALPpd encoding to parquet [Gh-48701][ParquetEncoding][c++] Add ALPpd encoding to parquet Dec 31, 2025
@kou kou changed the title [Gh-48701][ParquetEncoding][c++] Add ALPpd encoding to parquet GH-48701: [C++][Parquet] Add ALPpd encoding Jan 1, 2026
@github-actions

github-actions Bot commented Jan 1, 2026

Copy link
Copy Markdown

⚠️ GitHub issue #48701 has been automatically assigned in GitHub to PR creator.

Comment thread cpp/src/parquet/decoder.cc Outdated

// Slow path: partial read - decode to intermediate buffer
// ALP Bit unpacker needs batches of 64
if (needs_decode_) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO(prateek) : check with Antoine and other reviewers if there is a way to relax this constraint. Though this has negligible impact on performance.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no action needed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

umm ideally this submodule shouldn't be attached with this commit.
Should revert the changes to this file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request for dataset
apache/parquet-testing#100

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check cpp/src/arrow/util/alp/ALP_Encoding_Specification_terse.md for a more terse spec of the encoding.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this file will be removed once the spec in parquet format repository is merged.


## 2. Data Layout

ALP encoding consists of a page-level header followed by one or more encoded vectors. Each vector contains up to 1024 elements.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace 1024 with the constant specified in AlpConstant file.

@prtkgaur
prtkgaur force-pushed the gh540-alp-pseudoDecimal-encoding branch from 1b08599 to f5f5011 Compare January 12, 2026 16:00
@prtkgaur
prtkgaur marked this pull request as ready for review January 13, 2026 18:03
@prtkgaur
prtkgaur requested a review from wgtmac as a code owner January 13, 2026 18:03
Merges the duplicate float/double fixtures into one typed suite and replaces
tolerant float comparisons with the bit-exact helper the file already defines.
@alamb

alamb commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@pitrou @kou and @mapleFU -- do you have any thoughts or ideas on who could help review and approve this PR and help get it merged? I am sorry for the direct ping, but you seem to be the most active committers merging into the parquet directory recently

@wgtmac

wgtmac commented Aug 28, 2026

Copy link
Copy Markdown
Member

Sorry for the long delay! I'll take a look.

@HuaHuaY
HuaHuaY requested review from HuaHuaY and sdf-jkl and removed request for sdf-jkl August 31, 2026 06:34

@wgtmac wgtmac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @prtkgaur for adding the C++ implementation! I haven't thoroughly reviewed all files yet but I think I have enough questions (especially architectural ones) to post. Let me know what you think.

It would be great if @pitrou could help advise this PR.

auto file = test::get_data_file(file_name);
auto pool = ::arrow::default_memory_pool();
std::unique_ptr<FileReader> parquet_reader;
ASSERT_OK(FileReader::Make(pool, ParquetFileReader::OpenFile(file, false),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not compile any more if rebased.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests have since moved to parquet/arrow/arrow_encoding_test.cc, per your other comment, so a rebase now picks up a different file than the one you were on. If you're still hitting a compile error there, paste it and I'll chase it — I'd rather not close this on the move having happened to fix it.

Comment thread cpp/src/parquet/encoder.cc Outdated
int64_t EstimatedDataEncodedSize() override { return sink_.length(); }

std::shared_ptr<Buffer> FlushValues() override {
if (sink_.length() == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an optional page is all null, PutSpaced adds zero values and sink_ stays empty. This path still writes a page because the writer counts levels, so returning a zero-byte payload violates the required 7-byte ALP header and the reader rejects it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real bug, fixed. FlushValues no longer short-circuits on an empty sink — it runs the normal path with a zero count, producing a 7-byte header with no offset section. The reader accepts that: Open returns early when there are no vectors and num_values_ comes out 0.

Two tests write an all-null optional V2 page and read it back; the writer path had no coverage at all before. I checked they fail without the fix.

Comment thread cpp/src/arrow/util/alp/alp_codec.cc Outdated
const uint8_t* body = input + AlpHeader::kSize;
const int64_t body_size = input_size - static_cast<int64_t>(AlpHeader::kSize);

ARROW_RETURN_NOT_OK(DecodeAlp<TargetType>(num_elements, body, body_size,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DecodeAlp sizes its work from header.num_elements, but AlpDecoder returns the outer page count. If the header count is smaller (including zero), decoding can return OK after writing only part of the output. Please require the header count to match the expected non-null value count.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Required now — Decode fails when the two disagree in either direction, since a smaller header count leaves part of output unwritten and a larger one overruns it.

AlpRobustnessTest.HeaderElementCountMismatch drives both sides, including the zero case you called out. The decoder passing the wrong count in the first place was the other half of this; that's your SetData comment below.

Comment thread cpp/src/arrow/util/alp/alp_codec.cc Outdated
" > capacity=", num_elements);
}

// Validate offset is within bounds and enough buffer remains for metadata

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ALP spec requires offset[0] = num_vectors * 4 and each later offset to be the previous offset plus the previous vector size. This code only checks each offset independently, so duplicate, backward, or gapped offsets are accepted and can decode the wrong bytes.

@prtkgaur prtkgaur Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. The chain rule is checked now, exactly as you describe. VectorReader::Open checks the offsets in one pass against a running expected value, starting at num_vectors * sizeof(OffsetType) and adding each vector's size, and says which vector broke the chain. The end of the last vector is bound-checked against the buffer.

AlpRobustnessTest.CorruptedOffsetChain covers duplicate, backward, gapped and skipped offsets, all chosen to stay inside the buffer so only the chain rule can reject them.

Comment thread cpp/src/arrow/CMakeLists.txt Outdated
list(APPEND ARROW_UTIL_SRCS util/compression_zstd.cc)
endif()

# ALP (for Parquet encoder/decoder)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add these to meson.build as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to meson.build too. The CMake side had a second problem worth mentioning: the ALP sources were in ARROW_UTIL_SRCS and also listed in the alp-test target, so the test compiled them a second time instead of linking the library's copies. They build once now, and the test is registered in both build systems.

Comment thread cpp/src/parquet/encoder.cc Outdated
// ----------------------------------------------------------------------
// ALP encoder (Adaptive Lossless floating-Point)

// TODO: support incremental encoding. Today `Put` only appends raw input

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's shorten these comments. They look like notes that taken by coding agents to talk to themselves.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, and trimmed — the block above AlpEncoder went from 33 lines to 7. What's left is the two TODOs and one fact each: Put buffers the page, so working memory scales with it, and the PLAIN fallback needs a ratio estimate the sampler computes but doesn't expose. I kept the paper's break-even numbers, since they're the evidence the fallback matters; the argument about where that decision belongs is down to one clause.

Comment thread cpp/src/parquet/decoder.cc Outdated
#include "arrow/array/builder_dict.h"
#include "arrow/array/builder_primitive.h"
#include "arrow/type_traits.h"
#include "arrow/util/alp/alp.h"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably can optimize header structure to include only one alp header.

@prtkgaur prtkgaur Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decoder.cc is down to one, alp_codec_internal.h; it had been pulling in three. What removed the other two is that the decoder no longer derives anything itself — SetData opens a VectorReader and takes the page's value count from it, instead of computing it from AlpConstants and the header layout, so the codec header is the only one it needs. encoder.cc still has a second include, for AlpConstants::kAlpVectorSize, the writer's fixed vector size.

Comment thread cpp/src/parquet/decoder.cc Outdated
using Base = TypedDecoderImpl<DType>;
using T = typename DType::c_type;

// TODO: support incremental decode. Partial reads currently decode the entire

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that incremental decoding is worth doing in this PR.

@prtkgaur prtkgaur Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and done. VectorReader validates the header and the whole offset chain once in Open and then decodes any single vector on demand, so Decode is Open plus a loop and both paths share one validator instead of having one each — a few lines longer than the whole-page version rather than shorter.

A vector entered at its first value and read to its end decodes straight into the caller's buffer; anything else goes through one vector of scratch. So the decoder holds 4 or 8 KB rather than a page, pool-backed and allocated on first use — which also answers your scratch-buffer comment. TestAlpEncoding.BatchedDecode covers six batch plans over a 2000-value page.

Comment thread cpp/src/parquet/decoder.cc Outdated
private:
std::vector<T> decoded_buffer_;
size_t current_offset_;
bool needs_decode_;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs_decode_, current_offset_, and inherited num_values_ all track the same page progress, while different branches update different subsets. Please consolidate this into one source of truth so the state cannot diverge.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidated to one: the inherited num_values_. needs_decode_ and current_offset_ are gone, along with a scratch_filled_ flag that my first attempt at this introduced. Position is derived as total_values_ - num_values_, with total_values_ set once by SetData and not touched again, and Decode and DecodeArrow each decrement num_values_ exactly once, so the two paths can't disagree.

Comment thread cpp/src/parquet/encoder.cc Outdated

private:
::arrow::BufferBuilder sink_;
int32_t vector_size_;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int32_t vector_size_;
const int32_t vector_size_;

@prtkgaur prtkgaur Sep 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The member is gone instead — it's a static constexpr int32_t kVectorSize on the encoder now, since nothing sets it per instance.

encoding_alp_benchmark.cc loaded 20 real-world floating-point CSVs from
cpp/submodules/parquet-testing, which required pointing the submodule at a
fork carrying a dataset tarball several times larger than the whole of
parquet-testing. That data was never accepted upstream, so the benchmark
cannot build for anyone else and the submodule bump has to travel with the
branch.

Remove the benchmark, its CMake entry, and the submodule bump. The synthetic
ALP cases in encoding_benchmark.cc are unaffected and stay.
apache/parquet-testing now ships alp_extended.zstd.parquet, published for
exactly this purpose. All eight of its columns hold the same 9032 values;
float_plain and double_plain are PLAIN-encoded references, so a correct
decoder reproduces them bit for bit and the test needs no hardcoded
expected values. Its three vector sizes per type (1024, 4096, 32) force a
reader to honour log_vector_size from the page header rather than assume
the default, which nothing here covered before.

This replaces the eight tests that read ALP files and expected-value CSVs
from a fork of parquet-testing. That data was never accepted upstream, so
those tests could not run against the submodule pointer this branch now
carries. The conformance file covers strictly more: three distinct NaN bit
patterns, +/-Inf, -0.0, subnormals, a value that cannot round-trip as a
decimal, all-exception vectors, a constant vector (bit_width 0), and nulls.
It also retires ~150 lines of hand-rolled CSV parsing.

Comparison is on bit patterns rather than values, so NaN payloads are
actually checked (NaN != NaN under ==) and -0.0 is not accepted in place
of 0.0. A separate test asserts the reference column really does contain
the corner cases, so the suite cannot pass vacuously if the file is ever
regenerated as ordinary data.
ALP is a Preview feature in the Parquet format. The Preview note in
Encodings.md asks writers to keep such an encoding behind an opt-in flag,
because a reader that has not implemented it must fail rather than return
wrong values, and the ecosystem has not caught up yet.

Add WriterProperties::Builder::enable_alp_encoding(), with a per-column
overload, defaulting to disabled. The flag grants permission; it does not
select the encoding. Selecting Encoding::ALP for a column that has not been
granted permission makes build() throw, rather than silently falling back
to PLAIN, so a caller who asked for ALP never gets something else without
being told. WriterProperties' constructor is private, so build() is the
only way to construct one and the check cannot be bypassed.

This mirrors parquet-java, which added withAlpEncoding(boolean) with the
same default. The versioning discussion on dev@ settled that
implementations agree on behaviour but each chooses its own API shape, and
there is no format-level field to write yet, so this is writer-side only.

Decoding stays unconditional: Arrow implements ALP, so it can always read
what it is given.
Bit extraction in the conformance test picked a 64-bit holder for any type
that was not four bytes wide, then copied only sizeof(CType) bytes into it,
so instantiating the fixture on a half float would have compared six bytes
of uninitialized stack. Move it into a helper with a static_assert on the
width.

ReferenceColumnsCoverCornerCases was plural but only looked at
double_plain; check float_plain too. It also counted NaNs while claiming to
check "three distinct NaN bit patterns" -- distinctness is the whole reason
to compare bits, so collect the payloads in a set and assert on its size.
Print bit patterns in hex when a comparison fails, since decimal is
unreadable for a value like 0x7ff800deadbeef00.

AlpRejectedWithoutOptIn matched only "enable_alp_encoding", which both
branches of the check emit, so it did not pin down that the default column
properties are what rejected the build. Match on both substrings.

Add ALP to the encodings support table in docs/source/cpp/parquet.rst,
which lists every other encoding Arrow reads and writes, with a note
covering the Preview status, the opt-in flag and the FLOAT/DOUBLE
restriction.
Refuse a count above INT32_MAX before it sizes the sampling span, require the
page header's count to equal the caller's, and check each vector offset against
where the previous vector ended rather than only against the buffer bounds.
The page header counts nulls, so AlpDecoder now reads its count from the ALP
header, keeps one progress variable, expands nulls with SpacedExpandLeftward and
holds its whole-page scratch in a pool-backed buffer.
An all-null optional page buffers no values, and the empty payload it used to
emit has no header for the reader to load. Also drop the vector_size parameter
nothing passes and trim the encoder's TODO comments.
Move them into the sorted ARROW_UTIL_SRCS list so alp-test links them instead of
compiling them a second time, and add the same sources and test to meson.
Every multi-byte wire field now converts explicitly, so the big-endian
static_assert is gone. The bit-packed values already needed no conversion.
It is only used by the header codec in alp_codec.cc, so it belongs in that
file's anonymous namespace.
Each test was checked against the code with its validation removed, so a
regression in any of the three shows up as a failure.
The batched test fails if the decoder's remaining count and its scratch index
disagree, which is the divergence the old three-variable state allowed.
AlpCodec<T>::VectorReader validates the header and offset chain once, then
decodes any single vector on demand, so a batched reader needs scratch for
one vector rather than for a whole page.
arrow_reader_writer_test.cc is already long, so the encoding round trips move
to arrow/arrow_encoding_test.cc, which later encodings can share.
The names now say what the install rules already do: these headers are not
installed and carry no backward-compatibility obligation.
The test hand-duplicated a float block and a double block, which is what the
type-parameterized suite is for.  Also move the float decode benchmark's output
buffer out of the loop and stop timing its SetData, matching the double one.
Incremental decode calls DecodeVector once per vector, and each call built a
fresh view and a fresh vector of unpacked integers, so a page's worth of
vectors meant a heap allocation per vector (three, when the vector had
exceptions). Let the reader hold that scratch and reuse it: ResetDataOnly
points an existing view at the next vector's data, and DecompressVectorView
now unpacks into a caller-provided span instead of returning a vector.

Decoding 32 vectors of doubles allocates 11 times for the first vector and
nothing after it, where before it allocated on every one.
@prtkgaur
prtkgaur requested a review from wgtmac September 3, 2026 16:47
The ALP decode benchmarks were the only ones in the file hiding SetData behind
PauseTiming, which left their numbers incomparable to their neighbours'.
parquet.thrift is a vendored copy of the format repo's file, and ALP has
since been merged there. The comment written here says the same thing in
different words, and points at Encodings.md#alp for the full spec, which
now lives in AlpEncoding.md.
parquet/encoder.cc and decoder.cc call AlpCodec, whose out-of-line
definitions live in libarrow, so the ten symbols they reference have to
cross the library boundary. Every other arrow symbol libparquet imports
carries ARROW_EXPORT; these did not, which breaks an MSVC shared build
and any build that gives arrow hidden default visibility.

Also fold the three-deep namespace into one, which is what clang-tidy's
modernize-concat-nested-namespaces asks for.
Four of the five const members were copies of AlpConstants values and
two of those were only ever read to derive the sampling interval, which
is itself a constant. Reference the constants directly and keep the
derived one as a static constexpr, which removes the constructor and 40
bytes from every sampler.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants