You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by ja...@apache.org on 2015/04/15 17:56:03 UTC
[2/6] drill git commit: DRILL-2675: Implement a subset of User
Exceptions to improve how errors are reported to the user
DRILL-2675: Implement a subset of User Exceptions to improve how errors are reported to the user
Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/99b6d0e6
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/99b6d0e6
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/99b6d0e6
Branch: refs/heads/master
Commit: 99b6d0e6d2fc6dea165e9e809db4fc63d9a70d3a
Parents: 859e6a8
Author: adeneche <ad...@gmail.com>
Authored: Thu Apr 9 09:30:33 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Wed Apr 15 07:02:10 2015 -0700
----------------------------------------------------------------------
.../common/exceptions/DrillRemoteException.java | 44 ++
.../common/exceptions/DrillUserException.java | 204 ++++++++++
.../drill/common/exceptions/ErrorHelper.java | 186 +++++++++
.../common/exceptions/UserExceptionContext.java | 148 +++++++
.../exceptions/TestDrillUserException.java | 130 ++++++
.../apache/drill/exec/client/DrillClient.java | 5 +-
.../exec/client/PrintingResultsListener.java | 9 +-
.../apache/drill/exec/ops/FragmentContext.java | 17 +-
.../drill/exec/physical/impl/ScreenCreator.java | 2 -
.../drill/exec/planner/sql/DrillSqlWorker.java | 18 +-
.../drill/exec/rpc/CoordinationQueue.java | 3 +-
.../drill/exec/rpc/RemoteRpcException.java | 43 --
.../java/org/apache/drill/exec/rpc/RpcBus.java | 12 +-
.../drill/exec/rpc/user/QueryResultHandler.java | 28 +-
.../exec/rpc/user/UserResultsListener.java | 4 +-
.../drill/exec/server/rest/QueryWrapper.java | 6 +-
.../exec/store/easy/json/JSONRecordReader.java | 28 +-
.../org/apache/drill/exec/work/ErrorHelper.java | 229 -----------
.../apache/drill/exec/work/foreman/Foreman.java | 17 +-
.../drill/exec/work/foreman/QueryManager.java | 4 +-
.../work/foreman/SqlUnsupportedException.java | 4 +-
.../work/fragment/AbstractStatusReporter.java | 14 +-
.../exec/work/fragment/FragmentExecutor.java | 13 +-
.../exec/work/fragment/StatusReporter.java | 3 +-
.../java/org/apache/drill/BaseTestQuery.java | 11 +-
.../org/apache/drill/SingleRowListener.java | 6 +-
.../java/org/apache/drill/TestBugFixes.java | 6 +-
.../apache/drill/TestDisabledFunctionality.java | 140 +++----
.../java/org/apache/drill/TestStarQueries.java | 6 +-
.../java/org/apache/drill/TestUnionAll.java | 8 +-
.../exec/server/TestDrillbitResilience.java | 22 +-
.../store/parquet/ParquetResultListener.java | 8 +-
.../store/parquet/TestParquetPhysicalPlan.java | 4 +-
.../java/org/apache/drill/jdbc/DrillCursor.java | 4 +-
.../drill/jdbc/impl/DrillResultSetImpl.java | 8 +-
.../drill/exec/proto/SchemaUserBitShared.java | 4 +-
.../apache/drill/exec/proto/UserBitShared.java | 408 +++++++++++++------
.../drill/exec/proto/beans/DrillPBError.java | 58 ++-
protocol/src/main/protobuf/UserBitShared.proto | 14 +-
39 files changed, 1268 insertions(+), 610 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java b/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
new file mode 100644
index 0000000..7b707a5
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+
+/**
+ * Wraps a DrillPBError object so we don't need to rebuilt it multiple times when sending it to the client. It also
+ * gives access to the original exception className and message.
+ */
+public class DrillRemoteException extends DrillUserException {
+
+ private final DrillPBError error;
+
+ public DrillRemoteException(DrillPBError error) {
+ super(null, "Drill Remote Exception", null);
+ this.error = error;
+ }
+
+ @Override
+ public String getMessage() {
+ return error.getMessage(); // we don't want super class to generate the error message
+ }
+
+ @Override
+ public DrillPBError getOrCreatePBError(boolean verbose) {
+ return error;
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java b/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
new file mode 100644
index 0000000..73718ae
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
@@ -0,0 +1,204 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+
+public class DrillUserException extends DrillRuntimeException {
+
+ /**
+ * Builder class for DrillUserException. You can wrap an existing exception, in this case it will first check if
+ * this exception is, or wraps, a DrillUserException. If it does then the builder will use the user exception as it is
+ * (it will ignore the message passed to the constructor) and will add any additional context information to the
+ * exception's context
+ */
+ public static class Builder extends UserExceptionContext {
+
+ private final Throwable cause;
+ private final String message;
+ private final DrillPBError.ErrorType errorType;
+
+ private final DrillUserException uex;
+
+ /**
+ * builds a system error that wrap an existing exception. If the exception is, or wraps, a DrillUserException it
+ * won't be converted to a system error.
+ *
+ * We should never need to call this, it will be done automatically before the exception is sent to the client.
+ *
+ * @param cause exception to wrap into a system error
+ */
+ Builder(Throwable cause) {
+ this(DrillPBError.ErrorType.SYSTEM, cause);
+ }
+
+ /**
+ * builds a new user exception of the specified type, with a defined error message
+ *
+ * @param errorType user exception's type
+ * @param format A format string
+ * @param args Arguments referenced by the format specifiers in the format string.
+ */
+ public Builder(DrillPBError.ErrorType errorType, String format, Object... args) {
+ this(errorType, null, format, args);
+ }
+
+ /**
+ * wraps an existing exception inside a user exception. If the exception is, or wraps, a user exception
+ * already, the builder will extract the original user exception and use it instead. If the builder creates a new
+ * user exception it will use the passed exception message, otherwise the builder won't change the message of the
+ * exception
+ *
+ * @param errorType user exception type that should be created if the passed exception isn't, or doesn't wrap a user exception
+ * @param cause exception to wrap inside a user exception
+ */
+ public Builder(DrillPBError.ErrorType errorType, Throwable cause) {
+ this(errorType, cause, null);
+ }
+
+ /**
+ * wraps an existing exception inside a user exception. If the exception is, or wraps, a user exception
+ * already, the builder will extract the original user exception and use it instead.
+ * If the builder creates a new user exception it will use the passed exception message, otherwise the builder
+ * won't change the message of the exception and will add the passed message to the context instead
+ *
+ * @param errorType user exception type that should be created if the passed exception isn't, or doesn't wrap a user exception
+ * @param cause exception to wrap inside a user exception
+ * @param format A format string
+ * @param args Arguments referenced by the format specifiers in the format string.
+ */
+ public Builder(DrillPBError.ErrorType errorType, Throwable cause, String format, Object... args) {
+ super(ErrorHelper.getExceptionContextOrNew(cause));
+ this.cause = cause;
+
+ if (format == null) {
+ this.message = cause != null ? cause.getMessage() : null;
+ } else {
+ this.message = String.format(format, args);
+ }
+
+ //TODO handle the improbable case where cause is a SYSTEM exception ?
+ uex = ErrorHelper.findWrappedUserException(cause);
+ if (uex != null) {
+ this.errorType = null;
+ if (format != null) {
+ // we won't change the exception's message, so add it to the context
+ add(this.message);
+ }
+ } else {
+ // we will create a new user exception
+ this.errorType = errorType;
+ }
+ }
+
+ public DrillUserException build() {
+
+ if (uex != null) {
+ return uex;
+ }
+
+ return new DrillUserException(this);
+ }
+ }
+
+ private final DrillPBError.ErrorType errorType;
+
+ private final UserExceptionContext context;
+
+ protected DrillUserException(DrillPBError.ErrorType errorType, String message, Throwable cause) {
+ super(message, cause);
+
+ this.errorType = errorType;
+ this.context = new UserExceptionContext();
+ }
+
+ private DrillUserException(Builder builder) {
+ super(builder.message, builder.cause);
+ this.errorType = builder.errorType;
+ this.context = builder;
+ }
+
+ public UserExceptionContext getContext() {
+ return context;
+ }
+
+ /**
+ * generates the message that will be displayed to the client without the stack trace.
+ *
+ * @return non verbose error message
+ */
+ @Override
+ public String getMessage() {
+ return generateMessage();
+ }
+
+ /**
+ *
+ * @return the error message that was passed to the builder
+ */
+ public String getOriginalMessage() {
+ return super.getMessage();
+ }
+
+ /**
+ * generates the message that will be displayed to the client. The message also contains the stack trace.
+ *
+ * @return verbose error message
+ */
+ public String getVerboseMessage() {
+ return generateMessage() + "\n\n" + ErrorHelper.buildCausesMessage(getCause());
+ }
+
+ /**
+ * returns or creates a DrillPBError object corresponding to this user exception.
+ *
+ * @param verbose should the error object contain the verbose error message ?
+ * @return protobuf error object
+ */
+ public DrillPBError getOrCreatePBError(boolean verbose) {
+ String message = verbose ? getVerboseMessage() : getMessage();
+
+ DrillPBError.Builder builder = DrillPBError.newBuilder();
+ builder.setErrorType(errorType);
+ builder.setErrorId(context.getErrorId());
+ if (context.getEndpoint() != null) {
+ builder.setEndpoint(context.getEndpoint());
+ }
+ builder.setMessage(message);
+
+ if (getCause() != null) {
+ // some unit tests use this information to make sure a specific exception was thrown in the server
+ builder.setException(ErrorHelper.getWrapper(getCause()));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Generates a user error message that has the following structure:
+ * ERROR TYPE: ERROR_MESSAGE
+ * CONTEXT
+ * [ERROR_ID on DRILLBIT_IP:DRILLBIT_USER_PORT]
+ *
+ * @return generated user error message
+ */
+ private String generateMessage() {
+ return errorType + " ERROR: " + super.getMessage() + "\n" +
+ context.generateContextMessage();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java b/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
new file mode 100644
index 0000000..1dc4eb5
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.ExceptionWrapper;
+import org.apache.drill.exec.proto.UserBitShared.StackTraceElementWrapper;
+
+import java.util.regex.Pattern;
+
+/**
+ * Utility class that handles error message generation from protobuf error objects.
+ */
+public class ErrorHelper {
+
+ private final static Pattern IGNORE= Pattern.compile("^(sun|com\\.sun|java).*");
+
+ /**
+ * Wraps the exception into a SYSTEM ERROR if it's not already a DrillUserException, or if it's not wrapping a
+ * DrillUserException
+ * @param ex exception to wrap
+ * @return user exception
+ */
+ public static DrillUserException wrap(final Throwable ex) {
+ return new DrillUserException.Builder(ex).build();
+ }
+
+ /**
+ * returns the user exception context for DrillUserExceptions(s) even if they are wrapped multiple times. If no
+ * DrillUserException is found, it will create a new one.
+ * This is useful if we want to add context to user exception before re-throwing it. For all other exception the
+ * context will be discarded.
+ *
+ * @param ex exception we are trying to get the context for
+ * @return user exception context
+ */
+ public static UserExceptionContext getExceptionContextOrNew(final Throwable ex) {
+ DrillUserException uex = findWrappedUserException(ex);
+ if (uex != null) {
+ //TODO if uex is SYSTEM exception the calling code will be able to add context information to it. Do we want this ?
+ return uex.getContext();
+ }
+
+ return new UserExceptionContext();
+ }
+
+ static String buildCausesMessage(final Throwable t) {
+
+ StringBuilder sb = new StringBuilder();
+ Throwable ex = t;
+ boolean cause = false;
+ while(ex != null){
+
+ sb.append(" ");
+
+ if(cause){
+ sb.append("Caused By ");
+ }
+
+ sb.append("(");
+ sb.append(ex.getClass().getCanonicalName());
+ sb.append(") ");
+ sb.append(ex.getMessage());
+ sb.append("\n");
+
+ for(StackTraceElement st : ex.getStackTrace()){
+ sb.append(" ");
+ sb.append(st.getClassName());
+ sb.append('.');
+ sb.append(st.getMethodName());
+ sb.append("():");
+ sb.append(st.getLineNumber());
+ sb.append("\n");
+ }
+ cause = true;
+
+ if(ex.getCause() != null && ex.getCause() != ex){
+ ex = ex.getCause();
+ } else {
+ ex = null;
+ }
+ }
+
+ return sb.toString();
+ }
+
+ static ExceptionWrapper getWrapper(Throwable ex) {
+ return getWrapperBuilder(ex).build();
+ }
+
+ private static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex) {
+ return getWrapperBuilder(ex, false);
+ }
+
+ private static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex, boolean includeAllStack) {
+ ExceptionWrapper.Builder ew = ExceptionWrapper.newBuilder();
+ if(ex.getMessage() != null) {
+ ew.setMessage(ex.getMessage());
+ }
+ ew.setExceptionClass(ex.getClass().getCanonicalName());
+ boolean isHidden = false;
+ StackTraceElement[] stackTrace = ex.getStackTrace();
+ for(int i = 0; i < stackTrace.length; i++){
+ StackTraceElement ele = ex.getStackTrace()[i];
+ if(include(ele, includeAllStack)){
+ if(isHidden){
+ isHidden = false;
+ }
+ ew.addStackTrace(getSTWrapper(ele));
+ }else{
+ if(!isHidden){
+ isHidden = true;
+ ew.addStackTrace(getEmptyST());
+ }
+ }
+
+ }
+
+ if(ex.getCause() != null && ex.getCause() != ex){
+ ew.setCause(getWrapper(ex.getCause()));
+ }
+ return ew;
+ }
+
+ private static boolean include(StackTraceElement ele, boolean includeAllStack) {
+ return includeAllStack || !(IGNORE.matcher(ele.getClassName()).matches());
+ }
+
+ private static StackTraceElementWrapper.Builder getSTWrapper(StackTraceElement ele) {
+ StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
+ w.setClassName(ele.getClassName());
+ if(ele.getFileName() != null) {
+ w.setFileName(ele.getFileName());
+ }
+ w.setIsNativeMethod(ele.isNativeMethod());
+ w.setLineNumber(ele.getLineNumber());
+ w.setMethodName(ele.getMethodName());
+ return w;
+ }
+
+ private static StackTraceElementWrapper.Builder getEmptyST() {
+ StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
+ w.setClassName("...");
+ w.setIsNativeMethod(false);
+ w.setLineNumber(0);
+ w.setMethodName("...");
+ return w;
+ }
+
+ /**
+ * searches for a DrillUserException wrapped inside the exception
+ * @param ex exception
+ * @return null if exception is null or no DrillUserException was found
+ */
+ static DrillUserException findWrappedUserException(Throwable ex) {
+ if (ex == null) {
+ return null;
+ }
+
+ Throwable cause = ex;
+ while (!(cause instanceof DrillUserException)) {
+ if (cause.getCause() != null && cause.getCause() != cause) {
+ cause = cause.getCause();
+ } else {
+ return null;
+ }
+ }
+
+ return (DrillUserException) cause;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java b/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
new file mode 100644
index 0000000..ef7d486
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.CoordinationProtos;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Holds context information about a DrillUserException. We can add structured context information that will be used
+ * to generate the error message displayed to the client. We can also specify which context information should only
+ * be displayed in verbose mode
+ */
+public class UserExceptionContext {
+
+ private final String errorId;
+ private final List<String> contextList;
+
+ private CoordinationProtos.DrillbitEndpoint endpoint;
+
+ UserExceptionContext() {
+ errorId = UUID.randomUUID().toString();
+ contextList = new ArrayList<>();
+ }
+
+ UserExceptionContext(UserExceptionContext context) {
+ this.errorId = context.errorId;
+ this.contextList = context.contextList;
+ this.endpoint = context.endpoint;
+ }
+ /**
+ * adds a context line to the bottom of the context list
+ * @param context context line
+ */
+ public UserExceptionContext add(String context) {
+ contextList.add(context);
+ return this;
+ }
+
+ public UserExceptionContext add(CoordinationProtos.DrillbitEndpoint endpoint) {
+ //TODO should we allos the endpoint to change once set ?
+ this.endpoint = endpoint;
+ return this;
+ }
+
+ /**
+ * adds an int to the bottom of the context list
+ * @param context context prefix string
+ * @param value int value
+ */
+ public UserExceptionContext add(String context, long value) {
+ add(context + ": " + value);
+ return this;
+ }
+
+ /**
+ * adds a double to the bottom of the context list
+ * @param context context prefix string
+ * @param value double value
+ */
+ public UserExceptionContext add(String context, double value) {
+ add(context + ": " + value);
+ return this;
+ }
+
+ /**
+ * adds a context line at the top of the context list
+ * @param context context line
+ */
+ public UserExceptionContext push(String context) {
+ contextList.add(0, context);
+ return this;
+ }
+
+ /**
+ * adds an int at the top of the context list
+ * @param context context prefix string
+ * @param value int value
+ */
+ public UserExceptionContext push(String context, long value) {
+ push(context + ": " + value);
+ return this;
+ }
+
+ /**
+ * adds a double at the top of the context list
+ * @param context context prefix string
+ * @param value double value
+ */
+ public UserExceptionContext push(String context, double value) {
+ push(context + ": " + value);
+ return this;
+ }
+
+ String getErrorId() {
+ return errorId;
+ }
+
+ CoordinationProtos.DrillbitEndpoint getEndpoint() {
+ return endpoint;
+ }
+
+ /**
+ * generate a context message
+ * @return string containing all context information concatenated
+ */
+ String generateContextMessage() {
+ StringBuilder sb = new StringBuilder();
+
+ for (String context : contextList) {
+ sb.append(context).append("\n");
+ }
+
+ if (errorId != null || endpoint != null) {
+ // add identification infos
+ sb.append("\n[");
+ if (errorId != null) {
+ sb.append(errorId).append(" ");
+ }
+ if(endpoint != null) {
+ sb.append("on ")
+ .append(endpoint.getAddress())
+ .append(":")
+ .append(endpoint.getUserPort());
+ }
+ sb.append("]\n");
+ }
+
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java b/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
new file mode 100644
index 0000000..7b19d55
--- /dev/null
+++ b/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
@@ -0,0 +1,130 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test various use cases around creating user exceptions
+ */
+public class TestDrillUserException {
+
+ private Exception wrap(DrillUserException uex, int numWraps) {
+ Exception ex = uex;
+ for (int i = 0; i < numWraps; i++) {
+ ex = new Exception("wrap #" + (i+1), ex);
+ }
+
+ return ex;
+ }
+
+ // make sure system exceptions are created properly
+ @Test
+ public void testBuildSystemException() {
+ try {
+ throw new DrillUserException.Builder(new RuntimeException("this is an exception")).build();
+ } catch (DrillUserException ex) {
+ DrillPBError error = ex.getOrCreatePBError(true);
+ Assert.assertEquals(ErrorType.SYSTEM, error.getErrorType());
+ }
+ }
+
+ @Test
+ public void testBuildUserExceptionWithMessage() {
+ String message = "Test message";
+
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, message).build();
+ DrillPBError error = uex.getOrCreatePBError(false);
+
+ Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+ Assert.assertEquals(message, uex.getOriginalMessage());
+ }
+
+ @Test
+ public void testBuildUserExceptionWithCause() {
+ String message = "Test message";
+
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(message)).build();
+ DrillPBError error = uex.getOrCreatePBError(false);
+
+ // cause message should be used
+ Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+ Assert.assertEquals(message, uex.getOriginalMessage());
+ }
+
+ @Test
+ public void testBuildUserExceptionWithCauseAndMessage() {
+ String messageA = "Test message A";
+ String messageB = "Test message B";
+
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(messageA), messageB).build();
+ DrillPBError error = uex.getOrCreatePBError(false);
+
+ // passed message should override the cause message
+ Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+ Assert.assertFalse(error.getMessage().contains(messageA)); // messageA should not be part of the context
+ Assert.assertEquals(messageB, uex.getOriginalMessage());
+ }
+
+ @Test
+ public void testBuildUserExceptionWithUserExceptionCauseAndMessage() {
+ String messageA = "Test message A";
+ String messageB = "Test message B";
+
+ DrillUserException original = new DrillUserException.Builder(ErrorType.CONNECTION, messageA).build();
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, wrap(original, 5), messageB).build();
+
+ //builder should return the unwrapped original user exception and not build a new one
+ Assert.assertEquals(original, uex);
+
+ DrillPBError error = uex.getOrCreatePBError(false);
+ Assert.assertEquals(messageA, uex.getOriginalMessage());
+ Assert.assertTrue(error.getMessage().contains(messageB)); // messageA should be part of the context
+ }
+
+ @Test
+ public void testBuildUserExceptionWithFormattedMessage() {
+ String format = "This is test #%d";
+
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.CONNECTION, format, 5).build();
+ DrillPBError error = uex.getOrCreatePBError(false);
+
+ Assert.assertEquals(ErrorType.CONNECTION, error.getErrorType());
+ Assert.assertEquals(String.format(format, 5), uex.getOriginalMessage());
+ }
+
+ // make sure wrapped user exceptions are retrieved properly when calling ErrorHelper.wrap()
+ @Test
+ public void testWrapUserException() {
+ DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_READ, "this is a data read exception").build();
+
+ Exception wrapped = wrap(uex, 3);
+ Assert.assertEquals(uex, ErrorHelper.wrap(wrapped));
+ }
+
+ @Test
+ public void testEdgeCases() {
+ new DrillUserException.Builder(null).build();
+ new DrillUserException.Builder(ErrorType.DATA_WRITE, null).build().getOrCreatePBError(true);
+ new DrillUserException.Builder(ErrorType.DATA_WRITE, null).build().getOrCreatePBError(true);
+ new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(), null).build().getOrCreatePBError(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java b/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
index 579cf7d..6555cad 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
@@ -33,6 +33,7 @@ import java.util.Vector;
import io.netty.channel.EventLoopGroup;
import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.coord.ClusterCoordinator;
import org.apache.drill.exec.coord.zk.ZKClusterCoordinator;
@@ -307,9 +308,9 @@ public class DrillClient implements Closeable, ConnectionThrottle {
}
@Override
- public void submissionFailed(RpcException ex) {
+ public void submissionFailed(DrillUserException ex) {
// or !client.isActive()
- if (ex instanceof ChannelClosedException) {
+ if (ex.getCause() instanceof ChannelClosedException) {
if (reconnect()) {
try {
client.submitQuery(this, query);
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
index 98948af..a11cec0 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
@@ -22,6 +22,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import io.netty.buffer.DrillBuf;
import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.exec.client.QuerySubmitter.Format;
import org.apache.drill.exec.exception.SchemaChangeException;
import org.apache.drill.exec.memory.BufferAllocator;
@@ -29,7 +31,6 @@ import org.apache.drill.exec.memory.TopLevelAllocator;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryData;
import org.apache.drill.exec.record.RecordBatchLoader;
-import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.user.ConnectionThrottle;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -42,7 +43,7 @@ public class PrintingResultsListener implements UserResultsListener {
Format format;
int columnWidth;
BufferAllocator allocator;
- volatile Exception exception;
+ volatile DrillUserException exception;
QueryId queryId;
public PrintingResultsListener(DrillConfig config, Format format, int columnWidth) {
@@ -53,7 +54,7 @@ public class PrintingResultsListener implements UserResultsListener {
}
@Override
- public void submissionFailed(RpcException ex) {
+ public void submissionFailed(DrillUserException ex) {
exception = ex;
System.out.println("Exception (no rows returned): " + ex );
latch.countDown();
@@ -76,7 +77,7 @@ public class PrintingResultsListener implements UserResultsListener {
try {
loader.load(header.getDef(), data);
} catch (SchemaChangeException e) {
- submissionFailed(new RpcException(e));
+ submissionFailed(ErrorHelper.wrap(e));
}
switch(format) {
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
index da2229c..8c402e8 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
@@ -18,7 +18,6 @@
package org.apache.drill.exec.ops;
import com.google.common.base.Preconditions;
-import io.netty.buffer.ByteBuf;
import io.netty.buffer.DrillBuf;
import java.io.IOException;
@@ -30,6 +29,8 @@ import net.hydromatic.optiq.jdbc.SimpleOptiqSchema;
import org.apache.drill.common.DeferredException;
import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.common.exceptions.ExecutionSetupException;
import org.apache.drill.exec.exception.ClassTransformationException;
import org.apache.drill.exec.expr.ClassGenerator;
@@ -37,18 +38,14 @@ import org.apache.drill.exec.expr.CodeGenerator;
import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
import org.apache.drill.exec.memory.BufferAllocator;
import org.apache.drill.exec.memory.OutOfMemoryException;
-import org.apache.drill.exec.physical.impl.materialize.QueryWritableBatch;
import org.apache.drill.exec.planner.physical.PlannerSettings;
import org.apache.drill.exec.proto.BitControl.PlanFragment;
import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
import org.apache.drill.exec.proto.GeneralRPCProtos.Ack;
-import org.apache.drill.exec.record.FragmentWritableBatch;
-import org.apache.drill.exec.rpc.DrillRpcFuture;
import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.RpcOutcomeListener;
import org.apache.drill.exec.rpc.control.ControlTunnel;
-import org.apache.drill.exec.rpc.data.DataTunnel;
import org.apache.drill.exec.rpc.user.UserServer.UserClientConnection;
import org.apache.drill.exec.server.DrillbitContext;
import org.apache.drill.exec.server.options.FragmentOptionManager;
@@ -150,10 +147,16 @@ public class FragmentContext implements AutoCloseable, UdfUtilities {
public void fail(Throwable cause) {
final FragmentHandle fragmentHandle = fragment.getHandle();
+
+ DrillUserException dse = ErrorHelper.wrap(cause);
+ dse.getContext().add(getIdentity());
+
+ // log the error id
logger.error("Fragment Context received failure -- Fragment: {}:{}",
- fragmentHandle.getMajorFragmentId(), fragmentHandle.getMinorFragmentId(), cause);
+ fragmentHandle.getMajorFragmentId(), fragmentHandle.getMinorFragmentId(), dse);
+
setState(FragmentContextState.FAILED);
- deferredException.addThrowable(cause);
+ deferredException.addThrowable(dse);
}
public void cancel() {
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
index 6b3caf4..80cbd81 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
@@ -38,8 +38,6 @@ import com.google.common.base.Preconditions;
public class ScreenCreator implements RootCreator<Screen>{
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ScreenCreator.class);
-
-
@Override
public RootExec getRoot(FragmentContext context, Screen config, List<RecordBatch> children) throws ExecutionSetupException {
Preconditions.checkNotNull(children);
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
index b98778d..7892999 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
@@ -18,7 +18,6 @@
package org.apache.drill.exec.planner.sql;
import java.io.IOException;
-import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +29,7 @@ import net.hydromatic.optiq.tools.RelConversionException;
import net.hydromatic.optiq.tools.RuleSet;
import net.hydromatic.optiq.tools.ValidationException;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.ops.QueryContext;
import org.apache.drill.exec.physical.PhysicalPlan;
import org.apache.drill.exec.planner.cost.DrillCostBase;
@@ -44,6 +44,7 @@ import org.apache.drill.exec.planner.sql.handlers.SqlHandlerConfig;
import org.apache.drill.exec.planner.sql.parser.DrillSqlCall;
import org.apache.drill.exec.planner.sql.parser.SqlCreateTable;
import org.apache.drill.exec.planner.sql.parser.impl.DrillParserWithCompoundIdConverter;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
import org.apache.drill.exec.store.StoragePluginRegistry;
import org.apache.drill.exec.util.Pointer;
import org.apache.drill.exec.work.foreman.ForemanSetupException;
@@ -56,10 +57,8 @@ import org.eigenbase.relopt.RelTraitDef;
import org.eigenbase.relopt.hep.HepPlanner;
import org.eigenbase.relopt.hep.HepProgramBuilder;
import org.eigenbase.sql.SqlNode;
-import org.eigenbase.sql.parser.SqlAbstractParserImpl;
import org.eigenbase.sql.parser.SqlParseException;
import org.eigenbase.sql.parser.SqlParser;
-import org.eigenbase.sql.parser.SqlParserImplFactory;
public class DrillSqlWorker {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillSqlWorker.class);
@@ -105,8 +104,8 @@ public class DrillSqlWorker {
private RuleSet[] getRules(QueryContext context) {
StoragePluginRegistry storagePluginRegistry = context.getStorage();
RuleSet drillLogicalRules = DrillRuleSets.mergedRuleSets(
- DrillRuleSets.getDrillBasicRules(context),
- DrillRuleSets.getDrillUserConfigurableLogicalRules(context));
+ DrillRuleSets.getDrillBasicRules(context),
+ DrillRuleSets.getDrillUserConfigurableLogicalRules(context));
RuleSet drillPhysicalMem = DrillRuleSets.mergedRuleSets(
DrillRuleSets.getPhysicalRules(context),
storagePluginRegistry.getStoragePluginRuleSet());
@@ -152,14 +151,13 @@ public class DrillSqlWorker {
handler = new DefaultSqlHandler(config, textPlan);
}
- try{
+ try {
return handler.getPlan(sqlNode);
- }catch(ValidationException e){
- throw new QueryInputException("Failure validating SQL. " + e.getMessage(), e);
+ } catch(ValidationException e) {
+ String errorMessage = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
+ throw new DrillUserException.Builder(ErrorType.PARSE, e, errorMessage).build();
} catch (IOException | RelConversionException e) {
throw new QueryInputException("Failure handling SQL.", e);
}
-
}
-
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
index 0016d6a..ad5002e 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
@@ -23,6 +23,7 @@ import io.netty.channel.ChannelFuture;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import org.apache.drill.common.exceptions.DrillRemoteException;
import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
/**
@@ -150,7 +151,7 @@ public class CoordinationQueue {
// logger.debug("Updating failed future.");
try {
RpcOutcome<?> rpc = removeFromMap(coordinationId);
- rpc.setException(new RemoteRpcException(failure));
+ rpc.setException(new DrillRemoteException(failure));
} catch(Exception ex) {
logger.warn("Failed to remove from map. Not a problem since we were updating on failed future.", ex);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
deleted file mode 100644
index 14ea873..0000000
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.drill.exec.rpc;
-
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.work.ErrorHelper;
-
-public class RemoteRpcException extends RpcException{
- static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RemoteRpcException.class);
-
- private final DrillPBError failure;
-
- public RemoteRpcException(DrillPBError failure) {
- super(ErrorHelper.getErrorMessage(failure, false));
- this.failure = failure;
- }
-
- @Override
- public DrillPBError getRemoteError() {
- return failure;
- }
-
- @Override
- public boolean isRemote() {
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
index b974963..79232c9 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
@@ -30,9 +30,10 @@ import java.io.Closeable;
import java.util.Arrays;
import java.util.List;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.exec.proto.GeneralRPCProtos.RpcMode;
import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.work.ErrorHelper;
import com.google.common.base.Preconditions;
import com.google.protobuf.Internal.EnumLite;
@@ -193,8 +194,13 @@ public abstract class RpcBus<T extends EnumLite, C extends RemoteConnection> imp
try {
handle(connection, msg.rpcType, msg.pBody, msg.dBody, sender);
} catch(UserRpcException e){
- DrillPBError error = ErrorHelper.logAndConvertError(e.getEndpoint(), e.getUserMessage(), e, logger);
- OutboundRpcMessage outMessage = new OutboundRpcMessage(RpcMode.RESPONSE_FAILURE, 0, msg.coordinationId, error);
+ DrillUserException uex = ErrorHelper.wrap(e);
+ uex.getContext().add(e.getEndpoint());
+
+ logger.error("Unexpected Error while handling request message", e);
+
+ OutboundRpcMessage outMessage = new OutboundRpcMessage(RpcMode.RESPONSE_FAILURE, 0, msg.coordinationId,
+ uex.getOrCreatePBError(false));
if (RpcConstants.EXTRA_DEBUGGING) {
logger.debug("Adding message to outbound buffer. {}", outMessage);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
index a1be83b..a03e2c0 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
@@ -23,7 +23,9 @@ import io.netty.buffer.DrillBuf;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
-import org.apache.drill.exec.proto.UserBitShared;
+import org.apache.drill.common.exceptions.DrillRemoteException;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryResult;
import org.apache.drill.exec.proto.UserBitShared.QueryData;
@@ -107,8 +109,7 @@ public class QueryResultHandler {
if (isFailureResult) {
// Failure case--pass on via submissionFailed(...).
- String message = buildErrorMessage(queryResult);
- resultsListener.submissionFailed(new RpcException(message));
+ resultsListener.submissionFailed(new DrillRemoteException(queryResult.getError(0)));
// Note: Listener is removed in finally below.
} else if (isTerminalResult) {
// A successful completion/canceled case--pass on via resultArrived
@@ -116,7 +117,7 @@ public class QueryResultHandler {
try {
resultsListener.queryCompleted();
} catch ( Exception e ) {
- resultsListener.submissionFailed(new RpcException(e));
+ resultsListener.submissionFailed(ErrorHelper.wrap(e));
}
} else {
logger.warn("queryState {} was ignored", queryState);
@@ -157,7 +158,7 @@ public class QueryResultHandler {
// That releases batch if successful.
} catch ( Exception e ) {
batch.release();
- resultsListener.submissionFailed(new RpcException(e));
+ resultsListener.submissionFailed(ErrorHelper.wrap(e));
}
}
@@ -189,18 +190,9 @@ public class QueryResultHandler {
return resultsListener;
}
- protected String buildErrorMessage(QueryResult result) {
- StringBuilder sb = new StringBuilder();
- for (UserBitShared.DrillPBError error : result.getErrorList()) {
- sb.append(error.getMessage());
- sb.append("\n");
- }
- return sb.toString();
- }
-
private void failAll() {
for (UserResultsListener l : queryIdToResultsListenersMap.values()) {
- l.submissionFailed(new RpcException("Received result without QueryId"));
+ l.submissionFailed(ErrorHelper.wrap(new RpcException("Received result without QueryId")));
}
}
@@ -208,7 +200,7 @@ public class QueryResultHandler {
private ConcurrentLinkedQueue<QueryDataBatch> results = Queues.newConcurrentLinkedQueue();
private volatile boolean finished = false;
- private volatile RpcException ex;
+ private volatile DrillUserException ex;
private volatile UserResultsListener output;
private volatile ConnectionThrottle throttle;
@@ -253,7 +245,7 @@ public class QueryResultHandler {
}
@Override
- public void submissionFailed(RpcException ex) {
+ public void submissionFailed(DrillUserException ex) {
finished = true;
synchronized (this) {
if (output == null) {
@@ -284,7 +276,7 @@ public class QueryResultHandler {
@Override
public void failed(RpcException ex) {
- resultsListener.submissionFailed(ex);
+ resultsListener.submissionFailed(ErrorHelper.wrap(ex));
}
@Override
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
index 934a094..b9f742c 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
@@ -17,8 +17,8 @@
*/
package org.apache.drill.exec.rpc.user;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
-import org.apache.drill.exec.rpc.RpcException;
public interface UserResultsListener {
@@ -33,7 +33,7 @@ public interface UserResultsListener {
* {@link #dataArrived(QueryDataBatch, ConnectionThrottle) dataArrived()} throws an exception
* @param ex exception describing the cause of the failure
*/
- void submissionFailed(RpcException ex);
+ void submissionFailed(DrillUserException ex);
/**
* The query has completed (successsful completion or cancellation). The listener will not receive any other
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
index fbbf0b8..8415440 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
@@ -30,6 +30,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.client.DrillClient;
import org.apache.drill.exec.coord.ClusterCoordinator;
import org.apache.drill.exec.exception.SchemaChangeException;
@@ -37,7 +38,6 @@ import org.apache.drill.exec.memory.BufferAllocator;
import org.apache.drill.exec.proto.UserBitShared;
import org.apache.drill.exec.record.RecordBatchLoader;
import org.apache.drill.exec.record.VectorWrapper;
-import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.user.ConnectionThrottle;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -118,7 +118,7 @@ public class QueryWrapper {
private static class Listener implements UserResultsListener {
- private volatile Exception exception;
+ private volatile DrillUserException exception;
private final CountDownLatch latch = new CountDownLatch(1);
private final BufferAllocator allocator;
public final List<Map<String, String>> results = Lists.newArrayList();
@@ -129,7 +129,7 @@ public class QueryWrapper {
}
@Override
- public void submissionFailed(RpcException ex) {
+ public void submissionFailed(DrillUserException ex) {
exception = ex;
logger.error("Query Failed", ex);
latch.countDown();
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
index cc7cb83..91e0b21 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
@@ -22,7 +22,7 @@ import java.io.InputStream;
import java.util.List;
import com.google.common.collect.ImmutableList;
-import org.apache.drill.common.exceptions.DrillRuntimeException;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.common.exceptions.ExecutionSetupException;
import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.exec.ExecConstants;
@@ -30,6 +30,7 @@ import org.apache.drill.exec.memory.OutOfMemoryException;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.ops.OperatorContext;
import org.apache.drill.exec.physical.impl.OutputMutator;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
import org.apache.drill.exec.store.AbstractRecordReader;
import org.apache.drill.exec.store.dfs.DrillFileSystem;
import org.apache.drill.exec.store.easy.json.reader.CountingJsonReader;
@@ -90,14 +91,27 @@ public class JSONRecordReader extends AbstractRecordReader {
}
}
- protected void handleAndRaise(String msg, Exception e) {
- StringBuilder sb = new StringBuilder();
- sb.append(msg).append(" - In ").append(hadoopPath.toUri().getPath()).append(" parser was at record: ").append(recordCount+1);
+ protected void handleAndRaise(String suffix, Exception e) throws DrillUserException {
+
+ String message = e.getMessage();
+ int columnNr = -1;
+
if (e instanceof JsonParseException) {
- JsonParseException ex = JsonParseException.class.cast(e);
- sb.append(" column: ").append(ex.getLocation().getColumnNr());
+ JsonParseException ex = (JsonParseException) e;
+ message = ex.getOriginalMessage();
+ columnNr = ex.getLocation().getColumnNr();
+ }
+
+ DrillUserException.Builder builder = new DrillUserException.Builder(ErrorType.DATA_READ, e, "%s - %s", suffix, message);
+
+ // add context information
+ builder.add("Filename: " + hadoopPath.toUri().getPath());
+ builder.add("Record", recordCount + 1);
+ if (columnNr != -1) {
+ builder.add("Column", columnNr);
}
- throw new DrillRuntimeException(sb.toString(), e);
+
+ throw builder.build();
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
deleted file mode 100644
index 0773d6c..0000000
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.drill.exec.work;
-
-import java.util.UUID;
-import java.util.regex.Pattern;
-
-import org.apache.drill.common.exceptions.DrillException;
-import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.proto.UserBitShared.ExceptionWrapper;
-import org.apache.drill.exec.proto.UserBitShared.StackTraceElementWrapper;
-import org.apache.drill.exec.rpc.RemoteRpcException;
-import org.slf4j.Logger;
-
-
-public class ErrorHelper {
- static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ErrorHelper.class);
-
- final static Pattern IGNORE= Pattern.compile("^(sun|com\\.sun|java).*");
-
- /**
- * Manages message conversion before returning to user. If the exception is a remote rpc exception, will simply return user friendly message. Otherwise, will log and return.
- * TODO: this should really be done client side but we don't currently have any way to maintain session state on the client.
- *
- * @param endpoint
- * @param message
- * @param t
- * @param logger
- * @param verbose
- * @return
- */
- public static DrillPBError logAndConvertMessageError(DrillbitEndpoint endpoint, String message, Throwable t, Logger logger, boolean verbose) {
-
- DrillPBError baseError = t instanceof RemoteRpcException ? ((RemoteRpcException) t).getRemoteError() : logAndConvertError(endpoint, message, t, logger);
- String userMessage = getErrorMessage(baseError, verbose);
- return DrillPBError.newBuilder() //
- .setEndpoint(baseError.getEndpoint()) //
- .setErrorId(baseError.getErrorId()) //
- .setMessage(userMessage) //
- .build();
- }
-
- public static DrillPBError logAndConvertError(DrillbitEndpoint endpoint, String message, Throwable t, Logger logger) {
- String id = UUID.randomUUID().toString();
- DrillPBError.Builder builder = DrillPBError.newBuilder();
- builder.setEndpoint(endpoint);
- builder.setErrorId(id);
- if(message != null){
- builder.setMessage(message);
- }
- if(t == null){
- t = new DrillException("Undefined failure occurred.");
- }
- builder.setException(getWrapper(t));
-
- // record the error to the log for later reference.
- logger.error("Error {}: {}", id, message, t);
-
- return builder.build();
- }
-
- public static ExceptionWrapper getWrapper(Throwable ex){
- return getWrapperBuilder(ex).build();
- }
-
- public static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex){
- return getWrapperBuilder(ex, false);
- }
-
- public static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex, boolean includeAllStack){
-
-
-
- ExceptionWrapper.Builder ew = ExceptionWrapper.newBuilder();
- if(ex.getMessage() != null) {
- ew.setMessage(ex.getMessage());
- }
- ew.setExceptionClass(ex.getClass().getCanonicalName());
- boolean isHidden = false;
- StackTraceElementWrapper[] wrappers = new StackTraceElementWrapper[ex.getStackTrace().length];
- for(int i = 0; i < wrappers.length; i++){
- StackTraceElement ele = ex.getStackTrace()[i];
- if(include(ele, includeAllStack)){
- if(isHidden){
- isHidden = false;
- }
- ew.addStackTrace(getSTWrapper(ele));
- }else{
- if(!isHidden){
- isHidden = true;
- ew.addStackTrace(getEmptyST());
- }
- }
-
- }
-
- if(ex.getCause() != null && ex.getCause() != ex){
- ew.setCause(getWrapper(ex.getCause()));
- }
- return ew;
- }
-
- private static boolean include(StackTraceElement ele, boolean includeAllStack){
- if(includeAllStack) {
- return true;
- }
- return !(IGNORE.matcher(ele.getClassName()).matches());
- }
-
- private static StackTraceElementWrapper.Builder getEmptyST(){
- StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
- w.setClassName("...");
- w.setIsNativeMethod(false);
- w.setLineNumber(0);
- w.setMethodName("...");
- return w;
- }
- public static StackTraceElementWrapper.Builder getSTWrapper(StackTraceElement ele){
- StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
- w.setClassName(ele.getClassName());
- if(ele.getFileName() != null) {
- w.setFileName(ele.getFileName());
- }
- w.setIsNativeMethod(ele.isNativeMethod());
- w.setLineNumber(ele.getLineNumber());
- w.setMethodName(ele.getMethodName());
- return w;
- }
-
-
- public static String getErrorMessage(final DrillPBError error, final boolean verbose) {
-
- String finalMessage = null;
- ExceptionWrapper ex = error.getException();
- StringBuilder sb = new StringBuilder();
-
-
-
- sb //
- .append("[ ") //
- .append(error.getErrorId()) //
- .append(" on ")
- .append(error.getEndpoint().getAddress())
- .append(":").append(error.getEndpoint().getUserPort())
- .append(" ]\n");
-
- boolean cause = false;
- while(ex != null){
-
- if(ex.hasMessage()){
- finalMessage = ex.getMessage();
- }
-
- if(verbose){
- sb.append(" ");
-
- if(cause){
- sb.append("Caused By ");
- }
-
- sb.append("(");
- sb.append(ex.getExceptionClass());
- sb.append(") ");
- sb.append(ex.getMessage());
- sb.append("\n");
- for(int i = 0; i < ex.getStackTraceCount(); i++){
- StackTraceElementWrapper st = ex.getStackTrace(i);
- sb.append(" ");
- sb.append(st.getClassName());
- sb.append('.');
- sb.append(st.getMethodName());
- sb.append("():");
- sb.append(st.getLineNumber());
- sb.append("\n");
- }
- cause = true;
- }
-
- ex = ex.hasCause() ? ex.getCause() : null;
-
-
- }
-
- StringBuilder msg = new StringBuilder();
-
- if (error.hasMessage()){
- msg.append(error.getMessage());
- if(finalMessage != null){
- msg.append(", ");
- msg.append(finalMessage);
- msg.append(' ');
- }
- }else if(finalMessage != null){
- msg.append(finalMessage);
- msg.append(' ');
- }else{
- msg.append("Error ");
- }
-
- msg.append(sb);
-
- return msg.toString();
- }
-
- public static void main(String[] args ){
- DrillPBError e = logAndConvertError(DrillbitEndpoint.newBuilder().setAddress("host1").setControlPort(1234).build(), "RpcFailure", new Exception("Excep 1", new Exception("excep2")), logger);
- System.out.println(getErrorMessage(e, false));
- System.out.println("\n\n\n");
- System.out.println(getErrorMessage(e, true));
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
index 23ef0d3..0df5145 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
@@ -28,9 +28,10 @@ import java.util.concurrent.TimeUnit;
import com.google.common.base.Preconditions;
-import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.drill.common.EventProcessor;
import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.common.exceptions.ExecutionSetupException;
import org.apache.drill.common.logical.LogicalPlan;
import org.apache.drill.common.logical.PlanProperties.Generator.ResultMode;
@@ -56,7 +57,6 @@ import org.apache.drill.exec.proto.BitControl.PlanFragment;
import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
import org.apache.drill.exec.proto.GeneralRPCProtos.Ack;
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryResult;
import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
@@ -71,7 +71,6 @@ import org.apache.drill.exec.server.options.OptionManager;
import org.apache.drill.exec.testing.ExceptionInjector;
import org.apache.drill.exec.util.Pointer;
import org.apache.drill.exec.work.EndpointListener;
-import org.apache.drill.exec.work.ErrorHelper;
import org.apache.drill.exec.work.QueryWorkUnit;
import org.apache.drill.exec.work.WorkManager.WorkerBee;
import org.apache.drill.exec.work.batch.IncomingBuffers;
@@ -500,7 +499,7 @@ public class Foreman implements Runnable {
*/
private class ForemanResult implements AutoCloseable {
private QueryState resultState = null;
- private Exception resultException = null;
+ private DrillUserException resultException = null;
private boolean isClosed = false;
/**
@@ -533,7 +532,7 @@ public class Foreman implements Runnable {
Preconditions.checkState(resultState == null);
resultState = QueryState.FAILED;
- resultException = exception;
+ addException(exception);
}
/**
@@ -546,7 +545,8 @@ public class Foreman implements Runnable {
Preconditions.checkNotNull(exception);
if (resultException == null) {
- resultException = exception;
+ resultException = ErrorHelper.wrap(exception);
+ resultException.getContext().add(queryContext.getCurrentEndpoint());
} else {
resultException.addSuppressed(exception);
}
@@ -614,9 +614,8 @@ public class Foreman implements Runnable {
.setQueryId(queryId)
.setQueryState(resultState);
if (resultException != null) {
- final DrillPBError error = ErrorHelper.logAndConvertError(queryContext.getCurrentEndpoint(),
- ExceptionUtils.getRootCauseMessage(resultException), resultException, logger);
- resultBuilder.addError(error);
+ boolean verbose = queryContext.getOptions().getOption(ExecConstants.ENABLE_VERBOSE_ERRORS_KEY).bool_val;
+ resultBuilder.addError(resultException.getOrCreatePBError(verbose));
}
/*
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
index 8626d5b..dc60beb 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.drill.common.exceptions.DrillRemoteException;
import org.apache.drill.common.exceptions.DrillRuntimeException;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.proto.BitControl.FragmentStatus;
@@ -39,7 +40,6 @@ import org.apache.drill.exec.proto.UserBitShared.QueryProfile;
import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
import org.apache.drill.exec.proto.UserProtos.RunQuery;
import org.apache.drill.exec.proto.helper.QueryIdHelper;
-import org.apache.drill.exec.rpc.RemoteRpcException;
import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.control.Controller;
import org.apache.drill.exec.server.DrillbitContext;
@@ -160,7 +160,7 @@ public class QueryManager implements FragmentStatusListener, DrillbitStatusListe
break;
case FAILED:
- stateListener.moveToState(QueryState.FAILED, new RemoteRpcException(status.getProfile().getError()));
+ stateListener.moveToState(QueryState.FAILED, new DrillRemoteException(status.getProfile().getError()));
break;
default:
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
index 2299afa..e372283 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
@@ -47,10 +47,10 @@ public abstract class SqlUnsupportedException extends ForemanSetupException {
super(errorMessage);
}
- public static void errorMessageToException(String errorMessage) throws SqlUnsupportedException {
+ public static void errorClassNameToException(String errorClassName) throws SqlUnsupportedException {
UnsupportedOperatorCollector collector = new UnsupportedOperatorCollector();
for(ExceptionType ex : ExceptionType.values()) {
- if(errorMessage.startsWith(ex.toString())) {
+ if(errorClassName.endsWith(ex.toString())) {
collector.setException(ex);
collector.convertException();
collector.clean();
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
index 1b0885d..8279876 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
@@ -17,13 +17,13 @@
*/
package org.apache.drill.exec.work.fragment;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.proto.BitControl.FragmentStatus;
import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
import org.apache.drill.exec.proto.UserBitShared.FragmentState;
import org.apache.drill.exec.proto.UserBitShared.MinorFragmentProfile;
-import org.apache.drill.exec.work.ErrorHelper;
public abstract class AbstractStatusReporter implements StatusReporter{
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AbstractStatusReporter.class);
@@ -37,17 +37,17 @@ public abstract class AbstractStatusReporter implements StatusReporter{
}
private FragmentStatus.Builder getBuilder(FragmentState state){
- return getBuilder(context, state, null, null);
+ return getBuilder(context, state, null);
}
- public static FragmentStatus.Builder getBuilder(FragmentContext context, FragmentState state, String message, Throwable t){
+ public static FragmentStatus.Builder getBuilder(FragmentContext context, FragmentState state, DrillUserException ex){
FragmentStatus.Builder status = FragmentStatus.newBuilder();
MinorFragmentProfile.Builder b = MinorFragmentProfile.newBuilder();
context.getStats().addMetricsToStatus(b);
b.setState(state);
- if(t != null){
+ if(ex != null){
boolean verbose = context.getOptions().getOption(ExecConstants.ENABLE_VERBOSE_ERRORS_KEY).bool_val;
- b.setError(ErrorHelper.logAndConvertMessageError(context.getIdentity(), message, t, logger, verbose));
+ b.setError(ex.getOrCreatePBError(verbose));
}
status.setHandle(context.getHandle());
b.setMemoryUsed(context.getAllocator().getAllocatedMemory());
@@ -105,8 +105,8 @@ public abstract class AbstractStatusReporter implements StatusReporter{
protected abstract void statusChange(FragmentHandle handle, FragmentStatus status);
@Override
- public final void fail(FragmentHandle handle, String message, Throwable excep) {
- FragmentStatus.Builder status = getBuilder(context, FragmentState.FAILED, message, excep);
+ public final void fail(FragmentHandle handle, String message, DrillUserException excep) {
+ FragmentStatus.Builder status = getBuilder(context, FragmentState.FAILED, excep);
fail(handle, status);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
index a7e6c46..58f4256 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
@@ -21,6 +21,8 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.drill.common.DeferredException;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
import org.apache.drill.exec.coord.ClusterCoordinator;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.physical.base.FragmentRoot;
@@ -83,9 +85,8 @@ public class FragmentExecutor implements Runnable {
if(state.get() != FragmentState.RUNNING_VALUE) {
return null;
}
- final FragmentStatus status =
- AbstractStatusReporter.getBuilder(fragmentContext, FragmentState.RUNNING, null, null).build();
- return status;
+
+ return AbstractStatusReporter.getBuilder(fragmentContext, FragmentState.RUNNING, null).build();
}
public void cancel() {
@@ -227,7 +228,11 @@ public class FragmentExecutor implements Runnable {
private void internalFail(final Throwable excep) {
state.set(FragmentState.FAILED_VALUE);
- listener.fail(fragmentContext.getHandle(), "Failure while running fragment.", excep);
+
+ DrillUserException uex = ErrorHelper.wrap(excep);
+ uex.getContext().add(getContext().getIdentity());
+
+ listener.fail(fragmentContext.getHandle(), "Failure while running fragment.", uex);
}
/**
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
index 26b5d68..1699322 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
@@ -17,6 +17,7 @@
*/
package org.apache.drill.exec.work.fragment;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
import org.apache.drill.exec.proto.UserBitShared.FragmentState;
@@ -24,6 +25,6 @@ import org.apache.drill.exec.proto.UserBitShared.FragmentState;
* The status handler is responsible for receiving changes in fragment status and propagating them back to the foreman.
*/
public interface StatusReporter {
- void fail(FragmentHandle handle, String message, Throwable excep);
+ void fail(FragmentHandle handle, String message, DrillUserException excep);
void stateChanged(FragmentHandle handle, FragmentState newState);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
index 0c2f0e5..6df5801 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
@@ -25,9 +25,8 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.base.Preconditions;
-import com.google.common.io.Files;
import org.apache.drill.common.config.DrillConfig;
-import org.apache.drill.common.exceptions.ExecutionSetupException;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.ExecTest;
import org.apache.drill.exec.client.DrillClient;
@@ -37,7 +36,6 @@ import org.apache.drill.exec.memory.TopLevelAllocator;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryType;
import org.apache.drill.exec.record.RecordBatchLoader;
-import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.user.ConnectionThrottle;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -45,9 +43,6 @@ import org.apache.drill.exec.server.Drillbit;
import org.apache.drill.exec.server.DrillbitContext;
import org.apache.drill.exec.server.RemoteServiceSet;
import org.apache.drill.exec.store.StoragePluginRegistry;
-import org.apache.drill.exec.store.dfs.FileSystemConfig;
-import org.apache.drill.exec.store.dfs.FileSystemPlugin;
-import org.apache.drill.exec.store.dfs.WorkspaceConfig;
import org.apache.drill.exec.util.TestUtilities;
import org.apache.drill.exec.util.VectorUtil;
import org.junit.AfterClass;
@@ -325,12 +320,12 @@ public class BaseTestQuery extends ExecTest {
}
private static class SilentListener implements UserResultsListener {
- private volatile Exception exception;
+ private volatile DrillUserException exception;
private AtomicInteger count = new AtomicInteger();
private CountDownLatch latch = new CountDownLatch(1);
@Override
- public void submissionFailed(RpcException ex) {
+ public void submissionFailed(DrillUserException ex) {
exception = ex;
System.out.println("Query failed: " + ex.getMessage());
latch.countDown();
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java b/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
index 5703bf9..715904d 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
@@ -23,11 +23,11 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.apache.drill.exec.proto.UserBitShared.QueryId;
import org.apache.drill.exec.proto.UserBitShared.QueryData;
import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.rpc.RpcException;
import org.apache.drill.exec.rpc.user.ConnectionThrottle;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -49,10 +49,10 @@ public abstract class SingleRowListener implements UserResultsListener {
}
@Override
- public void submissionFailed(final RpcException ex) {
+ public void submissionFailed(final DrillUserException ex) {
exception = ex;
synchronized(errorList) {
- errorList.add(ex.getRemoteError());
+ errorList.add(ex.getOrCreatePBError(false));
}
latch.countDown();
}
http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java b/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
index 875fb25..12b1787 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
@@ -17,7 +17,7 @@
*/
package org.apache.drill;
-import org.apache.drill.exec.rpc.RpcException;
+import org.apache.drill.common.exceptions.DrillUserException;
import org.junit.Ignore;
import org.junit.Test;
@@ -73,13 +73,13 @@ public class TestBugFixes extends BaseTestQuery {
}
- @Test (expected = RpcException.class)
+ @Test (expected = DrillUserException.class)
// Should be "Failure while parsing sql. Node [rel#26:Subset#6.LOGICAL.ANY([]).[]] could not be implemented;".
// Drill will hit CanNotPlan, until we add code fix to transform the local LHS filter in left outer join properly.
public void testDRILL1337_LocalLeftFilterLeftOutJoin() throws Exception {
try {
test("select count(*) from cp.`tpch/nation.parquet` n left outer join cp.`tpch/region.parquet` r on n.n_regionkey = r.r_regionkey and n.n_nationkey > 10;");
- } catch (RpcException e) {
+ } catch (DrillUserException e) {
logger.info("***** Test resulted in expected failure: " + e.getMessage());
throw e;
}