Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .github/workflows/wheels-build-stage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,31 +105,15 @@ jobs:
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
with:
log-file: ${{ env.RAPIDS_ARTIFACTS_DIR }}/sccache.log
- name: Restore Cython cache
id: cython-cache-restore
if: inputs.stage == 'python'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ github.workspace }}/.cache/cython
key: cython-v1-${{ runner.os }}-${{ runner.arch }}-cuda${{ matrix.CUDA_VER }}-py${{ matrix.PY_VER }}-${{ hashFiles('dependencies.yaml', 'python/**/*.pyx', 'python/**/*.pxd', 'python/**/CMakeLists.txt', 'python/**/pyproject.toml') }}
restore-keys: |
cython-v1-${{ runner.os }}-${{ runner.arch }}-cuda${{ matrix.CUDA_VER }}-py${{ matrix.PY_VER }}-
- name: Build staged wheels
id: build-wheels
run: |
ulimit -n "$(ulimit -Hn)"
source "${INPUTS_SCRIPT}"
env:
CYTHON_CACHE_DIR: ${{ github.workspace }}/.cache/cython
GH_TOKEN: ${{ github.token }}
INPUTS_SCRIPT: ${{ inputs.script }}
shell: bash -leo pipefail {0}
- name: Save Cython cache
if: inputs.stage == 'python' && steps.cython-cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ github.workspace }}/.cache/cython
key: ${{ steps.cython-cache-restore.outputs.cache-primary-key }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: inputs.stage == 'cpp'
with:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ repos:
hooks:
- id: mypy
additional_dependencies: [
"polars>=1.35,<1.43",
"polars>=1.35,<1.45",
"numpy>=1.26",
"pyarrow-stubs>=19.0",
"pyarrow>=19.0.0,<24.0.0", # https://github.com/NVIDIA/cudf/issues/22229
Expand Down
2 changes: 1 addition & 1 deletion conda/environments/all_cuda-129_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies:
- packaging
- pandas>=3.0.0,<3.1.0
- pandoc
- polars>=1.35,<1.43
- polars>=1.35,<1.45
- pre-commit
- psutil
- pyarrow>=19.0.0
Expand Down
2 changes: 1 addition & 1 deletion conda/environments/all_cuda-129_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies:
- packaging
- pandas>=3.0.0,<3.1.0
- pandoc
- polars>=1.35,<1.43
- polars>=1.35,<1.45
- pre-commit
- psutil
- pyarrow>=19.0.0
Expand Down
2 changes: 1 addition & 1 deletion conda/environments/all_cuda-133_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies:
- packaging
- pandas>=3.0.0,<3.1.0
- pandoc
- polars>=1.35,<1.43
- polars>=1.35,<1.45
- pre-commit
- psutil
- pyarrow>=19.0.0
Expand Down
2 changes: 1 addition & 1 deletion conda/environments/all_cuda-133_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ dependencies:
- packaging
- pandas>=3.0.0,<3.1.0
- pandoc
- polars>=1.35,<1.43
- polars>=1.35,<1.45
- pre-commit
- psutil
- pyarrow>=19.0.0
Expand Down
2 changes: 1 addition & 1 deletion conda/recipes/cudf-polars/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ requirements:
- rapidsmpf =${{ minor_version }}
- kvikio =${{ minor_version }}
- cudf-streaming =${{ version }}
- polars>=1.35,<1.43
- polars>=1.35,<1.45
- packaging
- ${{ pin_compatible("cuda-version", upper_bound="x", lower_bound="x") }}
- if: cuda_major == "12"
Expand Down
15 changes: 15 additions & 0 deletions cpp/include/cudf/io/experimental/hybrid_scan_multifile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class hybrid_scan_multifile {
/**
* @brief Constructor for the multi-file experimental Parquet reader
*
* @throws std::invalid_argument if no sources are provided
*
* @param footer_bytes Host span of Parquet file footer byte spans, one per source
* @param options Parquet reader options
*/
Expand All @@ -70,12 +72,25 @@ class hybrid_scan_multifile {
/**
* @brief Constructor for the multi-file experimental Parquet reader
*
* @throws std::invalid_argument if no sources are provided
*
* @param parquet_metadata Host span of pre-populated Parquet file metadata, one per source
* @param options Parquet reader options
*/
explicit hybrid_scan_multifile(cudf::host_span<FileMetaData const> parquet_metadata,
parquet_reader_options const& options);

/**
* @brief Constructor that takes ownership of pre-populated Parquet file metadata
*
* @throws std::invalid_argument if no sources are provided
*
* @param parquet_metadata Pre-populated Parquet file metadata, one per source
* @param options Parquet reader options
*/
explicit hybrid_scan_multifile(std::vector<FileMetaData>&& parquet_metadata,
parquet_reader_options const& options);

/**
* @brief Destructor for the multi-file experimental Parquet reader
*/
Expand Down
30 changes: 16 additions & 14 deletions cpp/include/cudf/utilities/span.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,26 +107,28 @@ struct host_span {

/// Constructor from container
/// @param in The container to construct the span from
template <typename C,
// Only supported containers of types convertible to T
std::enable_if_t<is_host_span_supported_container<C>::value &&
std::is_convertible_v<
std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
std::declval<C&>().data()))> (*)[],
T (*)[]>>* = nullptr> // NOLINT
template <
typename C,
// Only supported containers of types convertible to T
std::enable_if_t<
is_host_span_supported_container<C>::value &&
std::is_convertible_v<std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
std::declval<C&>().data()))> (*)[], // NOLINT(modernize-type-traits)
T (*)[]>>* = nullptr> // NOLINT
constexpr host_span(C& in) : _span{thrust::raw_pointer_cast(in.data()), in.size()}
{
}

/// Constructor from const container
/// @param in The container to construct the span from
template <typename C,
// Only supported containers of types convertible to T
std::enable_if_t<is_host_span_supported_container<C>::value &&
std::is_convertible_v<
std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
std::declval<C&>().data()))> (*)[],
T (*)[]>>* = nullptr> // NOLINT
template <
typename C,
// Only supported containers of types convertible to T
std::enable_if_t<
is_host_span_supported_container<C>::value &&
std::is_convertible_v<std::remove_pointer_t<decltype(thrust::raw_pointer_cast( // NOLINT
std::declval<C&>().data()))> (*)[], // NOLINT(modernize-type-traits)
T (*)[]>>* = nullptr> // NOLINT
constexpr host_span(C const& in) : _span{thrust::raw_pointer_cast(in.data()), in.size()}
{
}
Expand Down
50 changes: 36 additions & 14 deletions cpp/src/io/parquet/compact_protocol_reader.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2025, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2018-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand All @@ -8,12 +8,17 @@
#include "parquet_common.hpp"

#include <cudf/io/parquet_schema.hpp>
#include <cudf/utilities/error.hpp>
#include <cudf/utilities/export.hpp>

#include <cuda/std/bit>

#include <algorithm>
#include <concepts>
#include <cstddef>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <utility>

namespace CUDF_EXPORT cudf {
Expand All @@ -36,24 +41,41 @@ class CompactProtocolReader {
explicit CompactProtocolReader(uint8_t const* base = nullptr, size_t len = 0) { init(base, len); }
void init(uint8_t const* base, size_t len)
{
// A null base is valid only for an empty buffer; a positive length would then have no backing
// storage. This keeps every later pointer op defined (the empty state has all-null pointers).
CUDF_EXPECTS(base != nullptr || len == 0,
"CompactProtocolReader requires a non-null buffer when length is non-zero",
std::invalid_argument);
m_base = m_cur = base;
m_end = base + len;
// Guard against `nullptr + len` (undefined) so a zero-length buffer stays fully defined.
m_end = base != nullptr ? base + len : base;
}
[[nodiscard]] ptrdiff_t bytecount() const noexcept
{
// Avoid `nullptr - nullptr` on a null-base reader; it has consumed nothing.
return m_base != nullptr ? m_cur - m_base : 0;
}
[[nodiscard]] ptrdiff_t bytecount() const noexcept { return m_cur - m_base; }
unsigned int getb() noexcept { return (m_cur < m_end) ? *m_cur++ : 0; }
void skip_bytes(size_t bytecnt) noexcept
{
bytecnt = std::min(bytecnt, (size_t)(m_end - m_cur));
m_cur += bytecnt;
}

// returns a varint encoded integer
template <typename T>
T get_varint() noexcept
// Returns a varint-encoded integer. `T` is constrained to unsigned so `numeric_limits<T>::digits`
// is the full value width; a signed `T` would drop the sign bit and misplace the overflow bound.
template <std::unsigned_integral T>
T get_varint()
{
T v = 0;
for (uint32_t l = 0;; l += 7) {
T c = getb();
T const c = getb();
// The byte's value, shifted into place, must fit in `T`; `l < digits` also keeps `max() >> l`
// itself in range. Comparing the raw byte, not the masked payload, is intentional: it also
// rejects a continuation byte whose successor group could not fit.
CUDF_EXPECTS(l < std::numeric_limits<T>::digits && c <= (std::numeric_limits<T>::max() >> l),
"Parquet varint exceeds the width of its target type",
std::overflow_error);
v |= (c & 0x7f) << l;
if (c < 0x80) { break; }
}
Expand All @@ -62,22 +84,22 @@ class CompactProtocolReader {

// returns a zigzag encoded signed integer
template <typename T>
T get_zigzag() noexcept
T get_zigzag()
{
using U = std::make_unsigned_t<T>;
U const u = get_varint<U>();
return static_cast<T>((u >> 1u) ^ -static_cast<T>(u & 1));
}

// thrift spec says to use zigzag i32 for i16 types
int32_t get_i16() noexcept { return get_zigzag<int32_t>(); }
int32_t get_i32() noexcept { return get_zigzag<int32_t>(); }
int64_t get_i64() noexcept { return get_zigzag<int64_t>(); }
int32_t get_i16() { return get_zigzag<int32_t>(); }
int32_t get_i32() { return get_zigzag<int32_t>(); }
int64_t get_i64() { return get_zigzag<int64_t>(); }

uint32_t get_u32() noexcept { return get_varint<uint32_t>(); }
uint64_t get_u64() noexcept { return get_varint<uint64_t>(); }
uint32_t get_u32() { return get_varint<uint32_t>(); }
uint64_t get_u64() { return get_varint<uint64_t>(); }

[[nodiscard]] std::pair<uint8_t, uint32_t> get_listh() noexcept
[[nodiscard]] std::pair<uint8_t, uint32_t> get_listh()
{
uint32_t const c = getb();
uint32_t sz = c >> 4;
Expand Down
4 changes: 2 additions & 2 deletions cpp/src/io/parquet/experimental/hybrid_scan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ hybrid_scan_metadata::hybrid_scan_metadata(cudf::host_span<uint8_t const> footer
: _metadata{std::make_shared<detail::aggregate_reader_metadata>(
std::vector<cudf::host_span<uint8_t const>>{footer_bytes},
options.is_enabled_use_arrow_schema(),
options.get_column_names().has_value() and options.is_enabled_allow_mismatched_pq_schemas())}
options.is_enabled_allow_mismatched_pq_schemas())}
{
}

Expand All @@ -27,7 +27,7 @@ hybrid_scan_metadata::hybrid_scan_metadata(FileMetaData const& parquet_metadata,
: _metadata{std::make_shared<detail::aggregate_reader_metadata>(
std::vector<FileMetaData>{parquet_metadata},
options.is_enabled_use_arrow_schema(),
options.get_column_names().has_value() and options.is_enabled_allow_mismatched_pq_schemas())}
options.is_enabled_allow_mismatched_pq_schemas())}
{
}

Expand Down
42 changes: 17 additions & 25 deletions cpp/src/io/parquet/experimental/hybrid_scan_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,6 @@ using text::byte_range_info;

namespace {

// Construct a vector of FileMetaData from the input footer bytes
[[nodiscard]] std::vector<FileMetaData> parquet_metadatas_from_footer_bytes(
cudf::host_span<cudf::host_span<uint8_t const> const> footer_bytes)
{
std::vector<FileMetaData> parquet_metadatas;
parquet_metadatas.reserve(footer_bytes.size());
std::transform(footer_bytes.begin(),
footer_bytes.end(),
std::back_inserter(parquet_metadatas),
[](auto const& footer_bytes) {
metadata parsed_metadata{footer_bytes};
return FileMetaData{std::move(parsed_metadata)};
});
return parquet_metadatas;
}

// Construct a vector of all row group indices from the input vectors
[[nodiscard]] auto all_row_group_indices(
std::span<std::vector<cudf::size_type> const> row_group_indices)
Expand All @@ -77,8 +61,10 @@ namespace {
}

// Compute the page index (column index and/or offset index) byte range
[[nodiscard]] byte_range_info page_index_byte_range(FileMetaData const& file_metadata)
[[nodiscard]] byte_range_info page_index_byte_range(parquet::detail::metadata const& file_metadata)
{
if (file_metadata.is_page_index_setup()) { return {}; }

auto const& row_groups = file_metadata.row_groups;
if (row_groups.empty() or row_groups.front().columns.empty()) { return {}; }

Expand Down Expand Up @@ -132,25 +118,31 @@ aggregate_reader_metadata::aggregate_reader_metadata(
cudf::host_span<cudf::host_span<uint8_t const> const> footer_bytes,
bool use_arrow_schema,
bool has_cols_from_mismatched_srcs)
: aggregate_reader_metadata_base(parquet_metadatas_from_footer_bytes(footer_bytes),
use_arrow_schema,
has_cols_from_mismatched_srcs)
: aggregate_reader_metadata(
parquet::detail::parallel_construct_metadatas(
footer_bytes, [](auto const& bytes) { return FileMetaData{metadata{bytes}}; }),
use_arrow_schema,
has_cols_from_mismatched_srcs)
{
CUDF_EXPECTS(
not footer_bytes.empty(), "At least one source must be provided", std::invalid_argument);
}

aggregate_reader_metadata::aggregate_reader_metadata(
cudf::host_span<FileMetaData const> parquet_metadatas,
bool use_arrow_schema,
bool has_cols_from_mismatched_srcs)
: aggregate_reader_metadata_base(
: aggregate_reader_metadata(
std::vector<FileMetaData>{parquet_metadatas.begin(), parquet_metadatas.end()},
use_arrow_schema,
has_cols_from_mismatched_srcs)
{
CUDF_EXPECTS(
not parquet_metadatas.empty(), "At least one source must be provided", std::invalid_argument);
}

aggregate_reader_metadata::aggregate_reader_metadata(std::vector<FileMetaData>&& parquet_metadatas,
bool use_arrow_schema,
bool has_cols_from_mismatched_srcs)
: aggregate_reader_metadata_base(
std::move(parquet_metadatas), use_arrow_schema, has_cols_from_mismatched_srcs)
{
}

std::vector<text::byte_range_info> aggregate_reader_metadata::page_index_byte_ranges() const
Expand Down
17 changes: 17 additions & 0 deletions cpp/src/io/parquet/experimental/hybrid_scan_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ class aggregate_reader_metadata : public aggregate_reader_metadata_base {
/**
* @brief Constructor for aggregate_reader_metadata
*
* @throws std::invalid_argument if no sources are provided
*
* @param footer_bytes Host span of Parquet file footer buffer bytes, one per source
* @param use_arrow_schema Whether to use Arrow schema
* @param has_cols_from_mismatched_srcs Whether to have columns from mismatched sources
Expand All @@ -92,6 +94,8 @@ class aggregate_reader_metadata : public aggregate_reader_metadata_base {
/**
* @brief Constructor for aggregate_reader_metadata
*
* @throws std::invalid_argument if no sources are provided
*
* @param parquet_metadatas Host span of pre-populated Parquet file metadata, one per source
* @param use_arrow_schema Whether to use Arrow schema
* @param has_cols_from_mismatched_srcs Whether to have columns from mismatched sources
Expand All @@ -100,6 +104,19 @@ class aggregate_reader_metadata : public aggregate_reader_metadata_base {
bool use_arrow_schema,
bool has_cols_from_mismatched_srcs);

/**
* @brief Constructor that takes ownership of pre-populated Parquet file metadata
*
* @throws std::invalid_argument if no sources are provided
*
* @param parquet_metadatas Pre-populated Parquet file metadata, one per source
* @param use_arrow_schema Whether to use Arrow schema
* @param has_cols_from_mismatched_srcs Whether to have columns from mismatched sources
*/
aggregate_reader_metadata(std::vector<FileMetaData>&& parquet_metadatas,
bool use_arrow_schema,
bool has_cols_from_mismatched_srcs);

aggregate_reader_metadata(aggregate_reader_metadata const&) = delete;
aggregate_reader_metadata& operator=(aggregate_reader_metadata const&) = delete;
aggregate_reader_metadata(aggregate_reader_metadata&&) = default;
Expand Down
Loading
Loading