Skip to content

[BUG] Fix ORC chunked writer root row statistics - #23118

Merged
rapids-bot[bot] merged 4 commits into
NVIDIA:release/26.08from
wjxiz1992:codex/15186-orc-chunked-row-stats
Jul 23, 2026
Merged

[BUG] Fix ORC chunked writer root row statistics#23118
rapids-bot[bot] merged 4 commits into
NVIDIA:release/26.08from
wjxiz1992:codex/15186-orc-chunked-row-stats

Conversation

@wjxiz1992

Copy link
Copy Markdown
Contributor

Description

Fix ORC root column statistics when an orc_chunked_writer receives multiple non-empty tables.

persisted_statistics::persist replaced num_rows on every write, so the root numberOfValues stored in the footer reflected only the final table. Accumulate the row count across writes instead, while retaining the existing early return for an empty current table.

This caused Spark ORC aggregate pushdown to return the number of output files instead of the row count for COUNT on a top-level struct written by the RAPIDS Accelerator. Related issue: NVIDIA/cudf-spark#15186.

Validation:

  • Before the fix, OrcChunkedWriterTest.RootStatisticsAccumulateRows failed with root number_of_values = 1, expected 6.
  • After the fix, the targeted test passed.
  • Full ORC_TEST: 197 tests from 36 test suites, 197 passed, 4 disabled.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@copy-pr-bot

copy-pr-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the libcudf Affects libcudf (C++/CUDA) code. label Jul 6, 2026
@wjxiz1992 wjxiz1992 added bug Something isn't working non-breaking Non-breaking change labels Jul 6, 2026
@wjxiz1992
wjxiz1992 marked this pull request as ready for review July 7, 2026 08:04
Copilot AI review requested due to automatic review settings July 7, 2026 08:04
@wjxiz1992
wjxiz1992 requested a review from a team as a code owner July 7, 2026 08:04
@wjxiz1992
wjxiz1992 requested review from bdice and simoneves July 7, 2026 08:04
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Updates ORC persisted statistics to accumulate row counts across chunked writes, widens row-count types to uint64_t, and adds tests for combined and oversized file-level statistics.

Changes

ORC chunked statistics row accumulation

Layer / File(s) Summary
Fix num_rows accumulation and validation tests
cpp/src/io/orc/writer_impl.hpp, cpp/src/io/orc/writer_impl.cu, cpp/tests/io/orc_test.cpp
persisted_statistics::persist accepts and accumulates uint64_t row counts, handles zero-row inputs, and is validated for chunked totals and oversized ORC payloads.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: simoneves, bdice, pointkernel

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main fix to ORC chunked writer root row statistics.
Description check ✅ Passed The description is directly related to the changes and explains the bug, fix, and validation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/src/io/orc/writer_impl.cu`:
- Line 398: The row-count accumulator in persisted_statistics is still using an
int, so chunked writes in writer_impl.cu can overflow across multiple write()
calls and produce an incorrect footer row count. Update
persisted_statistics::num_rows and the footer serialization path to use a 64-bit
type, and make sure the num_rows += num_table_rows accumulation in the write
flow and any related getter/setter or serialization code in writer_impl.cu
consistently use the widened type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1ee9c44a-788c-4a41-a642-1d465e484c69

📥 Commits

Reviewing files that changed from the base of the PR and between ba255bb and 860f0aa.

📒 Files selected for processing (2)
  • cpp/src/io/orc/writer_impl.cu
  • cpp/tests/io/orc_test.cpp

Comment thread cpp/src/io/orc/writer_impl.cu

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes ORC root column statistics for chunked ORC writes so the file-level root numberOfValues reflects the total number of rows across multiple non-empty orc_chunked_writer::write() calls (rather than only the final table), which affects downstream aggregate pushdown behavior.

Changes:

  • Accumulate persisted_statistics::num_rows across chunked writes instead of overwriting it per write.
  • Add a regression test validating root file statistics row-count accumulation for multiple writes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
cpp/src/io/orc/writer_impl.cu Accumulates persisted root row count across multiple write() calls to produce correct root footer statistics.
cpp/tests/io/orc_test.cpp Adds a regression test asserting root number_of_values equals the sum of rows written across multiple chunk writes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cpp/src/io/orc/writer_impl.cu Outdated
@GregoryKimball GregoryKimball moved this to Burndown in libcudf Jul 13, 2026
@wjxiz1992

Copy link
Copy Markdown
Contributor Author

/ok to test 8089674

@wjxiz1992

Copy link
Copy Markdown
Contributor Author

/ok to test 9887cf3

@wjxiz1992
wjxiz1992 requested a review from res-life July 16, 2026 06:57
}

void persist(int num_table_rows,
void persist(uint64_t num_table_rows,

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.

uint64_t is now used directly by this header, but <cstdint> is only available through a transitive include. Please add its declaring header to the standard-library include group, as required by the project's include-what-you-use rule:

+#include <cstdint>
 #include <memory>

Comment thread cpp/src/io/orc/writer_impl.cu Outdated
Comment on lines +396 to +399
stats_dtypes = std::move(intermediate_stats.stats_dtypes);
col_types = std::move(intermediate_stats.col_types);
num_rows = num_table_rows;
if (num_rows == 0) { return; }
num_rows += num_table_rows;
if (num_table_rows == 0) { return; }

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.

An empty chunk has an empty intermediate_stats.stats_dtypes, so assigning it before this early return discards the descriptors from prior non-empty chunks. close() later indexes the empty vector while merging the already-persisted stripe statistics. Please preserve the last non-empty descriptors by moving that assignment after the zero-row check, while still updating col_types for an all-empty file:

Suggested change
stats_dtypes = std::move(intermediate_stats.stats_dtypes);
col_types = std::move(intermediate_stats.col_types);
num_rows = num_table_rows;
if (num_rows == 0) { return; }
num_rows += num_table_rows;
if (num_table_rows == 0) { return; }
col_types = std::move(intermediate_stats.col_types);
num_rows += num_table_rows;
if (num_table_rows == 0) { return; }
stats_dtypes = std::move(intermediate_stats.stats_dtypes);

Please also add a regression case that writes a non-empty table followed by an empty table, closes the writer, and parses the resulting statistics.

Comment thread cpp/tests/io/orc_test.cpp
auto const stats = cudf::io::read_parsed_orc_statistics(cudf::io::source_info{filepath});
ASSERT_FALSE(stats.file_stats.empty());
ASSERT_TRUE(stats.file_stats.front().number_of_values.has_value());
EXPECT_EQ(*stats.file_stats.front().number_of_values, 6);

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.

This six-row assertion detects replacement with the final chunk's count, but it cannot detect regression of the widened accumulator to 32 bits. The existing SizeTypeRowsOverflow test already writes 2,500,000,000 rows; please extend that test after its metadata assertions to verify the root statistic produced by the accumulator:

+  auto const stats =
+    cudf::io::read_parsed_orc_statistics(cudf::io::source_info{cudf::host_span<std::byte const>{
+      reinterpret_cast<std::byte const*>(out_buffer.data()), out_buffer.size()}});
+  ASSERT_FALSE(stats.file_stats.empty());
+  ASSERT_TRUE(stats.file_stats.front().number_of_values.has_value());
+  EXPECT_EQ(*stats.file_stats.front().number_of_values, static_cast<uint64_t>(total_rows));

@wjxiz1992

Copy link
Copy Markdown
Contributor Author

/ok to test 3e8418f

@res-life res-life 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.

LGTM

@vuule vuule 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.

one non-blocking comment, good otherwise.

}

void persisted_statistics::persist(int num_table_rows,
void persisted_statistics::persist(uint64_t num_table_rows,

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.

This change was not necessary because we pass a value previously stored in size_type.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Any hardening against ~2B row limits is fine with me.

@vuule

vuule commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

/ok to test 4d5d9b0

Signed-off-by: Allen Xu <allxu@nvidia.com>
Signed-off-by: Allen Xu <allxu@nvidia.com>
Signed-off-by: Allen Xu <allxu@nvidia.com>
Signed-off-by: Allen Xu <allxu@nvidia.com>
@mhaseeb123
mhaseeb123 force-pushed the codex/15186-orc-chunked-row-stats branch from 4d5d9b0 to fa88fb5 Compare July 22, 2026 21:13
@mhaseeb123
mhaseeb123 requested review from a team as code owners July 22, 2026 21:13
@github-actions github-actions Bot added CMake CMake build issue Java Affects Java cuDF API. labels Jul 22, 2026
@mhaseeb123
mhaseeb123 changed the base branch from main to release/26.08 July 22, 2026 21:13
@mhaseeb123
mhaseeb123 removed request for a team July 22, 2026 21:14
@mhaseeb123 mhaseeb123 removed their assignment Jul 22, 2026
@mhaseeb123 mhaseeb123 added 4 - Needs Review Waiting for reviewer to review or respond and removed CMake CMake build issue Java Affects Java cuDF API. labels Jul 22, 2026
@mhaseeb123

Copy link
Copy Markdown
Contributor

/ok to test fa88fb5

@mhaseeb123

Copy link
Copy Markdown
Contributor

/merge

@mhaseeb123 mhaseeb123 added 5 - Ready to Merge Testing and reviews complete, ready to merge and removed 4 - Needs Review Waiting for reviewer to review or respond labels Jul 22, 2026
@rapids-bot
rapids-bot Bot merged commit f03e9cd into NVIDIA:release/26.08 Jul 23, 2026
267 of 270 checks passed
@GregoryKimball GregoryKimball moved this from Burndown to Landed in libcudf Jul 23, 2026
@GregoryKimball GregoryKimball removed this from libcudf Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5 - Ready to Merge Testing and reviews complete, ready to merge bug Something isn't working libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

Status: Landed

Development

Successfully merging this pull request may close these issues.

8 participants