Skip to content

Expand Java/C++ cross-language compatibility matrix to full coverage - #1068

Merged
ColinLeeo merged 10 commits into
apache:developfrom
ColinLeeo:compat-matrix-full-coverage
Nov 5, 2026
Merged

ColinLeeo merged 10 commits into
apache:developfrom
ColinLeeo:compat-matrix-full-coverage

Conversation

@ColinLeeo

Copy link
Copy Markdown
Contributor

Summary

Closes #1057.

The Java/C++ compatibility matrix now covers every (type, encoding, compression)
combination both implementations can write, at four data scales, in both
directions — and building it out surfaced and fixed two real cross-language
format bugs.

Changes

  • Add a shared spec (compat/compatibility-matrix.csv) consumed by both the
    Java and C++ tests, so the two matrices cannot drift.
  • Replace the table-only Java/C++ compatibility tests with a single
    spec-driven EncodingCompressionCompatibilityTest on each side, covering
    both models (table + tree), all six compressions, and four data scales
    (10 / 1k / 100k / 1M rows) with page sizes that cross page boundaries at
    every scale.
  • Implement the C++ codecs that were missing so every Java-writable
    combination is now C++-readable: FLOAT/DOUBLE RLE, FLOAT/DOUBLE GORILLA_V1,
    DATE/TIMESTAMP ZIGZAG/SPRINTZ, BOOLEAN RLE.
  • Fix two cross-language format bugs found by the expanded matrix:
    • INT64 RLE run values were read little-endian in C++ but written
      big-endian by Java/IoTDB.
    • The SPRINTZ FIR predictor used a 128-bit intermediate in C++, diverging
      from Java's 32/64-bit wrapping multiply on large values.
  • Narrow the compatibility workflow trigger to the binary-format surface
    (main source, the spec, build files) so routine PRs don't pay the ~30 minute
    matrix; the coverage/self-check tests still run in the normal unit suite.
  • Report the per-run coverage/gap matrix in the CI job summaries.

Validation

  • Java generates 3260 fixtures; C++ reads all 3260 (0 skipped).
  • C++ generates 3168 fixtures; Java reads all 3168.
  • C++ full unit suite: 1421 passed, 0 failed.
  • Java encoding/RLE/SPRINTZ tests pass; spotless:check clean.

… scales

Close the Java/C++ compatibility gaps so every Java-writable
(type, encoding, compression) combination is readable by C++, and
expand the shared fixture matrix to four data-scale tiers with
page-size coverage.

- Add C++ FLOAT/DOUBLE RLE and GORILLA_V1 encoders/decoders.
- Wire DATE/TIMESTAMP into ZIGZAG/SPRINTZ and BOOLEAN into RLE.
- Fix INT64 RLE decoder endianness: Java stores run values big-endian.
- Fix SPRINTZ FIR predictor to match Java's 32/64-bit wrapping multiply.
- Replace the table-only Java/C++ tests with a spec-driven
  EncodingCompressionCompatibilityTest consumed by both sides from
  compat/compatibility-matrix.csv; cover tree + table models, four
  scales (10/1k/100k/1M rows), and page-boundary sizes.
- Narrow the compatibility workflow trigger to the binary-format
  surface and report the coverage/gap matrix in CI.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Gorilla V1 fails to propagate read and write errors, allowing truncated streams to produce fabricated values and allocation failures to silently truncate encoded output.

8 open issues
What changed in this PR

Expands Apache TsFile’s Java/C++ compatibility testing toward the shared, bidirectional coverage requested in #1057, while adding missing codecs and correcting format mismatches.

Changes:

  • Replaces table-only tests with spec-driven table and tree fixtures, capability checks, and multiple data scales.
  • Adds C++ floating-point RLE and Gorilla V1 support, extends type mappings, and fixes RLE byte order and SPRINTZ prediction.
  • Narrows CI triggers and publishes generation and validation summaries.
File Description
java/​tsfile/​src/​test/​java/​org/​apache/​tsfile/​compatibility/​TableModelEncodingCompressionCompatibilityTest.java Removes the previous Java table-only harness.
java/​tsfile/​src/​test/​java/​org/​apache/​tsfile/​compatibility/​EncodingCompressionCompatibilityTest.java Adds spec-driven Java fixture generation and validation.
cpp/​test/​reader/​table_view/​table_model_encoding_compression_compatibility_test.cc Removes the previous C++ table-only harness.
cpp/​test/​reader/​table_view/​encoding_compression_compatibility_test.cc Adds spec-driven C++ fixtures and capability checks.
cpp/​src/​encoding/​int64_rle_decoder.h Reads repeated INT64 values in big-endian order.
cpp/​src/​encoding/​gorilla_v1_encoder.h Adds FLOAT/DOUBLE Gorilla V1 encoding.
cpp/​src/​encoding/​gorilla_v1_decoder.h Adds FLOAT/DOUBLE Gorilla V1 decoding.
cpp/​src/​encoding/​float_rle_encoder.h Adds floating-point RLE encoding with overflow metadata.
cpp/​src/​encoding/​float_rle_decoder.h Decodes floating-point RLE values and overflow metadata.
cpp/​src/​encoding/​fire.h Matches Java’s wrapping SPRINTZ predictor arithmetic.
cpp/​src/​encoding/​encoder_factory.h Registers new codecs and supported type mappings.
cpp/​src/​encoding/​decoder_factory.h Registers matching decoders and type mappings.
compat/​README.md Documents the matrix contract and local execution.
.github/​workflows/​compatibility-test.yml Updates harness commands, codec options, triggers, and summaries.

