Revert "remove redundant logic from ballista logical codec (#2348)" - #2379
Merged
Merged
Conversation
…)" This reverts commit 6fcc736. Delegating file format serde to DataFusion's DefaultLogicalExtensionCodec changed the CopyTo wire format in a way that older clients cannot detect. Ballista <= 54 encodes FileFormatProto { encoder_position, blob }, where encoder_position indexes [Parquet, Csv, Json, Arrow, Avro]. DataFusion encodes FileFormatProto { kind, encoded_file_format }, where kind is FileFormatKind (UNSPECIFIED=0, CSV=1, JSON=2, PARQUET=3, ARROW=4, AVRO=5). Both are a varint followed by a bytes field, so an old message decodes cleanly and the format tag is reinterpreted with the wrong meaning: Parquet fails loudly, CSV and JSON line up by coincidence, and Arrow decodes as Parquet with no error at all. Restore the previous encoding so released 54 clients keep working against a 55 scheduler, and add a test that pins the wire format independently of the production type. See apache#2376.
milenkovicm
approved these changes
Aug 25, 2026
milenkovicm
left a comment
Contributor
There was a problem hiding this comment.
no problem @andygrove
I did not really expect this is going to break this way, but good time to catch it
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
Closes #2376.
Rationale for this change
#2348 delegated file format serde to DataFusion's
DefaultLogicalExtensionCodec. That is a good cleanup in isolation, but it changed theCopyTowire format in a way that older clients cannot detect, and the two encodings are structurally identical so nothing errors at the transport layer.encoder_position: u32, an index into[Parquet, Csv, Json, Arrow, Avro]blobkind: FileFormatKind(UNSPECIFIED=0, CSV=1, JSON=2, PARQUET=3, ARROW=4, AVRO=5)encoded_file_formatBoth are a varint followed by a bytes field, so prost decodes an old message happily and the format tag is simply reinterpreted:
Parquet at least fails loudly, which is what the new job in #2374 caught when a released 54.0.0 Python client ran against a cluster built from the branch. Arrow is the one that worries me:
ArrowLogicalExtensionCodec::try_encode_file_formatwrites an empty payload and the Parquet decoder treats empty bytes as all defaults, soCOPY ... STORED AS ARROWfrom a 54 client executes as Parquet with no error at all.This is not transient skew.
pyballistare-exports datafusion-python types, so the Python bindings cannot move to 55 until there is a matchingdatafusion-pythonrelease, and until then every Python user runs a 54 client against a 55 cluster.Worth noting that DataFusion deliberately kept its own logical proto backward compatible across 54 to 55: removed fields became
reserved 8; // was bool collect_stat,string location = 2was kept and marked deprecated alongside a newrepeated string locations = 16, and everything else is additive. So a 54 client's plan is meant to be readable by a 55 scheduler, and 73 of the 75 Python tests in #2374 confirm it is. This encoding change was the one thing that broke it.What changes are included in this PR?
encoder_positionbasedFileFormatProto.decodes_file_format_bytes_from_a_54_client, which pins the wire format by re-declaring the legacy layout locally and asserting that those bytes still decode to the right format.The existing
file_format_serialization_roundtriptest could not catch this because it encodes and decodes with the same codec, so it passes for any self-consistent encoding. The new test fails on the pre-revert code with exactly the error CI hit, and passes after the revert.Avro is deliberately left out of the new test. DataFusion's
AvroLogicalExtensionCodec::try_decode_file_formatreturns anArrowFormatFactoryin both 54 and 55, which looks like an upstream bug and is unrelated to this change.Are these changes tested?
cargo test -p ballista-core --lib serde::passes, 32 tests.cargo clippy --all-targets --workspace --all-features -- -D warningsclean.cargo fmt --all -- --checkclean.Python client vs branch-built clusterjob should go green once this lands.Are there any user-facing changes?
Yes, in the sense that it restores compatibility. Released 54 clients can once again run
CopyToagainst a scheduler built from main.I am not proposing we carry the duplicated codec forever. The better end state is client side validation of
BALLISTA_PROTOCOL_VERSION(#2370), after which #2348 can land again on a bumped protocol version and old clients get a clear error instead of a mis-decode. That is a larger change than I would want to rush before 55.0.0 (#2369), and on its own it would not help the Python client, since it would turn silent breakage into a hard block that users cannot act on until datafusion-python 55 exists.@milenkovicm sorry to revert your cleanup, happy to help re-land it behind a version check once the client handshake is in place.