Skip to content

Add hybrid scan multifile reader basics - #22616

Merged
rapids-bot[bot] merged 19 commits into
NVIDIA:mainfrom
mhaseeb123:fea/hybrid-scan-multifile-base
Jun 2, 2026
Merged

Add hybrid scan multifile reader basics#22616
rapids-bot[bot] merged 19 commits into
NVIDIA:mainfrom
mhaseeb123:fea/hybrid-scan-multifile-base

Conversation

@mhaseeb123

@mhaseeb123 mhaseeb123 commented May 21, 2026

Copy link
Copy Markdown
Contributor

Description

Contributes to #22583

This PR adds barebones basic APIs for the hybrid_scan_multifile reader.

Note to reviewers: Please use the "Hide whitespace" feature when reviewing this PR as it will remove a lot of noise from simple indentation

Checklist

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

@mhaseeb123
mhaseeb123 requested review from a team as code owners May 21, 2026 01:16
@mhaseeb123
mhaseeb123 requested review from PointKernel and lamarrr May 21, 2026 01:16
@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. CMake CMake build issue labels May 21, 2026
@mhaseeb123
mhaseeb123 marked this pull request as draft May 21, 2026 01:16
@copy-pr-bot

copy-pr-bot Bot commented May 21, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

*
* @note Detailed usage documentation will be added once all APIs are in place.
*/
class hybrid_scan_multifile {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am going to eventually remove this file, move this class to hybrid_scan.hpp and make the existing single-file reader (hybrid_scan_reader) a subclass of this one. Only keeping this separate for now to avoid noise.

@coderabbitai

coderabbitai Bot commented May 21, 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

Refactors hybrid-scan internals to operate on multiple Parquet sources, adds an exported hybrid_scan_multifile wrapper that delegates to the refactored impl, adapts single-source adapter to single-element multi-source containers, and adds unit tests plus CMake/test wiring.

Changes

Multi-source Parquet Hybrid Scan Implementation

Layer / File(s) Summary
Public multifile API and implementation
cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp, cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp
Adds exported hybrid_scan_multifile class with constructors from per-source footers or pre-populated metadatas, per-source metadata/page-index accessors, page-index setup, row-group enumeration, total-row counting, and reset.
Core multi-source metadata & page-index plumbing
cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp, cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp, cpp/src/io/parquet/experimental/hybrid_scan_impl.hpp, cpp/src/io/parquet/experimental/hybrid_scan_impl.cpp
Refactors aggregate metadata and hybrid-scan internals to accept nested spans or spans of FileMetaData, return per-source collections, apply schema normalization across sources, and produce per-source row-group index vectors.
Single-source adapter and build wiring
cpp/src/io/parquet/experimental/hybrid_scan.cpp, cpp/include/cudf/io/experimental/hybrid_scan.hpp, cpp/CMakeLists.txt
Adapts existing single-source hybrid_scan_reader to wrap inputs/results as single-element per-source containers; updates forward-declaration form and total_rows_in_row_groups return type; adds hybrid_scan_multifile.cpp to the cudf library sources.
Tests and test build integration
cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp, cpp/tests/CMakeLists.txt
Adds tests covering metadata/page-index installation under filters and empty-source handling; updates HYBRID_SCAN_TEST CMake target to compile the new test.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Suggested reviewers

  • lamarrr
  • bdice
  • mroeschke
  • ttnghia
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.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
Title check ✅ Passed The title directly and clearly summarizes the main change: adding basic APIs for a new hybrid_scan_multifile reader class.
Description check ✅ Passed The description is directly related to the changeset, explaining that it adds barebones basic APIs for the hybrid_scan_multifile reader and references a related issue.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

🧹 Nitpick comments (2)
cpp/src/io/parquet/experimental/hybrid_scan.cpp (1)

32-40: ⚡ Quick win

Instrument touched delegating public methods with CUDF_FUNC_RANGE().

The updated wrapper methods delegate directly to _impl but currently skip NVTX range tagging.

🛠️ Suggested patch
 [[nodiscard]] text::byte_range_info hybrid_scan_reader::page_index_byte_range() const
 {
+  CUDF_FUNC_RANGE();
   return _impl->page_index_byte_range().front();
 }
 
