-
Notifications
You must be signed in to change notification settings - Fork 13.8k
[FLINK-17668][table] Fix shortcomings in new data structures #12130
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
Conversation
|
Thanks a lot for your contribution to the Apache Flink project. I'm the @flinkbot. I help the community Automated ChecksLast check on commit 3ce9117 (Wed May 13 13:54:46 UTC 2020) Warnings:
Mention the bot in a comment to re-run the automated checks. Review Progress
Please see the Pull Request Review Guide for a full explanation of the review process. DetailsThe Bot is tracking the review progress through labels. Labels are applied according to the order of the review items. For consensus, approval by a Flink committer of PMC member is required Bot commandsThe @flinkbot bot supports the following commands:
|
dawidwys
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, I would be really interested to see how this affects performance.
| case STRUCTURED_TYPE: | ||
| case RAW: | ||
| // long, double is 8 bytes. | ||
| // It store the length and offset of variable-length part when type is string, map, etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // It store the length and offset of variable-length part when type is string, map, etc. | |
| // It stores the length and offset of the variable-length part for types such as string, map, etc. |
| GenericArrayData that = (GenericArrayData) o; | ||
| return size == that.size && | ||
| isPrimitiveArray == that.isPrimitiveArray && | ||
| Arrays.deepEquals(new Object[] {array}, new Object[]{that.array}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to use Arrays.deepEquals for GenericRowData.equals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I think we need that. GenericRowData may contains byte[] which should use Arrays.deepEquals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I revisited all GenericXXX classes again for hashCode and equals.
wuchong
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the great work! The changes look good to me. Except GenericRowData#equals/hashcode mentioned by Benchao.
I'm +1 to use the ElementGetter and FieldGetter. But, we should still encourage deveploers to use the getXxx because this can avoid boxing and unboxing. At least, connectors in Flink repository should use getXxxx. That's also why we create FLINK-17528.
| * @return the element object at the specified position in this array data | ||
| * @deprecated Use {@link #createElementGetter(LogicalType)} for a more efficient hot path. | ||
| */ | ||
| @Deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you create an issue to use createElementGetter to replace get utility and remove this method? I think we should provide a clean interface before release.
|
Btw, I have a simple benchmark to compare the performance of get utitilty and the get accessor. The result shows get accessor is slightly worse than get utility: Here is the code, maybe the virtual function call is the reason. Or I did something wrong and missed something. |
| throw new IllegalArgumentException(); | ||
| } | ||
| if (!elementType.isNullable()) { | ||
| return elementGetter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the nullable attribute reliable now ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I have to say it's tricky to guarantee the NOT NULL attributes in runtime, especially in streaming. AFAIK, StreamExecExpand will produce null values even if the field is NOT NULL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of locations ignore nullability. We should gradually fix this. By default a type is nullable, so the check is performed in most of the cases. The implementation of the method is correct (given its input parameters), if there is a problem it should be the callers task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think we should be cautious here. As you said, most of the cases are nullable, so we don't get much performance improvement from this. However, it may occure unexpected bugs if it is called in planner. We can add a TODO on this. When we fix all the nullable problem, we can update this without breaking compatibility.
if there is a problem it should be the callers task.
The problem is planner will also call this method, and I'm sure there are cases that null values exist in NOT NULL fields, then an exception will happen. This will be a bug then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no strong guarantee that our runtime would not generate null value for a not null field based on current codebase, and if there was, the bug would probably hard to trace out.
How much performance can we gain with the type nullable short-cut check ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far only the converters will call this method. Let's fix upstream bugs gradually, once code is updated to this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not only about performance but also correctness. A caller assumes the behavior when passing a nullable/not nullable type. It is harder to trace where a null comes from than a method that throws a hard exception when it encounters an unexpected null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nullble problems are known issues but can't be fixed easily, they may need major rework (e.g. Expand node). I don't think we should let the queries failed.
If we want to keep this logic, then I would suggest only use this method in connectors, because we guarantee the NOT NULL constraint when writing values to sink (table.exec.sink.not-null-enforcer). But in planner, we shouldn't use this method now, because the NOT NULL information of field type is not trusted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, we can add this information to the issue that removes the RowData.get method. So far the new method is only used in converters.
|
Thanks for sharing your benchmark results @wuchong. I also performed additional benchmarks. What I didn't like in your branch is the little data size, I don't know if the JIT compiler can already kick in. I tried to perform a more realistic benachmark on the current branch. See: The results didn't make a big difference: |
| return Arrays.deepEquals(map.keySet().toArray(), that.map.keySet().toArray()) && | ||
| Arrays.deepEquals(map.values().toArray(), that.map.values().toArray()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this. Arrays.deepEquals will compare elements in order. However, map.keySet() doesn't guarentee order. Maybe we can simply use Objects.equals(map, that.map) here. Because byte[] shouldn't be as map key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, we can do the key check differently. But for values we need to include byte[] as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. Maybe we need to foreach entries and get values from another map using the entry key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I will just copy the implementation of HashMap.equals/HashMap.hashCode and replace the equals call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
wuchong
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updating. LGTM.
What is the purpose of the change
This fixes the following shortcomings in the new data structures:
RawValueDatacannot be created from bytes.So far these changes are not used. This will change in FLINK-16999.
Brief change log
Adds
hashCode/equalsand specialized runtime instances by type for getting and setting values.Verifying this change
Tests are following in FLINK-16999.
Does this pull request potentially affect one of the following parts:
@Public(Evolving): yesDocumentation