-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Add table and column information to query errors #14388
base: master
Are you sure you want to change the base?
Add table and column information to query errors #14388
Conversation
+ " LIMIT 200 " | ||
+ ") " | ||
+ " GROUP BY time_col "; | ||
|
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 think it might be better to add test function to registry but make it work only if a system flag is set, e.g. enableTestFunctions, than to rely on fragile mocks.
* under the License. | ||
*/ | ||
package org.apache.pinot.core.common; | ||
|
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.
This one's a just a simple exception that makes it possible to fetch important context information spread throught the stack.
I'd be good to discuss how to integrate the approach with other exceptions and re-organize exceptions thrown by the engine. There are many more places that don't report conversion errors properly (e.g. plenty of parse calls for function arguments that won't report which argument they failed for).
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 think this is a really nice improvement! IMO we could add similar custom runtime exceptions for different classes of processing errors as a subsequent enhancement. Although in that case it might be nice to name this class something more specific than PinotRuntimeException
, WDYT?
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 completely agree we need to have our own family of exceptions, but I think it will need more discussion.
My initial suggestion is to reserve PinotRuntimeException
name for a marker exception that extends RuntimeException
, then add another for queries (something like QueryException
) and then
---
config:
look: handDrawn
theme: neutral
---
classDiagram
RuntimeException
note for RuntimeException "From JDK"
PinotRuntimeException
note for PinotRuntimeException "All new Pinot exceptions"
QException
note for QException "All new Pinot exceptions"
QException <|-- ParsingQException
QException <|-- OptimizationQException
ExecutionQException
note for ExecutionQException "Exceptions thrown by Operators"
RuntimeException <|-- PinotRuntimeException
PinotRuntimeException <|-- QException
QException <|-- ExecutionQException
ExecutionQException <|-- ColumnExecutionQException
class ExecutionQException {
+stage
}
class ColumnExecutionQException {
+table
+column
}
note for ColumnExecutionQException "Execution exception dealing with a column"
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #14388 +/- ##
============================================
+ Coverage 61.75% 63.76% +2.01%
- Complexity 207 1555 +1348
============================================
Files 2436 2662 +226
Lines 133233 146118 +12885
Branches 20636 22350 +1714
============================================
+ Hits 82274 93173 +10899
- Misses 44911 46058 +1147
- Partials 6048 6887 +839
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
* under the License. | ||
*/ | ||
package org.apache.pinot.core.common; | ||
|
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 think this is a really nice improvement! IMO we could add similar custom runtime exceptions for different classes of processing errors as a subsequent enhancement. Although in that case it might be nice to name this class something more specific than PinotRuntimeException
, WDYT?
StringBuilder message = new StringBuilder("Error when processing"); | ||
if (_tableName != null) { | ||
message.append(" ").append(_tableName); | ||
} | ||
if (_columnName != null) { | ||
if (_tableName != null) { | ||
message.append("."); | ||
} else { | ||
message.append(" "); | ||
} | ||
message.append(_columnName); | ||
} | ||
message.append(": "); | ||
message.append(super.getMessage()); | ||
|
||
return message.toString(); |
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.
Might be clearer to change this to something like Error when processing column "abc" in table "xyz"
?
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'm open to suggestions. We've to keep in mind that table could actually mean alias and column - an expression - e.g. max(x)
so it should be generic but still readable :).
I guess we can add more useful bits of context data.
@@ -127,6 +128,9 @@ public float[] getFloatValuesSV() { | |||
try (InvocationScope scope = Tracing.getTracer().createScope(ProjectionBlockValSet.class)) { | |||
recordReadValues(scope, DataType.FLOAT, true); | |||
return _dataBlockCache.getFloatValuesForSVColumn(_column); | |||
} catch (RuntimeException re) { | |||
//add column information, then later enrich it with table name |
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.
then later enrich it with table name
I presume this means we don't have access to the table name information in this class currently?
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 think table name was missing when I debugged some cases.
Let me double check .
@@ -135,6 +139,9 @@ public double[] getDoubleValuesSV() { | |||
try (InvocationScope scope = Tracing.getTracer().createScope(ProjectionBlockValSet.class)) { | |||
recordReadValues(scope, DataType.DOUBLE, true); | |||
return _dataBlockCache.getDoubleValuesForSVColumn(_column); | |||
} catch (RuntimeException re) { |
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.
Why is the error handling only added for float and double here?
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.
Probably because it's really hard to trigger those conversions in both engines :)
You're right, I'll add them and try to test with stub aggregate.
return ((Number) value).doubleValue(); | ||
} else { | ||
return Double.parseDouble(value.toString()); | ||
private static Double toDouble(Comparable<?> value, DataSource dataSource) { |
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 could just pass in the column name directly here I suppose?
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 guess so but I'm not sure how sensitive the place and tried to minimize potential overhead.
@@ -129,7 +129,11 @@ public int[] getIntValuesForSVColumn(String column) { | |||
intValues = new int[_length]; | |||
putValues(FieldSpec.DataType.INT, column, intValues); | |||
} | |||
_dataFetcher.fetchIntValues(column, _docIds, _length, intValues); | |||
try { |
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.
This is a nit: Have you considered adding the catch block in
pinot/pinot-core/src/main/java/org/apache/pinot/core/operator/docvalsets/ProjectionBlockValSet.java
Line 110 in 969bbf0
public int[] getIntValuesSV() { |
@@ -122,12 +123,13 @@ public void runJob() { | |||
// NOTE: We need to handle Error here, or the execution threads will die without adding the execution | |||
// exception into the query response, and the main thread might wait infinitely (until timeout) or | |||
// throw unexpected exceptions (such as NPE). | |||
PinotRuntimeException pe = PinotRuntimeException.create(t).withTableName(_queryContext.getTableName()); |
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.
One issue is that other types of exceptions like NPE may get missed when looking at stack traces. I know that the NPE will still appear in the stack trace etc. However as on-call our senses are trained to certain exception types in the top message. Is there an example of how the error looks like ? Maybe you can simulate by forcibly throwing an NPE ?
values[matchedRowId] = ((Number) _rows.get(rowId)[_colId]).longValue(); | ||
} else { | ||
values[matchedRowId] = Long.parseLong((String) _rows.get(rowId)[_colId]); | ||
try { |
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 cant comment at the right line no. In line 136, column names maybe useful in Precondition checks as well. I dont know how often they are triggered though.
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 name PinotRuntimeException
is too generic and therefore cannot be used to identify an error associated with a column during query execution. We need to think about other areas of the code like ingeston or system management that can also fail with runtime exceptions.
I'm not asking to create the whole exception hierarchy I suggested in https://github.com/apache/pinot/pull/14388/files#r1829241167, but at least we need to rename the exception to something like ColumnExecutionQueryException (or some acronym like ColExecQException).
At the moment exceptions thrown during query execution are often missing basic table and column information, making it hard diagnose issues.
For example, if dat is a string column containing dates then issuing following query :
might return
NumberFormatException: For input string: "2021-10-01T09:01:00-0800"
.This PR adds table/alias and column/expression information to conversion errors, e.g.
Error when processing table.dat: NumberFormatException: For input string: "2021-10-01T09:01:00-0800".