 [[nodiscard]] FileMetaData hybrid_scan_reader::parquet_metadata() const
 {
+  CUDF_FUNC_RANGE();
   return _impl->parquet_metadata().front();
 }
@@
 std::vector<cudf::size_type> hybrid_scan_reader::all_row_groups(
   parquet_reader_options const& options) const
 {
+  CUDF_FUNC_RANGE();
   CUDF_EXPECTS(options.get_row_groups().size() <= 1,
                "Encountered invalid size of row group indices in parquet reader options");

As per coding guidelines cpp/src/**/*.{cu,cpp}: "Add CUDF_FUNC_RANGE() in public functions before delegating to detail:: functions".

Also applies to: 50-60

🤖 Prompt for 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.

In `@cpp/src/io/parquet/experimental/hybrid_scan.cpp` around lines 32 - 40, The
public wrapper methods hybrid_scan_reader::page_index_byte_range() and
hybrid_scan_reader::parquet_metadata() (and other public wrappers around lines
50-60) need NVTX/CUDF range instrumentation: add CUDF_FUNC_RANGE() as the first
statement in each of these public functions before delegating to _impl (e.g.,
before calling _impl->page_index_byte_range().front() and
_impl->parquet_metadata().front()) so the calls are properly range-tagged per
the cpp/src/**/*.{cu,cpp} guideline.
cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp (1)

28-58: ⚡ Quick win

Add CUDF_FUNC_RANGE() to the delegating public methods.

Several public APIs here delegate directly to _impl but are missing NVTX range instrumentation (e.g., Lines 28-36, 45-56, 58).

🛠️ Suggested patch
 std::vector<FileMetaData> hybrid_scan_multifile::parquet_metadata() const
 {
+  CUDF_FUNC_RANGE();
   return _impl->parquet_metadata();
 }
 
 std::vector<text::byte_range_info> hybrid_scan_multifile::page_index_byte_range() const
 {
+  CUDF_FUNC_RANGE();
   return _impl->page_index_byte_range();
 }
@@
 std::vector<std::vector<size_type>> hybrid_scan_multifile::all_row_groups(
   parquet_reader_options const& options) const
 {
+  CUDF_FUNC_RANGE();
   return _impl->all_row_groups(options);
 }
 
 size_type hybrid_scan_multifile::total_rows_in_row_groups(
   cudf::host_span<std::vector<size_type> const> row_group_indices) const
 {
+  CUDF_FUNC_RANGE();
   if (row_group_indices.empty()) { return 0; }
   return _impl->total_rows_in_row_groups(row_group_indices);
 }
 
-void hybrid_scan_multifile::reset_column_selection() const { _impl->reset_column_selection(); }
+void hybrid_scan_multifile::reset_column_selection() const
+{
+  CUDF_FUNC_RANGE();
+  _impl->reset_column_selection();
+}

As per coding guidelines cpp/src/**/*.{cu,cpp}: "Add CUDF_FUNC_RANGE() in public functions before delegating to detail:: functions".

🤖 Prompt for 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.

In `@cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp` around lines 28 -
58, Add NVTX range instrumentation by inserting CUDF_FUNC_RANGE() at the start
of each public delegating method that currently lacks it: parquet_metadata(),
page_index_byte_range(), all_row_groups(parquet_reader_options const&),
total_rows_in_row_groups(cudf::host_span<std::vector<size_type> const>) and
reset_column_selection(). Place CUDF_FUNC_RANGE() before delegating to _impl
(for total_rows_in_row_groups, ensure the range is present when the function
proceeds to call _impl — keep the early empty check but add CUDF_FUNC_RANGE()
before the _impl call). This ensures all public APIs wrap their impl delegation
with NVTX ranges.
🤖 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/parquet/experimental/hybrid_scan_helpers.cpp`:
- Around line 166-199: In aggregate_reader_metadata::setup_page_index, when
iterating page_index_bytes and hitting an empty pgidx_bytes currently skipped
silently, emit the documented one-time warning instead of just returning; add a
local bool (e.g., warned_empty_page_index) before the loop, and on first empty
pgidx_bytes log a warning (including the source identifier or index if
available) and set the flag so subsequent empties are not logged, then continue;
ensure you still call file_metadata.setup_page_index(...) for non-empty spans
and keep references to page_index_bytes and per_file_metadata as before.

---

Nitpick comments:
In `@cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp`:
- Around line 28-58: Add NVTX range instrumentation by inserting
CUDF_FUNC_RANGE() at the start of each public delegating method that currently
lacks it: parquet_metadata(), page_index_byte_range(),
all_row_groups(parquet_reader_options const&),
total_rows_in_row_groups(cudf::host_span<std::vector<size_type> const>) and
reset_column_selection(). Place CUDF_FUNC_RANGE() before delegating to _impl
(for total_rows_in_row_groups, ensure the range is present when the function
proceeds to call _impl — keep the early empty check but add CUDF_FUNC_RANGE()
before the _impl call). This ensures all public APIs wrap their impl delegation
with NVTX ranges.

In `@cpp/src/io/parquet/experimental/hybrid_scan.cpp`:
- Around line 32-40: The public wrapper methods
hybrid_scan_reader::page_index_byte_range() and
hybrid_scan_reader::parquet_metadata() (and other public wrappers around lines
50-60) need NVTX/CUDF range instrumentation: add CUDF_FUNC_RANGE() as the first
statement in each of these public functions before delegating to _impl (e.g.,
before calling _impl->page_index_byte_range().front() and
_impl->parquet_metadata().front()) so the calls are properly range-tagged per
the cpp/src/**/*.{cu,cpp} guideline.
🪄 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: fb3c5e4e-9d78-4b6b-b108-6823a3a1a8fe

📥 Commits

Reviewing files that changed from the base of the PR and between 0560e41 and 121bf9d.

📒 Files selected for processing (8)
  • cpp/CMakeLists.txt
  • cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp
  • cpp/src/io/parquet/experimental/hybrid_scan.cpp
  • cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp
  • cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp
  • cpp/src/io/parquet/experimental/hybrid_scan_impl.cpp
  • cpp/src/io/parquet/experimental/hybrid_scan_impl.hpp
  • cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp

Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp Outdated
@mhaseeb123 mhaseeb123 added 2 - In Progress Currently a work in progress cuIO cuIO issue Spark Functionality that helps Spark RAPIDS feature request New feature or request non-breaking Non-breaking change and removed Spark Functionality that helps Spark RAPIDS labels May 21, 2026
@mhaseeb123
mhaseeb123 marked this pull request as ready for review May 21, 2026 19:50

@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: 2

🤖 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/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp`:
- Around line 8-9: Add the project gtest wrapper header to the test translation
unit by inserting `#include` <cudf_test/cudf_gtest.hpp> alongside the existing
`#include` <cudf_test/base_fixture.hpp> in hybrid_scan_multifile_filters_test.cpp
so the file uses the project wrapper instead of relying on raw gtest headers;
ensure the new include appears before any test definitions or fixtures (e.g.,
references to BaseFixture/Test macros) to follow the project's test include
convention.
- Around line 23-76: The helpers are defined inside an anonymous namespace which
violates the test-file namespace rule; move the struct multifile_inputs and the
functions build_multifile_inputs and create_empty_parquet_with_stats out of the
anonymous namespace into the global namespace (remove "namespace { ... }"
wrapper) so they live at global scope and keep their signatures and behavior
unchanged; ensure any forward-uses in this file still compile after the move and
remove the closing comment that references the anonymous namespace.
🪄 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: 0179ac61-2242-47c5-8f70-421c96a28264

📥 Commits

Reviewing files that changed from the base of the PR and between 121bf9d and ec0b59e.

📒 Files selected for processing (3)
  • cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp
  • cpp/tests/CMakeLists.txt
  • cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp

Comment on lines +8 to +9
#include <cudf_test/base_fixture.hpp>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include cudf_gtest.hpp explicitly in this test file.

Line 8 currently includes only base_fixture.hpp. Please add the direct gtest wrapper include in this TU to match project test conventions.

Suggested patch
 `#include` <cudf_test/base_fixture.hpp>
+#include <cudf_test/cudf_gtest.hpp>

As per coding guidelines Use #include <cudf_test/cudf_gtest.hpp> in test files, never raw gtest/gtest.h.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include <cudf_test/base_fixture.hpp>
`#include` <cudf_test/base_fixture.hpp>
`#include` <cudf_test/cudf_gtest.hpp>
🤖 Prompt for 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.

In `@cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp` around
lines 8 - 9, Add the project gtest wrapper header to the test translation unit
by inserting `#include` <cudf_test/cudf_gtest.hpp> alongside the existing `#include`
<cudf_test/base_fixture.hpp> in hybrid_scan_multifile_filters_test.cpp so the
file uses the project wrapper instead of relying on raw gtest headers; ensure
the new include appears before any test definitions or fixtures (e.g.,
references to BaseFixture/Test macros) to follow the project's test include
convention.

Comment on lines +23 to +76
namespace {

/**
* @brief Struct to hold multifile datasources, and footer buffers along with their byte spans
*/
struct multifile_inputs {
std::vector<std::unique_ptr<cudf::io::datasource>> datasources;
std::vector<std::unique_ptr<cudf::io::datasource::buffer>> footer_buffers;
std::vector<cudf::host_span<uint8_t const>> footer_byte_spans;
};

template <typename Buffers>
multifile_inputs build_multifile_inputs(Buffers const& file_buffers)
{
multifile_inputs out;
out.datasources.reserve(file_buffers.size());
out.footer_buffers.reserve(file_buffers.size());
out.footer_byte_spans.reserve(file_buffers.size());
for (auto const& buf : file_buffers) {
out.datasources.emplace_back(cudf::io::datasource::create(cudf::host_span<std::byte const>(
reinterpret_cast<std::byte const*>(buf.data()), buf.size())));
out.footer_buffers.emplace_back(
cudf::io::parquet::fetch_footer_to_host(*out.datasources.back()));
out.footer_byte_spans.emplace_back(*out.footer_buffers.back());
}
return out;
}

/**
* @brief Creates a parquet buffer with zero-rows and same schema as table from
* `create_parquet_with_stats`
*/
template <typename T>
std::vector<char> create_empty_parquet_with_stats()
{
auto const non_empty = std::get<0>(create_parquet_with_stats<T, 1>());
auto const empty = cudf::empty_like(non_empty->view());

cudf::io::table_input_metadata output_metadata(empty->view());
output_metadata.column_metadata[0].set_name("col0");
output_metadata.column_metadata[1].set_name("col1");
output_metadata.column_metadata[2].set_name("col2");

std::vector<char> buffer;
auto out_opts =
cudf::io::parquet_writer_options::builder(cudf::io::sink_info{&buffer}, empty->view())
.metadata(std::move(output_metadata))
.stats_level(cudf::io::statistics_freq::STATISTICS_COLUMN)
.build();
cudf::io::write_parquet(out_opts);
return buffer;
}

} // namespace

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid anonymous namespace in this test source.

Line 23 introduces an anonymous namespace for helpers. Move these declarations to the global namespace to align with the test-file namespace rule.

Suggested patch
-namespace {
-
 /**
  * `@brief` Struct to hold multifile datasources, and footer buffers along with their byte spans
  */
 struct multifile_inputs {
@@
 template <typename T>
 std::vector<char> create_empty_parquet_with_stats()
@@
   return buffer;
 }
-
-}  // namespace

As per coding guidelines Test code must be in the global namespace, not in custom namespaces.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
namespace {
/**
* @brief Struct to hold multifile datasources, and footer buffers along with their byte spans
*/
struct multifile_inputs {
std::vector<std::unique_ptr<cudf::io::datasource>> datasources;
std::vector<std::unique_ptr<cudf::io::datasource::buffer>> footer_buffers;
std::vector<cudf::host_span<uint8_t const>> footer_byte_spans;
};
template <typename Buffers>
multifile_inputs build_multifile_inputs(Buffers const& file_buffers)
{
multifile_inputs out;
out.datasources.reserve(file_buffers.size());
out.footer_buffers.reserve(file_buffers.size());
out.footer_byte_spans.reserve(file_buffers.size());
for (auto const& buf : file_buffers) {
out.datasources.emplace_back(cudf::io::datasource::create(cudf::host_span<std::byte const>(
reinterpret_cast<std::byte const*>(buf.data()), buf.size())));
out.footer_buffers.emplace_back(
cudf::io::parquet::fetch_footer_to_host(*out.datasources.back()));
out.footer_byte_spans.emplace_back(*out.footer_buffers.back());
}
return out;
}
/**
* @brief Creates a parquet buffer with zero-rows and same schema as table from
* `create_parquet_with_stats`
*/
template <typename T>
std::vector<char> create_empty_parquet_with_stats()
{
auto const non_empty = std::get<0>(create_parquet_with_stats<T, 1>());
auto const empty = cudf::empty_like(non_empty->view());
cudf::io::table_input_metadata output_metadata(empty->view());
output_metadata.column_metadata[0].set_name("col0");
output_metadata.column_metadata[1].set_name("col1");
output_metadata.column_metadata[2].set_name("col2");
std::vector<char> buffer;
auto out_opts =
cudf::io::parquet_writer_options::builder(cudf::io::sink_info{&buffer}, empty->view())
.metadata(std::move(output_metadata))
.stats_level(cudf::io::statistics_freq::STATISTICS_COLUMN)
.build();
cudf::io::write_parquet(out_opts);
return buffer;
}
} // namespace
/**
* `@brief` Struct to hold multifile datasources, and footer buffers along with their byte spans
*/
struct multifile_inputs {
std::vector<std::unique_ptr<cudf::io::datasource>> datasources;
std::vector<std::unique_ptr<cudf::io::datasource::buffer>> footer_buffers;
std::vector<cudf::host_span<uint8_t const>> footer_byte_spans;
};
template <typename Buffers>
multifile_inputs build_multifile_inputs(Buffers const& file_buffers)
{
multifile_inputs out;
out.datasources.reserve(file_buffers.size());
out.footer_buffers.reserve(file_buffers.size());
out.footer_byte_spans.reserve(file_buffers.size());
for (auto const& buf : file_buffers) {
out.datasources.emplace_back(cudf::io::datasource::create(cudf::host_span<std::byte const>(
reinterpret_cast<std::byte const*>(buf.data()), buf.size())));
out.footer_buffers.emplace_back(
cudf::io::parquet::fetch_footer_to_host(*out.datasources.back()));
out.footer_byte_spans.emplace_back(*out.footer_buffers.back());
}
return out;
}
/**
* `@brief` Creates a parquet buffer with zero-rows and same schema as table from
* `create_parquet_with_stats`
*/
template <typename T>
std::vector<char> create_empty_parquet_with_stats()
{
auto const non_empty = std::get<0>(create_parquet_with_stats<T, 1>());
auto const empty = cudf::empty_like(non_empty->view());
cudf::io::table_input_metadata output_metadata(empty->view());
output_metadata.column_metadata[0].set_name("col0");
output_metadata.column_metadata[1].set_name("col1");
output_metadata.column_metadata[2].set_name("col2");
std::vector<char> buffer;
auto out_opts =
cudf::io::parquet_writer_options::builder(cudf::io::sink_info{&buffer}, empty->view())
.metadata(std::move(output_metadata))
.stats_level(cudf::io::statistics_freq::STATISTICS_COLUMN)
.build();
cudf::io::write_parquet(out_opts);
return buffer;
}
🤖 Prompt for 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.

In `@cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp` around
lines 23 - 76, The helpers are defined inside an anonymous namespace which
violates the test-file namespace rule; move the struct multifile_inputs and the
functions build_multifile_inputs and create_empty_parquet_with_stats out of the
anonymous namespace into the global namespace (remove "namespace { ... }"
wrapper) so they live at global scope and keep their signatures and behavior
unchanged; ensure any forward-uses in this file still compile after the move and
remove the closing comment that references the anonymous namespace.

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

Mainly style nits. One thing I noticed is that the API behavior has changed quite a bit from handling a single file/source to supporting multiple ones, while the API names remain the same. We probably want to either update the naming or introduce separate APIs for clarity instead of changing the existing behavior implicitly.

Comment thread cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp Outdated
Comment thread cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp Outdated
* @param footer_bytes Host span of Parquet file footer byte spans, one per source
* @param options Parquet reader options
*/
explicit hybrid_scan_multifile(cudf::host_span<cudf::host_span<uint8_t const> const> footer_bytes,

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.

@mhaseeb123 can you please check #22560 to see if cudf::host_span is the best fit?

@mhaseeb123 mhaseeb123 May 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Happy to use std::span here if it can be implicitly converted to host_span to pass on to the existing impl class. If not, I would lean towards keep using host_spans until hybrid_scan_multifile is complete (#22583) and then replace all occurrences across hybrid_scan** at once.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Update: We also gotta make sure that cudf::io::datasource::buffer is also implicitly convertible to std::span

Comment thread cpp/src/io/parquet/experimental/hybrid_scan.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp Outdated
Comment thread cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_multifile.cpp Outdated
Comment thread cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp Outdated
@mhaseeb123

mhaseeb123 commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

We probably want to either update the naming or introduce separate APIs for clarity instead of changing the existing behavior implicitly.

These APIs are in a separate new class (single source reader will become its subclass eventually) so same (or pluralized) API names kinda work here as context can be inferred from the reader's type.

mhaseeb123 and others added 2 commits May 21, 2026 13:53
Co-authored-by: Yunsong Wang <12716979+PointKernel@users.noreply.github.com>
Co-authored-by: Yunsong Wang <12716979+PointKernel@users.noreply.github.com>
@mhaseeb123 mhaseeb123 added 3 - Ready for Review Ready for review by team 4 - Needs Review Waiting for reviewer to review or respond and removed 2 - In Progress Currently a work in progress 3 - Ready for Review Ready for review by team labels May 28, 2026
CUDF_EXPECTS(row_group_indices.size() == per_file_metadata.size(),
"Encountered unexpected number of input row group indices",
std::invalid_argument);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Literally no logical difference here, just using std::accumulate instead of for_each's and changed return type to size_t to allow more than 2B rows

@GregoryKimball
GregoryKimball requested a review from qbacpey May 29, 2026 19:54
Comment thread cpp/include/cudf/io/experimental/hybrid_scan.hpp
Comment thread cpp/tests/io/experimental/hybrid_scan_multifile_filters_test.cpp
Comment thread cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp
Comment thread cpp/src/io/parquet/experimental/hybrid_scan.cpp
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp Outdated
Comment thread cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp Outdated
@mhaseeb123
mhaseeb123 requested a review from lamarrr May 29, 2026 21:07

@lamarrr lamarrr 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 LGTM!

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

Approving CMake

@mhaseeb123

Copy link
Copy Markdown
Contributor Author

/merge

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 CMake CMake build issue cuIO cuIO issue feature request New feature or request libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants