blob: e956abc93eb1b04b84241b7281fe00a9b12f00d5 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <cstdint>
#include <sstream>
#include <variant>
#include "arrow/util/bit_util.h"
#include "arrow/util/int_util_overflow.h"
#include "arrow/util/logging.h"
#include "arrow/util/macros.h"
#include "arrow/util/rle_bitmap_internal.h"
#include "arrow/util/rle_encoding_internal.h"
#include "arrow/util/ubsan.h"
#include "parquet/exception.h"
#include "parquet/level_comparison.h"
#include "parquet/types.h"
namespace parquet {
struct LevelDecoderParams {
int32_t value_count = 0;
int16_t max_level = 0;
};
/*******************************
* PageLevelDecoder Adapters *
*******************************/
/// BitPackedDecoder adapter for PageLevelDecoder.
struct LevelBitPackedDecoder : ::arrow::util::BitPackedDecoder<int16_t> {
using Base = BitPackedDecoder<int16_t>;
LevelBitPackedDecoder(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params)
: Base(data, data_size,
/* value_bit_width= */ ::arrow::bit_util::Log2(params.max_level + 1),
params.value_count) {}
int32_t GetBatch(int16_t* out, int32_t batch_size, int16_t max_level);
};
/// RleBitPackedDecoder adapter for PageLevelDecoder.
struct LevelRleBitPackedDecoder : ::arrow::util::RleBitPackedDecoder<int16_t> {
using Base = RleBitPackedDecoder<int16_t>;
LevelRleBitPackedDecoder(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params)
: Base(data, data_size,
/* value_bit_width= */ ::arrow::bit_util::Log2(params.max_level + 1)) {}
int32_t GetBatch(int16_t* out, int32_t batch_size, int16_t max_level);
};
/**************************************
* PageLevelDecoder Bitmap Adapters *
**************************************/
struct LevelToBitmapBitPackedDecoder : ::arrow::util::BitPackedToBitmapDecoder {
using Base = BitPackedToBitmapDecoder;
LevelToBitmapBitPackedDecoder(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params)
: Base(data, data_size, params.value_count) {
ARROW_DCHECK_EQ(params.max_level, 1);
}
template <typename Out>
int32_t GetBatch(Out&& out, int32_t batch_size, int16_t /* max_level */) {
return Base::GetBatch(out, batch_size);
}
};
struct LevelToBitmapRleBitPackedDecoder : ::arrow::util::RleBitPackedToBitmapDecoder {
using Base = RleBitPackedToBitmapDecoder;
LevelToBitmapRleBitPackedDecoder(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params)
: Base(data, data_size) {
ARROW_DCHECK_EQ(params.max_level, 1);
}
template <typename Out>
int32_t GetBatch(Out&& out, int32_t batch_size, int16_t /* max_level */) {
return Base::GetBatch(out, batch_size);
}
};
/**********************
* PageLevelDecoder *
**********************/
/// Decoder for repetition or definition level.
///
/// This decoder is used with either a deprecated bit packed (`BIT_PACKED = 4`)
/// encoding or a mixed bit packed and RLE one (`RLE = 3`).
/// Because it takes as input a single buffer, `SetData` and `Decode` are typically
/// used on each of the Parquet `DataPage`.
/// The number of levels is guaranteed to fit into an `int32_t` by the specification.
///
/// @see https://research.google.com/pubs/archive/36632.pdf
template <typename BitDecoder = LevelBitPackedDecoder,
typename RleDecoder = LevelRleBitPackedDecoder>
class PageLevelDecoder {
public:
explicit PageLevelDecoder(int16_t max_level = 0)
: decoder_(BitDecoder(nullptr, 0, LevelDecoderParams{.max_level = max_level})),
max_level_(max_level) {}
/// Initialize the decoder state with new data from a legacy (V1) page.
///
/// @return the number of bytes consumed
int32_t SetDataV1(Encoding::type encoding, const uint8_t* data, int32_t max_data_size,
const LevelDecoderParams& params);
/// Initialize the decoder state with new data from a V2 page.
///
/// Repetition and definition levels in V2 pages are always RLE encoded.
void SetDataV2(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params);
/// Decode a batch of levels into `out` and return the number of levels decoded.
template <typename Out>
int32_t Decode(Out&& out, int32_t batch_size);
/// Advance the decoder and throw away decoded levels.
int32_t Skip(int32_t batch_size);
struct CountUpToResult {
int32_t matching_count;
int32_t processed_count;
};
/// Advance and count the number of occurrences of `value`.
///
/// The count is limited to at most the next `batch_size` items.
/// @return The matching value count and number of elements that were processed.
CountUpToResult CountUpTo(int16_t value, int32_t batch_size);
/// Return the max level used in this decoder.
int16_t max_level() const { return max_level_; }
/// Return the number of values left to be decoded.
int32_t remaining() const { return num_values_remaining_; }
private:
std::variant<BitDecoder, RleDecoder> decoder_;
/// Number of values remaining. The underlying decoder zero pads bit packed values
/// up to a multiple of 8 so it cannot know the exact number of remaining values.
int32_t num_values_remaining_ = 0;
int16_t max_level_ = 0;
};
/// Decoder for definition levels that writes directly into a validity bitmap.
///
/// This is the bitmap counterpart of the default ``PageLevelDecoder``,
/// specialized for levels encoded on a single bit (a max level of 1),
/// such as the definition levels of a flat, nullable column.
/// Rather than decoding into an ``int16_t`` array and re-encoding into
/// an Arrow validity bitmap, it decodes straight into the bitmap.
///
/// @see PageLevelDecoder
struct PageLevelToBitmapDecoder
: PageLevelDecoder<LevelToBitmapBitPackedDecoder, LevelToBitmapRleBitPackedDecoder> {
PageLevelToBitmapDecoder() : PageLevelDecoder(/* max_level= */ 1) {}
};
/***************
* Utilities *
***************/
/// Throws if the decoder could not provide as many levels as the page header announces.
inline void CheckValidLevelCount(bool valid) {
if (ARROW_PREDICT_FALSE(!valid)) {
throw ParquetException(
"Number of decoded rep / def levels do not match num_values in page header");
}
}
inline void CheckLevelMinMax(const int16_t* data, int32_t size, int16_t max_level) {
if (size > 0) {
internal::MinMax min_max = internal::FindMinMax(data, size);
if (ARROW_PREDICT_FALSE(min_max.min < 0 || min_max.max > max_level)) {
std::stringstream ss;
ss << "Malformed levels. min: " << min_max.min << " max: " << min_max.max
<< " out of range. Max Level: " << max_level;
throw ParquetException(ss.str());
}
}
}
/*************************************************
* Implementation of PageLevelDecoder Adapters *
*************************************************/
inline int32_t LevelBitPackedDecoder::GetBatch(int16_t* out, int32_t batch_size,
int16_t max_level) {
const int32_t num_decoded = Base::GetBatch(out, batch_size);
CheckLevelMinMax(out, num_decoded, max_level);
return num_decoded;
}
inline int32_t LevelRleBitPackedDecoder::GetBatch(int16_t* out, int32_t batch_size,
int16_t max_level) {
const int32_t num_decoded = Base::GetBatch(out, batch_size);
CheckLevelMinMax(out, num_decoded, max_level);
return num_decoded;
}
/****************************************
* Implementation of PageLevelDecoder *
****************************************/
template <typename BitDec, typename RleDec>
int32_t PageLevelDecoder<BitDec, RleDec>::SetDataV1(Encoding::type encoding,
const uint8_t* data,
int32_t max_data_size,
const LevelDecoderParams& params) {
using ::arrow::bit_util::BytesForBits;
using ::arrow::bit_util::Log2;
using ::arrow::internal::MultiplyWithOverflow;
num_values_remaining_ = params.value_count;
max_level_ = params.max_level;
const int32_t value_bit_width = Log2(params.max_level + 1);
switch (encoding) {
case Encoding::RLE: {
if (ARROW_PREDICT_FALSE(max_data_size < 4)) {
throw ParquetException("Received invalid levels (corrupt data page?)");
}
const auto data_size = ::arrow::util::SafeLoadAs<int32_t>(data);
if (ARROW_PREDICT_FALSE(data_size < 0 || data_size > max_data_size - 4)) {
throw ParquetException("Received invalid number of bytes (corrupt data page?)");
}
decoder_ = RleDec(/* data= */ data + 4, /* data_size= */ data_size, params);
return 4 + data_size;
}
case Encoding::BIT_PACKED: {
int32_t num_bits = 0;
if (MultiplyWithOverflow(params.value_count, value_bit_width, &num_bits)) {
throw ParquetException(
"Number of buffered values too large (corrupt data page?)");
}
const auto data_size = static_cast<int32_t>(BytesForBits(num_bits));
if (ARROW_PREDICT_FALSE(data_size < 0 || data_size > max_data_size)) {
throw ParquetException("Received invalid number of bytes (corrupt data page?)");
}
decoder_ = BitDec(/* data= */ data, /* data_size= */ data_size, params);
return data_size;
}
default:
throw ParquetException("Unknown encoding type for levels.");
}
return -1;
}
template <typename BitDec, typename RleDec>
void PageLevelDecoder<BitDec, RleDec>::SetDataV2(const uint8_t* data, int32_t data_size,
const LevelDecoderParams& params) {
if (data_size < 0) {
throw ParquetException("Invalid page header (corrupt data page?)");
}
num_values_remaining_ = params.value_count;
max_level_ = params.max_level;
decoder_ = RleDec(data, data_size, params);
}
template <typename BitDec, typename RleDec>
template <typename Out>
int32_t PageLevelDecoder<BitDec, RleDec>::Decode(Out&& out, int32_t batch_size) {
const int32_t num_values = std::min(num_values_remaining_, batch_size);
const int32_t num_decoded = std::visit(
[&](auto& dec) { return dec.GetBatch(out, num_values, max_level_); }, decoder_);
num_values_remaining_ -= num_decoded;
return num_decoded;
}
template <typename BitDec, typename RleDec>
int32_t PageLevelDecoder<BitDec, RleDec>::Skip(int32_t batch_size) {
const int32_t num_values = std::min(num_values_remaining_, batch_size);
const int32_t num_advanced =
std::visit([&](auto& dec) { return dec.Advance(num_values); }, decoder_);
num_values_remaining_ -= num_advanced;
return num_advanced;
}
template <typename BitDec, typename RleDec>
auto PageLevelDecoder<BitDec, RleDec>::CountUpTo(int16_t value,
int32_t batch_size) -> CountUpToResult {
const int32_t num_values = std::min(num_values_remaining_, batch_size);
const auto result =
std::visit([&](auto& dec) { return dec.CountUpTo(value, num_values); }, decoder_);
num_values_remaining_ -= result.processed_count;
return {
.matching_count = result.matching_count,
.processed_count = result.processed_count,
};
}
} // namespace parquet