ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability - #4963

Closed
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor
Closed

ARROW-6065: [C++][Parquet] Clean up parquet/arrow/reader.cc, reduce code duplication, improve readability#4963
wesm wants to merge 4 commits into
apache:masterfrom
wesm:parquet-arrow-read-refactor

Conversation

@wesm

@wesmwesm commented Jul 29, 2019

Copy link
Copy Markdown
Member

This is strictly a refactoring PR. I'm going to start working (for a new PR) on some refactoring of the handling of schemas and nested types (which is also pretty messy in my opinion). The motivation for this is to be able to more cleanly reason about direct dictionary-decoding without having to resort to such hacks as the current FixSchemas function

Also cleans up Parquet includes using IWYU

@wesm

wesm commented Jul 29, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield I'm also trying to clean up some business logic in such a way that it will help you with implementing nested reads, though there is little enough logic related to nested data that you might want to start fresh anyway

@codecov-io

Copy link
Copy Markdown

Codecov Report

Merging #4963 into master will increase coverage by 1.64%.
The diff coverage is 90.65%.

Impacted file tree graph

@@ Coverage Diff @@## master #4963 +/- ##
==========================================
+ Coverage 87.5% 89.14% +1.64% 
==========================================
Files 998 722 -276 Lines 141869 101612 -40257 Branches 1418 0 -1418 ==========================================
- Hits 124139 90587 -33552 + Misses 17368 11025 -6343 + Partials 362 0 -362
Impacted FilesCoverage Δ
cpp/src/parquet/column_writer.h88.88% <ø> (ø)⬆️
cpp/src/parquet/file_reader.cc94.3% <ø> (ø)⬆️
cpp/src/parquet/statistics.h100% <ø> (ø)⬆️
cpp/src/parquet/bloom_filter.cc91.13% <ø> (ø)⬆️
cpp/src/parquet/encoding.cc93.73% <ø> (ø)⬆️
cpp/src/parquet/types.cc93.76% <ø> (ø)⬆️
cpp/src/parquet/statistics.cc87.96% <ø> (ø)⬆️
cpp/src/parquet/file_writer.h100% <ø> (ø)⬆️
cpp/src/parquet/schema.cc90.07% <ø> (ø)⬆️
cpp/src/parquet/arrow/writer.h100% <ø> (ø)⬆️
... and 300 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 171c3f7...cf9f5e3. Read the comment docs.

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

I didn't really look at implementation details. A couple comments below.

{ include: ["<ext/alloc_traits.h>", private, "<unordered_map>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<unordered_set>", public ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public ] },
{ include: ["<bits/exception.h>", private, "<exception>", public ] },

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.

Wow. Are we really maintaing all this by ourselves? Sounds like IWYU is not exactly user-friendy.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

yeah, see another project e.g. https://github.com/apache/kudu/tree/master/build-support/iwyu/mappings

the trouble is that IWYU in some cases will find the "minimal" header to obtain certain symbols which might be something internal to the STL implementation, but that will vary on different compilers (e.g. MSVC's internal STL stuff may be different) so you need to force it in some cases to use the right "official"/"public" headers

const int num_columns = 20;
const int num_rows = 1000;
const int num_columns = 10;
const int num_rows = 100;

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.

Is this to make the test faster?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Yes, and easier to debug


// ----------------------------------------------------------------------
// File reader implementation
// FileReaderImpl forward declaration

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.

It's not really a "forward declaration", right? Seems like an implementation to me :-)

int64_t GetTotalRecords(const std::vector<int>& row_groups, int column_chunk = 0) {
// Can throw exception
int64_t records = 0;
for (int j = 0; j < static_cast<int>(row_groups.size()); j++) {

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.

Use a range-based loop? for (const auto& row_group : row_groups) ...

for (auto& fut : futures) {
Status st = fut.get();
if (!st.ok()) {
final_status = std::move(st);

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.

Or simply final_status &= fut.get().

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is copy-paste


class PARQUET_NO_EXPORT Impl;
std::unique_ptr<Impl> impl_;
virtual ~FileReader() = default;

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.

Hmm... I'm not sure it's ok to use = default on a virtual destructor of a DLL-exported class. I think it's safer to define an empty destructor explicitly in the .cc file, though I may be mistaken.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Hm. Would be nice to know what the C++ standard says

};

class PARQUET_EXPORT RowGroupReader {
class RowGroupReader {

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.

Do we need to PARQUET_EXPORT this class and also ColumnChunkReader?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Nope


for (int64_t i = 0; i < length; i++) {
if (values[i]) {
::arrow::BitUtil::SetBit(data_ptr, i);

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.

Should this use GenerateBitsUnrolled for higher perf?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Old code

if (reader->read_dictionary()) {
return TransferDictionary(reader, logical_value_type, out);
}
auto binary_reader = dynamic_cast<internal::BinaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

Status TransferDictionary(RecordReader* reader,
const std::shared_ptr<DataType>& logical_value_type,
std::shared_ptr<ChunkedArray>* out) {
auto dict_reader = dynamic_cast<internal::DictionaryRecordReader*>(reader);

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.

Use checked_cast?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

static_cast doesn't work with this type

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

I'll address a couple comments in my follow up patch. I'm going to merge this so I'm not stacking up patches

@wesmwesm closed this in dbd93e3Jul 30, 2019
@emkornfield

Copy link
Copy Markdown
Contributor

@wesm thanks, I've been a little delayed with the parquet stuff and this week, I'd like to try to knock off java/c++ compatibility since it seems you still have a few more patches to do.

@wesm

wesm commented Jul 30, 2019

Copy link
Copy Markdown
MemberAuthor

@emkornfield yes, I'll let you know when it's the "all clear" viz-a-viz refactoring

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@wesm@codecov-io@emkornfield@pitrou