Skip to content

Commit f193d59

Browse files
authored
Include row group level stats when writing ORC files (#10041)
Closes #9964 Encodes row group level stats with the rest and writes the encoded blobs into the protobuf, at the start of each stripe (other stats are in the file footer). Adds `put_bytes` to `ProtobufWriter` to optimize writing of buffers. Adds new struct to represent the encoded ORC statistics so they are separated by granularity level (instead of using a single vector). Authors: - Vukasin Milovanovic (https://github.com/vuule) Approvers: - Mike Wilson (https://github.com/hyperbolic2346) - https://github.com/nvdbaranec URL: #10041
1 parent 8e88adc commit f193d59

8 files changed

+278
-218
lines changed

cpp/src/io/orc/orc.cpp

+38-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019-2021, NVIDIA CORPORATION.
2+
* Copyright (c) 2019-2022, NVIDIA CORPORATION.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,10 +38,10 @@ uint32_t ProtobufReader::read_field_size(const uint8_t* end)
3838
void ProtobufReader::skip_struct_field(int t)
3939
{
4040
switch (t) {
41-
case PB_TYPE_VARINT: get<uint32_t>(); break;
42-
case PB_TYPE_FIXED64: skip_bytes(8); break;
43-
case PB_TYPE_FIXEDLEN: skip_bytes(get<uint32_t>()); break;
44-
case PB_TYPE_FIXED32: skip_bytes(4); break;
41+
case ProtofType::VARINT: get<uint32_t>(); break;
42+
case ProtofType::FIXED64: skip_bytes(8); break;
43+
case ProtofType::FIXEDLEN: skip_bytes(get<uint32_t>()); break;
44+
case ProtofType::FIXED32: skip_bytes(4); break;
4545
default: break;
4646
}
4747
}
@@ -209,43 +209,54 @@ void ProtobufWriter::put_row_index_entry(int32_t present_blk,
209209
int32_t data_ofs,
210210
int32_t data2_blk,
211211
int32_t data2_ofs,
212-
TypeKind kind)
212+
TypeKind kind,
213+
ColStatsBlob const* stats)
213214
{
214215
size_t sz = 0, lpos;
215-
putb(1 * 8 + PB_TYPE_FIXEDLEN); // 1:RowIndex.entry
216+
put_uint(encode_field_number(1, ProtofType::FIXEDLEN)); // 1:RowIndex.entry
216217
lpos = m_buf->size();
217-
putb(0xcd); // sz+2
218-
putb(1 * 8 + PB_TYPE_FIXEDLEN); // 1:positions[packed=true]
219-
putb(0xcd); // sz
218+
put_byte(0xcd); // sz+2
219+
put_uint(encode_field_number(1, ProtofType::FIXEDLEN)); // 1:positions[packed=true]
220+
put_byte(0xcd); // sz
220221
if (present_blk >= 0) sz += put_uint(present_blk);
221222
if (present_ofs >= 0) {
222-
sz += put_uint(present_ofs) + 2;
223-
putb(0); // run pos = 0
224-
putb(0); // bit pos = 0
223+
sz += put_uint(present_ofs);
224+
sz += put_byte(0); // run pos = 0
225+
sz += put_byte(0); // bit pos = 0
225226
}
226227
if (data_blk >= 0) { sz += put_uint(data_blk); }
227228
if (data_ofs >= 0) {
228229
sz += put_uint(data_ofs);
229230
if (kind != STRING && kind != FLOAT && kind != DOUBLE && kind != DECIMAL) {
230-
putb(0); // RLE run pos always zero (assumes RLE aligned with row index boundaries)
231-
sz++;
231+
// RLE run pos always zero (assumes RLE aligned with row index boundaries)
232+
sz += put_byte(0);
232233
if (kind == BOOLEAN) {
233-
putb(0); // bit position in byte, always zero
234-
sz++;
234+
// bit position in byte, always zero
235+
sz += put_byte(0);
235236
}
236237
}
237238
}
238-
if (kind !=
239-
INT) // INT kind can be passed in to bypass 2nd stream index (dictionary length streams)
240-
{
239+
// INT kind can be passed in to bypass 2nd stream index (dictionary length streams)
240+
if (kind != INT) {
241241
if (data2_blk >= 0) { sz += put_uint(data2_blk); }
242242
if (data2_ofs >= 0) {
243-
sz += put_uint(data2_ofs) + 1;
244-
putb(0); // RLE run pos always zero (assumes RLE aligned with row index boundaries)
243+
sz += put_uint(data2_ofs);
244+
// RLE run pos always zero (assumes RLE aligned with row index boundaries)
245+
sz += put_byte(0);
245246
}
246247
}
247-
m_buf->data()[lpos] = (uint8_t)(sz + 2);
248+
// size of the field 1
248249
m_buf->data()[lpos + 2] = (uint8_t)(sz);
250+
251+
if (stats != nullptr) {
252+
sz += put_uint(encode_field_number<decltype(*stats)>(2)); // 2: statistics
253+
// Statistics field contains its length as varint and dtype specific data (encoded on the GPU)
254+
sz += put_uint(stats->size());
255+
sz += put_bytes<typename ColStatsBlob::value_type>(*stats);
256+
}
257+
258+
// size of the whole row index entry
259+
m_buf->data()[lpos] = (uint8_t)(sz + 2);
249260
}
250261

251262
size_t ProtobufWriter::write(const PostScript& s)
@@ -256,7 +267,7 @@ size_t ProtobufWriter::write(const PostScript& s)
256267
if (s.compression != NONE) { w.field_uint(3, s.compressionBlockSize); }
257268
w.field_packed_uint(4, s.version);
258269
w.field_uint(5, s.metadataLength);
259-
w.field_string(8000, s.magic);
270+
w.field_blob(8000, s.magic);
260271
return w.value();
261272
}
262273

@@ -300,8 +311,8 @@ size_t ProtobufWriter::write(const SchemaType& s)
300311
size_t ProtobufWriter::write(const UserMetadataItem& s)
301312
{
302313
ProtobufFieldWriter w(this);
303-
w.field_string(1, s.name);
304-
w.field_string(2, s.value);
314+
w.field_blob(1, s.name);
315+
w.field_blob(2, s.value);
305316
return w.value();
306317
}
307318

@@ -310,7 +321,7 @@ size_t ProtobufWriter::write(const StripeFooter& s)
310321
ProtobufFieldWriter w(this);
311322
w.field_repeated_struct(1, s.streams);
312323
w.field_repeated_struct(2, s.columns);
313-
if (s.writerTimezone != "") { w.field_string(3, s.writerTimezone); }
324+
if (s.writerTimezone != "") { w.field_blob(3, s.writerTimezone); }
314325
return w.value();
315326
}
316327

cpp/src/io/orc/orc.h

+79-59
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019-2021, NVIDIA CORPORATION.
2+
* Copyright (c) 2019-2022, NVIDIA CORPORATION.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -131,6 +131,67 @@ struct Metadata {
131131
std::vector<StripeStatistics> stripeStats;
132132
};
133133

134+
int inline constexpr encode_field_number(int field_number, ProtofType field_type) noexcept
135+
{
136+
return (field_number * 8) + static_cast<int>(field_type);
137+
}
138+
139+
namespace {
140+
template <typename base_t,
141+
typename std::enable_if_t<!std::is_arithmetic<base_t>::value and
142+
!std::is_enum<base_t>::value>* = nullptr>
143+
int static constexpr encode_field_number_base(int field_number) noexcept
144+
{
145+
return encode_field_number(field_number, ProtofType::FIXEDLEN);
146+
}
147+
148+
template <typename base_t,
149+
typename std::enable_if_t<std::is_integral<base_t>::value or
150+
std::is_enum<base_t>::value>* = nullptr>
151+
int static constexpr encode_field_number_base(int field_number) noexcept
152+
{
153+
return encode_field_number(field_number, ProtofType::VARINT);
154+
}
155+
156+
template <typename base_t, typename std::enable_if_t<std::is_same_v<base_t, float>>* = nullptr>
157+
int static constexpr encode_field_number_base(int field_number) noexcept
158+
{
159+
return encode_field_number(field_number, ProtofType::FIXED32);
160+
}
161+
162+
template <typename base_t, typename std::enable_if_t<std::is_same_v<base_t, double>>* = nullptr>
163+
int static constexpr encode_field_number_base(int field_number) noexcept
164+
{
165+
return encode_field_number(field_number, ProtofType::FIXED64);
166+
}
167+
}; // namespace
168+
169+
template <
170+
typename T,
171+
typename std::enable_if_t<!std::is_class<T>::value or std::is_same_v<T, std::string>>* = nullptr>
172+
int constexpr encode_field_number(int field_number) noexcept
173+
{
174+
return encode_field_number_base<T>(field_number);
175+
}
176+
177+
// containters change the field number encoding
178+
template <
179+
typename T,
180+
typename std::enable_if_t<std::is_same<T, std::vector<typename T::value_type>>::value>* = nullptr>
181+
int constexpr encode_field_number(int field_number) noexcept
182+
{
183+
return encode_field_number_base<T>(field_number);
184+
}
185+
186+
// optional fields don't change the field number encoding
187+
template <typename T,
188+
typename std::enable_if_t<
189+
std::is_same<T, std::optional<typename T::value_type>>::value>* = nullptr>
190+
int constexpr encode_field_number(int field_number) noexcept
191+
{
192+
return encode_field_number_base<typename T::value_type>(field_number);
193+
}
194+
134195
/**
135196
* @brief Class for parsing Orc's Protocol Buffers encoded metadata
136197
*/
@@ -181,60 +242,6 @@ class ProtobufReader {
181242
template <typename T, typename... Operator>
182243
void function_builder(T& s, size_t maxlen, std::tuple<Operator...>& op);
183244

184-
template <typename base_t,
185-
typename std::enable_if_t<!std::is_arithmetic<base_t>::value and
186-
!std::is_enum<base_t>::value>* = nullptr>
187-
int static constexpr encode_field_number_base(int field_number) noexcept
188-
{
189-
return (field_number * 8) + PB_TYPE_FIXEDLEN;
190-
}
191-
192-
template <typename base_t,
193-
typename std::enable_if_t<std::is_integral<base_t>::value or
194-
std::is_enum<base_t>::value>* = nullptr>
195-
int static constexpr encode_field_number_base(int field_number) noexcept
196-
{
197-
return (field_number * 8) + PB_TYPE_VARINT;
198-
}
199-
200-
template <typename base_t, typename std::enable_if_t<std::is_same_v<base_t, float>>* = nullptr>
201-
int static constexpr encode_field_number_base(int field_number) noexcept
202-
{
203-
return (field_number * 8) + PB_TYPE_FIXED32;
204-
}
205-
206-
template <typename base_t, typename std::enable_if_t<std::is_same_v<base_t, double>>* = nullptr>
207-
int static constexpr encode_field_number_base(int field_number) noexcept
208-
{
209-
return (field_number * 8) + PB_TYPE_FIXED64;
210-
}
211-
212-
template <typename T,
213-
typename std::enable_if_t<!std::is_class<T>::value or std::is_same_v<T, std::string>>* =
214-
nullptr>
215-
int static constexpr encode_field_number(int field_number) noexcept
216-
{
217-
return encode_field_number_base<T>(field_number);
218-
}
219-
220-
// containters change the field number encoding
221-
template <typename T,
222-
typename std::enable_if_t<
223-
std::is_same<T, std::vector<typename T::value_type>>::value>* = nullptr>
224-
int static constexpr encode_field_number(int field_number) noexcept
225-
{
226-
return encode_field_number_base<T>(field_number);
227-
}
228-
229-
// optional fields don't change the field number encoding
230-
template <typename T,
231-
typename std::enable_if_t<
232-
std::is_same<T, std::optional<typename T::value_type>>::value>* = nullptr>
233-
int static constexpr encode_field_number(int field_number) noexcept
234-
{
235-
return encode_field_number_base<typename T::value_type>(field_number);
236-
}
237-
238245
uint32_t read_field_size(const uint8_t* end);
239246

240247
template <typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
@@ -470,16 +477,28 @@ class ProtobufWriter {
470477
public:
471478
ProtobufWriter() { m_buf = nullptr; }
472479
ProtobufWriter(std::vector<uint8_t>* output) { m_buf = output; }
473-
void putb(uint8_t v) { m_buf->push_back(v); }
480+
uint32_t put_byte(uint8_t v)
481+
{
482+
m_buf->push_back(v);
483+
return 1;
484+
}
485+
template <typename T>
486+
uint32_t put_bytes(host_span<T const> values)
487+
{
488+
static_assert(sizeof(T) == 1);
489+
m_buf->reserve(m_buf->size() + values.size());
490+
m_buf->insert(m_buf->end(), values.begin(), values.end());
491+
return values.size();
492+
}
474493
uint32_t put_uint(uint64_t v)
475494
{
476495
int l = 1;
477496
while (v > 0x7f) {
478-
putb(static_cast<uint8_t>(v | 0x80));
497+
put_byte(static_cast<uint8_t>(v | 0x80));
479498
v >>= 7;
480499
l++;
481500
}
482-
putb(static_cast<uint8_t>(v));
501+
put_byte(static_cast<uint8_t>(v));
483502
return l;
484503
}
485504
uint32_t put_int(int64_t v)
@@ -493,7 +512,8 @@ class ProtobufWriter {
493512
int32_t data_ofs,
494513
int32_t data2_blk,
495514
int32_t data2_ofs,
496-
TypeKind kind);
515+
TypeKind kind,
516+
ColStatsBlob const* stats);
497517

498518
public:
499519
size_t write(const PostScript&);

cpp/src/io/orc/orc_common.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019-2021, NVIDIA CORPORATION.
2+
* Copyright (c) 2019-2022, NVIDIA CORPORATION.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -76,15 +76,15 @@ enum ColumnEncodingKind : int8_t {
7676
DICTIONARY_V2 = 3, // the encoding is dictionary-based using RLE v2
7777
};
7878

79-
enum : uint8_t { // Protobuf field types
80-
PB_TYPE_VARINT = 0,
81-
PB_TYPE_FIXED64 = 1,
82-
PB_TYPE_FIXEDLEN = 2,
83-
PB_TYPE_START_GROUP = 3, // deprecated
84-
PB_TYPE_END_GROUP = 4, // deprecated
85-
PB_TYPE_FIXED32 = 5,
86-
PB_TYPE_INVALID_6 = 6,
87-
PB_TYPE_INVALID_7 = 7,
79+
enum ProtofType : uint8_t {
80+
VARINT = 0,
81+
FIXED64 = 1,
82+
FIXEDLEN = 2,
83+
START_GROUP = 3, // deprecated
84+
END_GROUP = 4, // deprecated
85+
FIXED32 = 5,
86+
INVALID_6 = 6,
87+
INVALID_7 = 7,
8888
};
8989

9090
} // namespace orc

0 commit comments

Comments
 (0)