[NO ISSUE][RT] Best-effort serialization of ErrorCode enum values
Change-Id: Ia8ffec3961f20db9355ec6b309a5b6fd99921da9
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/10683
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Michael Blow <mblow@apache.org>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
index fcc6993..5153ebb 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
@@ -18,13 +18,7 @@
*/
package org.apache.asterix.api.http.server;
-import static org.apache.asterix.common.exceptions.ErrorCode.INVALID_REQ_JSON_VAL;
-import static org.apache.asterix.common.exceptions.ErrorCode.INVALID_REQ_PARAM_VAL;
import static org.apache.asterix.common.exceptions.ErrorCode.NO_STATEMENT_PROVIDED;
-import static org.apache.asterix.common.exceptions.ErrorCode.REJECT_BAD_CLUSTER_STATE;
-import static org.apache.asterix.common.exceptions.ErrorCode.REJECT_NODE_UNREGISTERED;
-import static org.apache.asterix.common.exceptions.ErrorCode.REQUEST_TIMEOUT;
-import static org.apache.hyracks.api.exceptions.ErrorCode.JOB_REQUIREMENTS_EXCEED_CAPACITY;
import java.io.IOException;
import java.io.PrintWriter;
@@ -35,6 +29,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -65,6 +60,7 @@
import org.apache.asterix.common.context.IStorageComponentProvider;
import org.apache.asterix.common.dataflow.ICcApplicationContext;
import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
import org.apache.asterix.common.exceptions.RuntimeDataException;
import org.apache.asterix.compiler.provider.ILangCompilationProvider;
import org.apache.asterix.lang.common.base.IParser;
@@ -86,7 +82,8 @@
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.api.application.IServiceContext;
import org.apache.hyracks.api.exceptions.HyracksDataException;
-import org.apache.hyracks.api.exceptions.HyracksException;
+import org.apache.hyracks.api.exceptions.IError;
+import org.apache.hyracks.api.exceptions.IFormattedException;
import org.apache.hyracks.api.exceptions.Warning;
import org.apache.hyracks.api.result.IResultSet;
import org.apache.hyracks.control.common.controllers.CCConfig;
@@ -419,6 +416,38 @@
buildResponseResults(responsePrinter, sessionOutput, translator.getExecutionPlans(), warnings);
}
+ protected boolean handleIFormattedException(IError error, IFormattedException ex,
+ RequestExecutionState executionState, QueryServiceRequestParameters param) {
+ if (error instanceof ErrorCode) {
+ switch ((ErrorCode) error) {
+ case INVALID_REQ_PARAM_VAL:
+ case INVALID_REQ_JSON_VAL:
+ case NO_STATEMENT_PROVIDED:
+ executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.BAD_REQUEST);
+ return true;
+ case REQUEST_TIMEOUT:
+ LOGGER.info(() -> "handleException: request execution timed out: "
+ + LogRedactionUtil.userData(param.toString()));
+ executionState.setStatus(ResultStatus.TIMEOUT, HttpResponseStatus.OK);
+ return true;
+ case REJECT_NODE_UNREGISTERED:
+ case REJECT_BAD_CLUSTER_STATE:
+ LOGGER.warn(() -> "handleException: " + ex.getMessage() + ": "
+ + LogRedactionUtil.userData(param.toString()));
+ executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.SERVICE_UNAVAILABLE);
+ default:
+ // fall-through
+ }
+ } else if (error instanceof org.apache.hyracks.api.exceptions.ErrorCode) {
+ switch ((org.apache.hyracks.api.exceptions.ErrorCode) error) {
+ case JOB_REQUIREMENTS_EXCEED_CAPACITY:
+ executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.BAD_REQUEST);
+ return true;
+ }
+ }
+ return false;
+ }
+
protected void handleExecuteStatementException(Throwable t, RequestExecutionState executionState,
QueryServiceRequestParameters param) {
if (t instanceof org.apache.asterix.lang.sqlpp.parser.TokenMgrError || t instanceof AlgebricksException) {
@@ -430,30 +459,17 @@
+ LogRedactionUtil.statement(param.toString()));
}
executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.BAD_REQUEST);
- } else if (t instanceof HyracksException) {
- HyracksException he = (HyracksException) t;
- // TODO(mblow): reconsolidate
- if (he.matchesAny(INVALID_REQ_PARAM_VAL, INVALID_REQ_JSON_VAL, NO_STATEMENT_PROVIDED,
- JOB_REQUIREMENTS_EXCEED_CAPACITY)) {
- executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.BAD_REQUEST);
- } else if (he.matches(REQUEST_TIMEOUT)) {
- LOGGER.info(() -> "handleException: request execution timed out: "
- + LogRedactionUtil.userData(param.toString()));
- executionState.setStatus(ResultStatus.TIMEOUT, HttpResponseStatus.OK);
- } else if (he.matchesAny(REJECT_BAD_CLUSTER_STATE, REJECT_NODE_UNREGISTERED)) {
- LOGGER.warn(() -> "handleException: " + he.getMessage() + ": "
- + LogRedactionUtil.userData(param.toString()));
- executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.SERVICE_UNAVAILABLE);
- } else {
- LOGGER.warn(() -> "handleException: unexpected exception " + he.getMessage() + ": "
- + LogRedactionUtil.userData(param.toString()), he);
- executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.INTERNAL_SERVER_ERROR);
+ return;
+ } else if (t instanceof IFormattedException) {
+ IFormattedException formattedEx = (IFormattedException) t;
+ Optional<IError> maybeError = formattedEx.getError();
+ if (maybeError.isPresent()
+ && handleIFormattedException(maybeError.get(), (IFormattedException) t, executionState, param)) {
+ return;
}
- } else {
- LOGGER.warn(() -> "handleException: unexpected exception: " + LogRedactionUtil.userData(param.toString()),
- t);
- executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
+ LOGGER.warn(() -> "handleException: unexpected exception: " + LogRedactionUtil.userData(param.toString()), t);
+ executionState.setStatus(ResultStatus.FATAL, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
private void setSessionConfig(SessionOutput sessionOutput, QueryServiceRequestParameters param,
diff --git a/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java b/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java
index f00161c..4b8179c 100644
--- a/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java
+++ b/hyracks-fullstack/algebricks/algebricks-common/src/main/java/org/apache/hyracks/algebricks/common/exceptions/AlgebricksException.java
@@ -18,6 +18,9 @@
*/
package org.apache.hyracks.algebricks.common.exceptions;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Optional;
@@ -28,7 +31,7 @@
import org.apache.hyracks.api.util.ErrorMessageUtil;
public class AlgebricksException extends Exception implements IFormattedException {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
public static final int UNKNOWN = 0;
private final String component;
@@ -36,7 +39,7 @@
private final Serializable[] params;
private final String nodeId;
private final SourceLocation sourceLoc;
- protected final transient IError error;
+ protected transient IError error;
@SuppressWarnings("squid:S1165") // exception class not final
private transient volatile String msgCache;
@@ -134,4 +137,12 @@
}
return msgCache;
}
+
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ ErrorMessageUtil.writeObjectWithError(error, out);
+ }
+
+ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+ error = ErrorMessageUtil.readObjectWithError(in).orElse(null);
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksException.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksException.java
index d6085f6..0769e18 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksException.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/HyracksException.java
@@ -25,15 +25,15 @@
import org.apache.hyracks.api.util.ErrorMessageUtil;
public class HyracksException extends IOException implements IFormattedException {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
public static final int UNKNOWN = 0;
private final String component;
private final int errorCode;
private final Serializable[] params;
private final String nodeId;
- protected transient final IError error;
private SourceLocation sourceLoc;
+ protected transient IError error;
private transient volatile String msgCache;
public static HyracksException create(Throwable cause) {
@@ -166,7 +166,11 @@
return Optional.ofNullable(error);
}
- public boolean matches(ErrorCode errorCode) {
- return component.equals(errorCode.component()) && getErrorCode() == errorCode.intValue();
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+ ErrorMessageUtil.writeObjectWithError(error, out);
+ }
+
+ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
+ error = ErrorMessageUtil.readObjectWithError(in).orElse(null);
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/IFormattedException.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/IFormattedException.java
index 1f814b4..33b3995 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/IFormattedException.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/IFormattedException.java
@@ -46,8 +46,13 @@
String getMessage();
/**
+ * See {@link Throwable#getSuppressed()}
+ */
+ Throwable[] getSuppressed();
+
+ /**
* If available, returns the {@link IError} associated with this exception
- * @return the error instance, othewise {@link Optional#empty()}
+ * @return the error instance, otherwise {@link Optional#empty()}
* @since 0.3.5.1
*/
Optional<IError> getError();
@@ -85,4 +90,16 @@
static boolean matchesAny(Throwable th, IError candidate, IError... otherCandidates) {
return th instanceof IFormattedException && ((IFormattedException) th).matchesAny(candidate, otherCandidates);
}
+
+ /**
+ * If the supplied {@link Throwable} is an instance of {@link IFormattedException}, return the {@link IError}
+ * associated with this exception if available
+ *
+ * @return the error instance, otherwise {@link Optional#empty()}
+ * @since 0.3.5.1
+ */
+ static Optional<IError> getError(Throwable throwable) {
+ return throwable instanceof IFormattedException ? ((IFormattedException) throwable).getError()
+ : Optional.empty();
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
index a7372ae..6479c8d 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/util/ErrorMessageUtil.java
@@ -21,11 +21,14 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import java.util.Properties;
import org.apache.hyracks.api.exceptions.IError;
@@ -140,4 +143,22 @@
}
return enumMessages;
}
+
+ public static void writeObjectWithError(IError error, ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ out.writeObject(error);
+ }
+
+ public static Optional<IError> readObjectWithError(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ try {
+ return Optional.ofNullable((IError) in.readObject());
+ } catch (IllegalArgumentException e) {
+ // this is expected in case of error codes not available in this version; return null
+ LOGGER.debug("unable to deserialize error object due to {}, the error reference will be empty",
+ String.valueOf(e));
+ return Optional.empty();
+ }
+ }
}