Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for plain and dictionary encoded INT64 timestamp in parquet files #8325

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

mskapilks
Copy link

Adds support for UTC adjusted INT64 timestamp in parquet files. Can read both the current parquet logical type and old converted type annotated timestamp.
This PR takes inspiration from this #4680

Copy link

netlify bot commented Jan 10, 2024

Deploy Preview for meta-velox canceled.

Name Link
🔨 Latest commit 187e2c5
🔍 Latest deploy log https://app.netlify.com/sites/meta-velox/deploys/66d84e78fabff200089f64e5

@mskapilks
Copy link
Author

@rui-mo

@mskapilks mskapilks changed the title Support for INT64 timestamp in parquet files Support for plain and dictionary encoded INT64 timestamp in parquet files Jan 10, 2024
@facebook-github-bot
Copy link
Contributor

Hi @mskapilks!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at [email protected]. Thanks!

Copy link
Collaborator

@rui-mo rui-mo left a comment

Choose a reason for hiding this comment

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

Thanks for your work! I'm still reading this PR, and just added several comments for the code style. Could you also sign the CLA?

velox/dwio/common/TimestampDecoder.h Outdated Show resolved Hide resolved
velox/dwio/common/TimestampDecoder.h Outdated Show resolved Hide resolved
velox/type/TimestampConversion.h Outdated Show resolved Hide resolved
velox/type/TimestampConversion.h Outdated Show resolved Hide resolved
velox/dwio/common/TimestampDecoder.h Outdated Show resolved Hide resolved
velox/dwio/common/TimestampDecoder.h Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/ParquetReader.cpp Outdated Show resolved Hide resolved
@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jan 12, 2024
@mskapilks
Copy link
Author

@rui-mo Thanks for your review. Have resolved all the comments

@rui-mo
Copy link
Collaborator

rui-mo commented Jan 15, 2024

@yingsu00 @Yuhta Could you help review the INT64 timestamp support in Parquet reader? Thank you.

@mskapilks
Copy link
Author

Not sure what this failure means in the CI pipeline.

From github.com:facebookincubator/velox
 * [new ref]             refs/pull/8325/head -> origin/pull/8325
Checking out branch
fatal: reference is not a tree: 29afcfa878266626e6ef8956452eb4a8b4be5504

exit status 128

@mskapilks
Copy link
Author

mskapilks commented Jan 22, 2024

@yingsu00 @Yuhta Gentle ping for review.

cc: @rui-mo

Copy link
Collaborator

@rui-mo rui-mo left a comment

Choose a reason for hiding this comment

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

Thanks for your efforts on the support of timestamp reader. Added several comments.

velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved
@mskapilks
Copy link
Author

@rui-mo Thank you for your review. I have addressed all the comments.

@mskapilks
Copy link
Author

Will check on the failure

*** Aborted at 1707296079 (Unix time, try 'date -d @1707296079') ***
*** Signal 6 (SIGABRT) (0x3db07) received by PID 252679 (pthread TID 0x7fa36cab7500) (linux TID 252679) (maybe from PID 252679, UID 0) (code: -6), stack trace: ***
(error retrieving stack trace)
/bin/bash: line 5: 252679 Aborted                 (core dumped) _build/debug/velox/exec/tests/velox_join_fuzzer_test --seed ${RANDOM} --duration_sec 1800 --logtostderr=1 --minloglevel=0

@mskapilks mskapilks force-pushed the timestamp_int64 branch 2 times, most recently from 4173963 to df6ed31 Compare February 12, 2024 05:05
@mskapilks
Copy link
Author

Will check on the failure

*** Aborted at 1707296079 (Unix time, try 'date -d @1707296079') ***
*** Signal 6 (SIGABRT) (0x3db07) received by PID 252679 (pthread TID 0x7fa36cab7500) (linux TID 252679) (maybe from PID 252679, UID 0) (code: -6), stack trace: ***
(error retrieving stack trace)
/bin/bash: line 5: 252679 Aborted                 (core dumped) _build/debug/velox/exec/tests/velox_join_fuzzer_test --seed ${RANDOM} --duration_sec 1800 --logtostderr=1 --minloglevel=0

Passing now in recent build

@mskapilks mskapilks requested a review from rui-mo March 18, 2024 04:59
Copy link
Collaborator

@rui-mo rui-mo left a comment

Choose a reason for hiding this comment

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

Thanks!