Review effort: Balanced

Comment thread cpp/src/encoding/gorilla_v1_decoder.h Resolved
Comment thread cpp/src/encoding/gorilla_v1_encoder.h Resolved
Comment thread cpp/src/encoding/float_rle_encoder.h Resolved
…fers

DecoderFactory::free() only released the placement-new'ed object memory
without running the decoder's destructor, leaking the heap buffers held by
decoders such as Int32RleDecoder (and the FLOAT/DOUBLE RLE wrappers around
it). Move the destructor call into free(), mirroring EncoderFactory::free(),
and drop the now-redundant explicit ~Decoder() calls at the reader call
sites.
- Propagate bit-read and write errors in the Gorilla V1 encoder/decoder
  instead of fabricating values or silently truncating output on failure.
- Match Java Math.round exactly in java_round (bit-exact for large doubles)
  instead of floor(x + 0.5).
- Check decoder support for every cpp_read case in the C++ self-check.
- Report writer-only (not-mine) gaps in the coverage summary.
- Restore BOOLEAN/RLE null coverage in the shared matrix.
- Validate Java table fixtures inline to bound memory at 1M rows.
- Include the Java module POMs and the compatibility harness in the CI
  trigger.
(double)INT64_MAX rounds up to 2^63, so a naive static_cast on a value at
that boundary is out of range. Clamp first, matching the saturation the
previous floor(x+0.5) implementation performed via its r >= 2^63 guard.
The full type-by-encoding cartesian product runs at 10/1000/100000 rows;
at 1M rows it uses a per-type representative encoding set (PLAIN/TS_2DIFF/
RLE/GORILLA/DICTIONARY). Cross-language compatibility is already fully
covered by the smaller scales, and the 1M tier only stresses page/chunk/
index machinery at scale, so this keeps the generation and validation jobs
within the 30-minute CI budget (the previous full 1M cartesian timed out).
Restore the full type-by-encoding cartesian product at all four data
scales (including 1M rows) and instead shard the generation across parallel
CI jobs so each job stays within its timeout.

- generateFixtures/GenerateFixtures take a shardIndex/shardCount and only
  emit the cases whose index falls into that shard.
- validateFixtures/ValidateFixtures skip the manifest completeness check
  when sharded (each shard's manifest is a partial subset).
- The CI matrix runs one generate/validate job per shard, uploading and
  downloading per-shard artifacts.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The predictor change corrupts legacy C++ SPRINTZ decoding, sharded validation can accept incomplete fixture manifests, and floating-point RLE overflow formats lack test coverage.

2 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Test RLE floating-point overflow and raw-IEEE formats

cpp/​src/​encoding/​encoder_factory.h:110

The new FLOAT/DOUBLE RLE support is exercised only with runs and default profiles, whose values never overflow after scaling by 100. Consequently, neither the scaled-overflow nor raw-IEEE bitmap format in the new wrappers is tested, and there are no dedicated RLE floating-point codec tests. Add shared RLE fixtures using the existing ts2diff profile (large finite values, NaN and infinities), so both directions exercise these formats and their page resets.

8 resolved since last review

Review effort: Balanced

Comment thread cpp/src/encoding/fire.h Resolved
…l spec

The previous sharding relaxation skipped the missing-fixture check entirely
when shardCount > 1, so a manifest containing only one expected fixture could
pass. Now the validator computes the expected subset using the same
shardIndex % shardCount partition the generator uses, and checks the manifest
against that subset in both directions. CI passes shardIndex to the
validation jobs.
camel_detail::java_math_round used floor(value + 0.5), which diverges from
Java's Math.round(double) for large doubles (|value| >= 2^52). Replace it
with the same bit-exact translation already used by java_round in the
TS_2DIFF/RLE encoders, so every rounding site matches Java.
Add shared table/tree fixtures for scaled overflow, raw IEEE values and page transitions, with Java and C++ codec regression tests. Clear stale overflow bitmaps when resetting the Java floating-point decoder.
@ColinLeeo
ColinLeeo merged commit d0a0bb4 into apache:develop Nov 5, 2026
58 checks passed
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.

[Feature][Test] Expand the Java–C++ cross-language compatibility matrix to full coverage

2 participants