memcpy(&value, &timestamp, sizeof(int128_t));
toSkip = visitor.process(value, atEnd);
} else {
toSkip = visitor.process(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you remind me when will this path be executed, and what is the expected behavior here?

Copy link
Author

@mskapilks mskapilks Apr 29, 2024

Choose a reason for hiding this comment

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

Thanks for pointing out. I don't think it will ever go there as type will always be int128_t. Updated the code.

velox/dwio/parquet/reader/PageReader.cpp Outdated Show resolved Hide resolved

auto precisionUnit = logicalType.TIMESTAMP.unit.__isset.MICROS
? dwio::common::TimestampPrecision::kMicros
: dwio::common::TimestampPrecision::kMillis;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to check __isset.MILLIS before assign kMillis, and throw for the other units?

Copy link
Author

@mskapilks mskapilks Apr 29, 2024

Choose a reason for hiding this comment

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

There are only 3 units. For Nano we throw error a line above. So one of MILLIS or MICROS will be true.

velox/dwio/common/TimestampDecoder.h Outdated Show resolved Hide resolved
@yingsu00 yingsu00 self-requested a review April 4, 2024 11:49
velox/dwio/parquet/reader/ParquetReader.cpp Outdated Show resolved Hide resolved
auto logicalType = type_->logicalType_.value();
if (logicalType.__isset.TIMESTAMP) {
VELOX_CHECK(
logicalType.TIMESTAMP.isAdjustedToUTC,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be VELOX_NYI?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Btw, what do you want to do if isAdjustedToUTC is false?

Copy link
Author

Choose a reason for hiding this comment

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

I haven't thought about it much. My perspective is from Spark, I think it writes in UTC adjusted. But once this framework is working it shouldn't be much effort to add that support in a followup PR.

velox/dwio/parquet/reader/TimestampColumnReader.h Outdated Show resolved Hide resolved
@yingsu00
Copy link
Collaborator

@mskapilks Hi Kapil, Hi will you be able to rebase and address the comments? There're conflicts.

@yingsu00
Copy link
Collaborator

yingsu00 commented Apr 26, 2024

cc @Yuhta

@mskapilks
Copy link
Author

@mskapilks Hi Kapil, Hi will you be able to rebase and address the comments? There're conflicts.

Yes will update the PR soon

// Use int128_t as a workaroud. Timestamp type in Velox is comprised of an
// int64_t seconds_ field and a uint64_t nanos_ field, a total of 16-byte
// length
prepareRead<int128_t>(offset, rows, nullptr);
Copy link
Collaborator

@yingsu00 yingsu00 Jul 5, 2024

Choose a reason for hiding this comment

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

@mskapilks I think a follow up PR would be better if this implementation doesn't meet any problem in using it

@mskapilks
Copy link
Author

@mskapilks @Yuhta I think we should merge this PR before Support for dictionary encoded INT96 timestamp in parquet files #4680. This PR is a more generic implementation, while 4680 only worked for dictionary encodings. Also 4680 needs update to read the unit from the column Parquet logical type, not through a hive config. @mskapilks Can you please address the comment and rebase? Thanks!

Thanks for review. I have rebased again and resolved comments.

@yingsu00
Copy link
Collaborator

yingsu00 commented Jul 9, 2024

Thanks @mskapilks
@Yuhta Jimmy do you have more comments for this PR? If not can we merge it soon?

@@ -216,6 +216,9 @@ void SelectiveColumnReader::getIntValues(
VELOX_FAIL("Unsupported value size: {}", valueSize_);
}
break;
case TypeKind::TIMESTAMP:
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need this

Copy link
Author

Choose a reason for hiding this comment

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

This is needed as the output type is Timestamp

Copy link
Contributor

Choose a reason for hiding this comment

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

You cannot use getIntValues directly for Timestamp, you need to override TimestampColumnReader::getValues like here (seems you are trying to create the same file):

void getValues(RowSet rows, VectorPtr* result) override {

@@ -489,6 +496,7 @@ class PageReader {
std::unique_ptr<StringDecoder> stringDecoder_;
std::unique_ptr<BooleanDecoder> booleanDecoder_;
std::unique_ptr<DeltaBpDecoder> deltaBpDecoder_;
std::unique_ptr<TimestampDecoder> timestampDecoder_;
Copy link
Contributor

Choose a reason for hiding this comment

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

I would not put this at decoder level, this should be a normal int64 decoder and you should convert it into Timestamp in column reader

Copy link
Author

Choose a reason for hiding this comment

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

I have removed the TimestampDecoder class. And moved the logic to direct decoder.

@mskapilks
Copy link
Author

@Yuhta @yingsu00 Please review, updated the PR based on previous comments. Thanks

auto logicalType = type_->logicalType_.value();
if (logicalType.__isset.TIMESTAMP) {
if (!logicalType.TIMESTAMP.isAdjustedToUTC) {
VELOX_NYI("Only UTC adjusted Timestamp is supported.");
Copy link
Contributor

@liujiayi771 liujiayi771 Jul 17, 2024

Choose a reason for hiding this comment

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

Hi @mskapilks. After your PR is merged, I will submit a follow-up PR to support the case when isAdjustedToUTC=false because I have already added the timezone information to the Parquet reader.

Copy link
Author

Choose a reason for hiding this comment

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

@liujiayi771 Thats great, thanks 👍

@@ -216,6 +216,9 @@ void SelectiveColumnReader::getIntValues(
VELOX_FAIL("Unsupported value size: {}", valueSize_);
}
break;
case TypeKind::TIMESTAMP:
Copy link
Contributor

Choose a reason for hiding this comment

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

You cannot use getIntValues directly for Timestamp, you need to override TimestampColumnReader::getValues like here (seems you are trying to create the same file):

void getValues(RowSet rows, VectorPtr* result) override {

@@ -221,5 +221,4 @@ Timestamp fromDatetime(int64_t daysSinceEpoch, int64_t microsSinceMidnight);
/// Returns the number of days since epoch for a given timestamp and optional
/// time zone.
int32_t toDate(const Timestamp& timestamp, const date::time_zone* timeZone_);

Copy link
Contributor

Choose a reason for hiding this comment

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

Just leave the file unchanged

@@ -92,7 +94,24 @@ class DirectDecoder : public IntDecoder<isSigned> {
} else if constexpr (std::is_same_v<
typename Visitor::DataType,
int128_t>) {
toSkip = visitor.process(super::template readInt<int128_t>(), atEnd);
if (precision_.has_value()) {
Copy link
Contributor

@Yuhta Yuhta Jul 17, 2024

Choose a reason for hiding this comment

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

This does not look correct. As far as I see you should not need to change anything at decoder level (the int96 implementation is a little hacky and you should not follow it), just use it as the plain vanilla int64_t decoder, and all these conversion should happen inside TimestampColumnReader (or rename it to something else to avoid name clash with the one reading int96).

Copy link
Author

Choose a reason for hiding this comment

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

I also have PR for timestamp filter support for INT64. So I did try moving the conversion inside TimestampColumnReader but it was causing issue with timestamp filter. As the filtering was happening with int64 values in decoder. I was getting testInt64() is not supported. Maybe I missed something.

Let me wait for the INT96 pr to go in first (since that is almost ready), as some effort is common in both to avoid conflicts

Copy link
Contributor

Choose a reason for hiding this comment

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

You can process the filter in column reader (there is no way to handle it in int decoder, different format has different timestamp representation), see example in

void SelectiveTimestampColumnReader::processFilter(

Copy link
Author

@mskapilks mskapilks Aug 7, 2024

Choose a reason for hiding this comment

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

Updated change based on the suggestion. Let me know your input on this.
Will try to merge both classes INT64, INT96 readers if feasible.

@mskapilks
Copy link
Author

@yingsu00 @liujiayi771 @Yuhta Can you please take a look.

velox/dwio/parquet/reader/TimestampColumnReader.h Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/ParquetReader.cpp Outdated Show resolved Hide resolved
velox/dwio/parquet/reader/ParquetReader.cpp Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

Added the tests. @Yuhta @zhli1142015

But not able to make it worked.
The null buffer I am getting after intezers are read seems to be not correct.

Error

Value of: result->equalValueAt(expectedColumn, i, expectedRow)
  Actual: false
Expected: true
Content mismatch at 3073 column 0: expected: null actual: 2015-06-02T06:50:18.000035000
Google Test trace:

As we want to process timestamp filter in TimestampInt64ColumnReader, i am passing AlwaysTrue filter to get all intezer values from parquet. In some case disabling fastpath worked but not in all cases.

Any thought where should I look, how to figure out the issue?

Copy link
Author

Choose a reason for hiding this comment

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

Most likely issue here?

image

Copy link
Author

Choose a reason for hiding this comment

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

@Yuhta Hi, can you suggest any workaround on this?
Thanks

Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably something wrong in the way you use readerNulls and resultNulls and row numbers in readHelper. The always true filter should be fine.

velox/dwio/parquet/reader/TimestampColumnReader.h Outdated Show resolved Hide resolved
readCommon<IntegerColumnReader, true>(rows);

auto tsValues =
AlignedBuffer::allocate<Timestamp>(numValues_, &memoryPool_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we do it in-place instead of allocating new buffer for each batch?

@j7nhai
Copy link

j7nhai commented Aug 19, 2024

@mskapilks Hi, The unit tests of commit 6081415 run fine on my machine. But the unit tests of commit 9166ff6 run fail on my machine. Can you provided some information for how to debug?

[ RUN      ] ParquetTableScanTest.sessionTimezone
[       OK ] ParquetTableScanTest.sessionTimezone (11 ms)
[ RUN      ] ParquetTableScanTest.timestampFilter
[       OK ] ParquetTableScanTest.timestampFilter (13 ms)
[ RUN      ] ParquetTableScanTest.timestampPrecisionMicrosecond
[       OK ] ParquetTableScanTest.timestampPrecisionMicrosecond (5 ms)
[ RUN      ] ParquetTableScanTest.timestampINT64millis
*** Aborted at 1724058475 (Unix time, try 'date -d @1724058475') ***
*** Signal 11 (SIGSEGV) (0x0) received by PID 1322556 (pthread TID 0x7fcd795ec700) (linux TID 1322979) (code: address not mapped to object), stack trace: ***
(error retrieving stack trace)
Segmentation fault (core dumped)

@mskapilks
Copy link
Author

@mskapilks Hi, The unit tests of commit 6081415 run fine on my machine. But the unit tests of commit 9166ff6 run fail on my machine. Can you provided some information for how to debug?

[ RUN      ] ParquetTableScanTest.sessionTimezone
[       OK ] ParquetTableScanTest.sessionTimezone (11 ms)
[ RUN      ] ParquetTableScanTest.timestampFilter
[       OK ] ParquetTableScanTest.timestampFilter (13 ms)
[ RUN      ] ParquetTableScanTest.timestampPrecisionMicrosecond
[       OK ] ParquetTableScanTest.timestampPrecisionMicrosecond (5 ms)
[ RUN      ] ParquetTableScanTest.timestampINT64millis
*** Aborted at 1724058475 (Unix time, try 'date -d @1724058475') ***
*** Signal 11 (SIGSEGV) (0x0) received by PID 1322556 (pthread TID 0x7fcd795ec700) (linux TID 1322979) (code: address not mapped to object), stack trace: ***
(error retrieving stack trace)
Segmentation fault (core dumped)

Fixed this, missed a null check

Resolve comments

Fix build

PR comments

Remove reinterpret_cast

Fix compile

PR comments

Update parquet files

Refactor

Fix formatting

Fix compile

PR comment

Fix decimal tests

Typo

Remove timestamp decoder

Remove white space

Remove import
Tmp
Add E2E test
},
true,
{"timestamp_val_0", "timestamp_val_1"},
1);
Copy link
Author

Choose a reason for hiding this comment

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

Will update to 20 once issue is resolved

@majetideepak
Copy link
Collaborator

@mskapilks can you please sign the CLA? Thanks.

@mskapilks
Copy link
Author

@mskapilks can you please sign the CLA? Thanks.

Done

@@ -50,6 +50,11 @@ class DataSetBuilder {
// groups. Tests skipping row groups based on row group stats.
DataSetBuilder& withRowGroupSpecificData(int32_t numRowsPerGroup);

DataSetBuilder& adjustTimestampToPrecision(TimestampPrecision precision);
void adjustTimestampToPrecision(
VectorPtr batch,
Copy link
Contributor

Choose a reason for hiding this comment

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

VectorPtr& batch

case common::FilterKind::kAlwaysTrue:
// Simply add all rows to output.
for (vector_size_t i = 0; i < numValues_; i++) {
addOutputRow(rows[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think you need to do this, we use inputRows_ in case there is no filter

@yingsu00
Copy link
Collaborator

@mskapilks Can you please address the comments and rebase? Thanks!

@majetideepak
Copy link
Collaborator

@mskapilks Do you mind if I push to this PR? We can work on this together. Thanks.

@mskapilks
Copy link
Author

@mskapilks Do you mind if I push to this PR? We can work on this together. Thanks.

Sure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants