Handle error conditions in the /query/result API
- introduce AbstractQueryApiServlet to factor out common code of
QueryResultApiServlet and QueryStatusApiServlet
- clean up ResultReader interface
- remove org.apache.asterix.api.http.servlet.HyracksProperties
Change-Id: Icb99fccb4b41768fa010c574bf1703ffcd47535e
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1532
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Yingyi Bu <buyingyi@gmail.com>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/AbstractQueryApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/AbstractQueryApiServlet.java
new file mode 100644
index 0000000..8d934ee
--- /dev/null
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/AbstractQueryApiServlet.java
@@ -0,0 +1,85 @@
+/*
+ * 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.asterix.api.http.server;
+
+import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_CONNECTION_ATTR;
+import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_DATASET_ATTR;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.asterix.app.result.ResultReader;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.exceptions.RuntimeDataException;
+import org.apache.hyracks.api.client.IHyracksClientConnection;
+import org.apache.hyracks.api.dataset.IHyracksDataset;
+import org.apache.hyracks.client.dataset.HyracksDataset;
+import org.apache.hyracks.http.server.AbstractServlet;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+class AbstractQueryApiServlet extends AbstractServlet {
+
+ AbstractQueryApiServlet(ConcurrentMap<String, Object> ctx, String[] paths) {
+ super(ctx, paths);
+ }
+
+ protected IHyracksDataset getHyracksDataset() throws Exception { // NOSONAR
+ synchronized (ctx) {
+ IHyracksDataset hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
+ if (hds == null) {
+ hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
+ if (hds == null) {
+ hds = new HyracksDataset(getHyracksClientConnection(), ResultReader.FRAME_SIZE,
+ ResultReader.NUM_READERS);
+ ctx.put(HYRACKS_DATASET_ATTR, hds);
+ }
+ }
+ return hds;
+ }
+ }
+
+ protected IHyracksClientConnection getHyracksClientConnection() throws Exception { // NOSONAR
+ synchronized (ctx) {
+ final IHyracksClientConnection hcc = (IHyracksClientConnection) ctx.get(HYRACKS_CONNECTION_ATTR);
+ if (hcc == null) {
+ throw new RuntimeDataException(ErrorCode.PROPERTY_NOT_SET, HYRACKS_CONNECTION_ATTR);
+ }
+ return hcc;
+ }
+ }
+
+ protected static JsonNode parseHandle(ObjectMapper om, String strHandle, Logger logger) throws IOException {
+ if (strHandle == null) {
+ logger.log(Level.WARNING, "No handle provided");
+ } else {
+ try {
+ JsonNode handleObj = om.readTree(strHandle);
+ return handleObj.get("handle");
+ } catch (JsonProcessingException e) { // NOSONAR
+ logger.log(Level.WARNING, "Invalid handle: \"" + strHandle + "\"");
+ }
+ }
+ return null;
+ }
+}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
index dfc8a8f..292dd2a 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java
@@ -18,40 +18,30 @@
*/
package org.apache.asterix.api.http.server;
-import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_CONNECTION_ATTR;
-import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_DATASET_ATTR;
-
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.asterix.api.http.servlet.HyracksProperties;
import org.apache.asterix.app.result.ResultReader;
import org.apache.asterix.app.result.ResultUtil;
-import org.apache.asterix.common.exceptions.AsterixException;
import org.apache.asterix.translator.IStatementExecutor.Stats;
import org.apache.asterix.translator.SessionConfig;
-import org.apache.hyracks.api.client.HyracksConnection;
-import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.hyracks.api.dataset.IHyracksDataset;
import org.apache.hyracks.api.dataset.ResultSetId;
+import org.apache.hyracks.api.exceptions.ErrorCode;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.apache.hyracks.api.job.JobId;
-import org.apache.hyracks.client.dataset.HyracksDataset;
import org.apache.hyracks.http.api.IServletRequest;
import org.apache.hyracks.http.api.IServletResponse;
-import org.apache.hyracks.http.server.AbstractServlet;
import org.apache.hyracks.http.server.utils.HttpUtil;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
-public class QueryResultApiServlet extends AbstractServlet {
+public class QueryResultApiServlet extends AbstractQueryApiServlet {
private static final Logger LOGGER = Logger.getLogger(QueryResultApiServlet.class.getName());
public QueryResultApiServlet(ConcurrentMap<String, Object> ctx, String[] paths) {
@@ -59,53 +49,24 @@
}
@Override
- protected void get(IServletRequest request, IServletResponse response) {
+ protected void get(IServletRequest request, IServletResponse response) throws Exception {
response.setStatus(HttpResponseStatus.OK);
// TODO this seems wrong ...
- try {
- HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8);
- } catch (IOException e) {
- LOGGER.log(Level.WARNING, "Failure setting content type", e);
- response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
- return;
- }
+ HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_HTML, HttpUtil.Encoding.UTF8);
String strHandle = request.getParameter("handle");
PrintWriter out = response.writer();
- IHyracksClientConnection hcc;
- IHyracksDataset hds;
try {
- if (strHandle == null || strHandle.isEmpty()) {
- throw new AsterixException("Empty request, no handle provided");
+ JsonNode handle = parseHandle(new ObjectMapper(), strHandle, LOGGER);
+ if (handle == null) {
+ response.setStatus(HttpResponseStatus.BAD_REQUEST);
+ return;
}
-
- HyracksProperties hp = new HyracksProperties();
- String strIP = hp.getHyracksIPAddress();
- int port = hp.getHyracksPort();
-
- hcc = (IHyracksClientConnection) ctx.get(HYRACKS_CONNECTION_ATTR);
- hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
- if (hcc == null || hds == null) {
- synchronized (ctx) {
- hcc = (IHyracksClientConnection) ctx.get(HYRACKS_CONNECTION_ATTR);
- hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
- if (hcc == null) {
- hcc = new HyracksConnection(strIP, port);
- ctx.put(HYRACKS_CONNECTION_ATTR, hcc);
- }
- if (hds == null) {
- hds = new HyracksDataset(hcc, ResultReader.FRAME_SIZE, ResultReader.NUM_READERS);
- ctx.put(HYRACKS_DATASET_ATTR, hds);
- }
- }
- }
- ObjectMapper om = new ObjectMapper();
- ObjectNode handleObj = (ObjectNode) om.readTree(strHandle);
- ArrayNode handle = (ArrayNode) handleObj.get("handle");
JobId jobId = new JobId(handle.get(0).asLong());
ResultSetId rsId = new ResultSetId(handle.get(1).asLong());
- ResultReader resultReader = new ResultReader(hds);
- resultReader.open(jobId, rsId);
+
+ IHyracksDataset hds = getHyracksDataset();
+ ResultReader resultReader = new ResultReader(hds, jobId, rsId);
// QQQ The output format is determined by the initial
// query and cannot be modified here, so calling back to
@@ -115,15 +76,22 @@
// some object that we can obtain here.
SessionConfig sessionConfig = RestApiServlet.initResponse(request, response);
ResultUtil.printResults(resultReader, sessionConfig, new Stats(), null);
-
- } catch (Exception e) {
+ } catch (HyracksDataException e) {
+ final int errorCode = e.getErrorCode();
+ if (ErrorCode.NO_RESULTSET == errorCode) {
+ LOGGER.log(Level.INFO, "No results for: \"" + strHandle + "\"");
+ response.setStatus(HttpResponseStatus.NOT_FOUND);
+ return;
+ }
response.setStatus(HttpResponseStatus.BAD_REQUEST);
out.println(e.getMessage());
- LOGGER.log(Level.WARNING, "Error retrieving result", e);
+ LOGGER.log(Level.WARNING, "Error retrieving result for \"" + strHandle + "\"", e);
+ } catch (Exception e) {
+ response.setStatus(HttpResponseStatus.BAD_REQUEST);
+ LOGGER.log(Level.WARNING, "Error retrieving result for \"" + strHandle + "\"", e);
}
if (out.checkError()) {
- LOGGER.warning("Error flushing output writer");
+ LOGGER.warning("Error flushing output writer for \"" + strHandle + "\"");
}
}
-
}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java
index 1c3f4c7..33c5c8f 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java
@@ -18,35 +18,26 @@
*/
package org.apache.asterix.api.http.server;
-import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_CONNECTION_ATTR;
-import static org.apache.asterix.api.http.servlet.ServletConstants.HYRACKS_DATASET_ATTR;
-
-import java.io.IOException;
-import java.io.PrintWriter;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.asterix.app.result.ResultReader;
-import org.apache.hyracks.api.client.IHyracksClientConnection;
import org.apache.hyracks.api.dataset.DatasetJobRecord;
import org.apache.hyracks.api.dataset.IHyracksDataset;
import org.apache.hyracks.api.dataset.ResultSetId;
import org.apache.hyracks.api.job.JobId;
-import org.apache.hyracks.client.dataset.HyracksDataset;
import org.apache.hyracks.http.api.IServletRequest;
import org.apache.hyracks.http.api.IServletResponse;
-import org.apache.hyracks.http.server.AbstractServlet;
import org.apache.hyracks.http.server.utils.HttpUtil;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.netty.handler.codec.http.HttpResponseStatus;
-public class QueryStatusApiServlet extends AbstractServlet {
+public class QueryStatusApiServlet extends AbstractQueryApiServlet {
private static final Logger LOGGER = Logger.getLogger(QueryStatusApiServlet.class.getName());
public QueryStatusApiServlet(ConcurrentMap<String, Object> ctx, String[] paths) {
@@ -54,71 +45,30 @@
}
@Override
- protected void get(IServletRequest request, IServletResponse response) {
- response.setStatus(HttpResponseStatus.OK);
- try {
- HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_PLAIN, HttpUtil.Encoding.UTF8);
- } catch (IOException e) {
- LOGGER.log(Level.WARNING, "Failure setting content type", e);
- response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
+ protected void get(IServletRequest request, IServletResponse response) throws Exception {
+ String strHandle = request.getParameter("handle");
+ ObjectMapper om = new ObjectMapper();
+ JsonNode handle = parseHandle(om, strHandle, LOGGER);
+ if (handle == null) {
+ response.setStatus(HttpResponseStatus.BAD_REQUEST);
return;
}
- String strHandle = request.getParameter("handle");
- PrintWriter out = response.writer();
- try {
- ObjectMapper om = new ObjectMapper();
- JsonNode handle = parseHandle(om, strHandle, LOGGER);
- if (handle == null) {
- response.setStatus(HttpResponseStatus.BAD_REQUEST);
- return;
- }
- JobId jobId = new JobId(handle.get(0).asLong());
- ResultSetId rsId = new ResultSetId(handle.get(1).asLong());
+ JobId jobId = new JobId(handle.get(0).asLong());
+ ResultSetId rsId = new ResultSetId(handle.get(1).asLong());
- IHyracksDataset hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
- if (hds == null) {
- synchronized (ctx) {
- hds = (IHyracksDataset) ctx.get(HYRACKS_DATASET_ATTR);
- if (hds == null) {
- hds = new HyracksDataset((IHyracksClientConnection) ctx.get(HYRACKS_CONNECTION_ATTR),
- ResultReader.FRAME_SIZE, ResultReader.NUM_READERS);
- ctx.put(HYRACKS_DATASET_ATTR, hds);
- }
- }
- }
- /* TODO(madhusudancs): We need to find a way to LOSSLESS_JSON serialize default format obtained from
- * metadataProvider in the AQLTranslator and store it as part of the result handle.
- */
- ResultReader resultReader = new ResultReader(hds);
- resultReader.open(jobId, rsId);
+ IHyracksDataset hds = getHyracksDataset();
+ ResultReader resultReader = new ResultReader(hds, jobId, rsId);
- ObjectNode jsonResponse = om.createObjectNode();
- final DatasetJobRecord.Status status = resultReader.getStatus();
- if (status == null) {
- LOGGER.log(Level.INFO, "No results for: \"" + strHandle + "\"");
- response.setStatus(HttpResponseStatus.NOT_FOUND);
- return;
- }
- jsonResponse.put("status", status.name());
- out.write(jsonResponse.toString());
-
- } catch (Exception e) {
- LOGGER.log(Level.SEVERE, "Failure handling a request", e);
- out.println(e.getMessage());
+ ObjectNode jsonResponse = om.createObjectNode();
+ final DatasetJobRecord.Status status = resultReader.getStatus();
+ if (status == null) {
+ LOGGER.log(Level.INFO, "No results for: \"" + strHandle + "\"");
+ response.setStatus(HttpResponseStatus.NOT_FOUND);
+ return;
}
- }
-
- static JsonNode parseHandle(ObjectMapper om, String strHandle, Logger logger) throws IOException {
- if (strHandle == null) {
- logger.log(Level.WARNING, "No handle provided");
- } else {
- try {
- JsonNode handleObj = om.readTree(strHandle);
- return handleObj.get("handle");
- } catch (JsonProcessingException e) {
- logger.log(Level.WARNING, "Invalid handle: \"" + strHandle + "\"");
- }
- }
- return null;
+ jsonResponse.put("status", status.name());
+ HttpUtil.setContentType(response, HttpUtil.ContentType.TEXT_PLAIN, HttpUtil.Encoding.UTF8);
+ response.setStatus(HttpResponseStatus.OK);
+ response.writer().write(jsonResponse.toString());
}
}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/HyracksProperties.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/HyracksProperties.java
deleted file mode 100644
index 269f813..0000000
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/HyracksProperties.java
+++ /dev/null
@@ -1,56 +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.asterix.api.http.servlet;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-public class HyracksProperties {
- private final InputStream is;
-
- private final Properties properties;
-
- private static String HYRACKS_IP = "127.0.0.1";
-
- private static int HYRACKS_PORT = 1098;
-
- public HyracksProperties() throws IOException {
- is = HyracksProperties.class.getClassLoader().getResourceAsStream("hyracks-deployment.properties");
- properties = new Properties();
- properties.load(is);
- }
-
- public String getHyracksIPAddress() {
- String strIP = properties.getProperty("cc.ip");
- if (strIP == null) {
- strIP = HYRACKS_IP;
- }
- return strIP;
- }
-
- public int getHyracksPort() {
- String strPort = properties.getProperty("cc.port");
- int port = HYRACKS_PORT;
- if (strPort != null) {
- port = Integer.parseInt(strPort);
- }
- return port;
- }
-}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultReader.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultReader.java
index b0677d8..1871476 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultReader.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultReader.java
@@ -30,8 +30,6 @@
import org.apache.hyracks.dataflow.common.comm.io.ResultFrameTupleAccessor;
public class ResultReader {
- private final IHyracksDataset hyracksDataset;
-
private IHyracksDatasetReader reader;
private IFrameTupleAccessor frameTupleAccessor;
@@ -41,12 +39,8 @@
public static final int FRAME_SIZE = AppContextInfo.INSTANCE.getCompilerProperties().getFrameSize();
- public ResultReader(IHyracksDataset hdc) {
- hyracksDataset = hdc;
- }
-
- public void open(JobId jobId, ResultSetId resultSetId) throws HyracksDataException {
- reader = hyracksDataset.createReader(jobId, resultSetId);
+ public ResultReader(IHyracksDataset hdc, JobId jobId, ResultSetId resultSetId) throws HyracksDataException {
+ reader = hdc.createReader(jobId, resultSetId);
frameTupleAccessor = new ResultFrameTupleAccessor();
}
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index f111c54..1e4d866 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -2436,8 +2436,7 @@
break;
case IMMEDIATE:
createAndRunJob(hcc, compiler, locker, resultDelivery, id -> {
- final ResultReader resultReader = new ResultReader(hdc);
- resultReader.open(id, resultSetId);
+ final ResultReader resultReader = new ResultReader(hdc, id, resultSetId);
ResultUtil.printResults(resultReader, sessionConfig, stats,
metadataProvider.findOutputRecordType());
});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/api.xml b/asterixdb/asterix-app/src/test/resources/runtimets/api.xml
index 6e97c0e..0fa83dd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/api.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/api.xml
@@ -94,5 +94,29 @@
<expected-error>HTTP/1.1 400 Bad Request</expected-error>
</compilation-unit>
</test-case>
+ <test-case FilePath="api">
+ <compilation-unit name="query_result_1">
+ <output-dir compare="Text">query_result_1</output-dir>
+ <expected-error>HTTP/1.1 404 Not Found</expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="api">
+ <compilation-unit name="query_result_2">
+ <output-dir compare="Text">query_result_2</output-dir>
+ <expected-error>HTTP/1.1 400 Bad Request</expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="api">
+ <compilation-unit name="query_result_3">
+ <output-dir compare="Text">query_result_3</output-dir>
+ <expected-error>HTTP/1.1 400 Bad Request</expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="api">
+ <compilation-unit name="query_result_4">
+ <output-dir compare="Text">query_result_4</output-dir>
+ <expected-error>HTTP/1.1 400 Bad Request</expected-error>
+ </compilation-unit>
+ </test-case>
</test-group>
</test-suite>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_1/query_result_1.1.get.http b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_1/query_result_1.1.get.http
new file mode 100644
index 0000000..d48dbe5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_1/query_result_1.1.get.http
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Test case Name : query_status_1
+ * Description : test query status for non-existent result
+ * Expected Result : Negative
+ * Date : 25th February 2017
+ */
+/query/result?handle={"handle":[18,0]}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_2/query_result_2.1.get.http b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_2/query_result_2.1.get.http
new file mode 100644
index 0000000..07b7556
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_2/query_result_2.1.get.http
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Test case Name : query_status_2
+ * Description : test query status for incorrect handle
+ * Expected Result : Negative
+ * Date : 25th February 2017
+ */
+/query/result?handle={"handle":[18,0]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_3/query_result_3.1.get.http b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_3/query_result_3.1.get.http
new file mode 100644
index 0000000..c39b87e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_3/query_result_3.1.get.http
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Test case Name : query_status_3
+ * Description : test query status for empty handle
+ * Expected Result : Negative
+ * Date : 25th February 2017
+ */
+/query/result?handle
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_4/query_result_4.1.get.http b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_4/query_result_4.1.get.http
new file mode 100644
index 0000000..88c4814
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_4/query_result_4.1.get.http
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/*
+ * Test case Name : query_status_4
+ * Description : test query status for non-existent handle
+ * Expected Result : Negative
+ * Date : 25th February 2017
+ */
+/query/result?handl={"handle":[18,0]}
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index 83ff3a2..6dbafd1 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -52,6 +52,8 @@
public static final int OUT_OF_BOUND = 11;
public static final int COERCION = 12;
public static final int DUPLICATE_FIELD_NAME = 13;
+ public static final int PROPERTY_NOT_SET = 14;
+
// Compilation errors
public static final int PARSE_ERROR = 1001;
diff --git a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index 3e96972..14bd0c7 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -44,6 +44,7 @@
10 = Invalid value: function %1$s expects its %2$s input parameter to be a non-negative value, but gets %3$s
11 = Index out of bound in %1$s: %2$s
12 = Invalid implicit scalar to collection coercion in %1$s
+14 = Property %1$s not set
# Compile-time check errors
1007 = Invalid expression: function %1$s expects its %2$s input parameter to be a %3$s expression, but the actual expression is %4$s
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties b/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
index 3711e48..3bf5a9a 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
@@ -42,6 +42,6 @@
21 = The distributed job %1$s was not found
22 = The distributed job %1$s already exists
23 = The distributed work failed for %1$s at %2$s
-24 = No result set %1$s for job %2$s
+24 = No result set for job %1$s
10000 = The given rule collection %1$s is not an instance of the List class.
diff --git a/hyracks-fullstack/hyracks/hyracks-client/src/main/java/org/apache/hyracks/client/dataset/HyracksDatasetReader.java b/hyracks-fullstack/hyracks/hyracks-client/src/main/java/org/apache/hyracks/client/dataset/HyracksDatasetReader.java
index e47d822..e377a50 100644
--- a/hyracks-fullstack/hyracks/hyracks-client/src/main/java/org/apache/hyracks/client/dataset/HyracksDatasetReader.java
+++ b/hyracks-fullstack/hyracks/hyracks-client/src/main/java/org/apache/hyracks/client/dataset/HyracksDatasetReader.java
@@ -125,6 +125,8 @@
resultChannel.registerMonitor(lastMonitor);
resultChannel.open(datasetClientCtx);
return true;
+ } catch (HyracksDataException e) {
+ throw e;
} catch (Exception e) {
throw new HyracksDataException(e);
}
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/dataset/DatasetDirectoryService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/dataset/DatasetDirectoryService.java
index ceeb9fa..98c0697 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/dataset/DatasetDirectoryService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/dataset/DatasetDirectoryService.java
@@ -72,8 +72,7 @@
}
@Override
- public synchronized void notifyJobCreation(JobId jobId, JobSpecification spec)
- throws HyracksException {
+ public synchronized void notifyJobCreation(JobId jobId, JobSpecification spec) throws HyracksException {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.info(getClass().getSimpleName() + " notified of new job " + jobId);
}
@@ -98,18 +97,18 @@
return jri == null ? null : jri.getRecord();
}
- private DatasetJobRecord getNonNullDatasetJobRecord(JobId jobId) {
+ private DatasetJobRecord getNonNullDatasetJobRecord(JobId jobId) throws HyracksDataException {
final DatasetJobRecord djr = getDatasetJobRecord(jobId);
if (djr == null) {
- throw new NullPointerException();
+ throw HyracksDataException.create(ErrorCode.NO_RESULTSET, jobId);
}
return djr;
}
@Override
public synchronized void registerResultPartitionLocation(JobId jobId, ResultSetId rsId, boolean orderedResult,
- boolean emptyResult, int partition, int nPartitions, NetworkAddress networkAddress) throws
- HyracksDataException {
+ boolean emptyResult, int partition, int nPartitions, NetworkAddress networkAddress)
+ throws HyracksDataException {
DatasetJobRecord djr = getNonNullDatasetJobRecord(jobId);
djr.setResultSetMetaData(rsId, orderedResult, nPartitions);
DatasetDirectoryRecord record = djr.getOrCreateDirectoryRecord(rsId, partition);
@@ -145,16 +144,20 @@
@Override
public synchronized void reportResultPartitionFailure(JobId jobId, ResultSetId rsId, int partition) {
- DatasetJobRecord djr = getNonNullDatasetJobRecord(jobId);
- djr.fail(rsId, partition);
+ DatasetJobRecord djr = getDatasetJobRecord(jobId);
+ if (djr != null) {
+ djr.fail(rsId, partition);
+ }
jobResultLocations.get(jobId).setException(new Exception());
notifyAll();
}
@Override
public synchronized void reportJobFailure(JobId jobId, List<Exception> exceptions) {
- DatasetJobRecord djr = getNonNullDatasetJobRecord(jobId);
- djr.fail(exceptions);
+ DatasetJobRecord djr = getDatasetJobRecord(jobId);
+ if (djr != null) {
+ djr.fail(exceptions);
+ }
// TODO(tillw) throwing an NPE here hangs the system, why?
jobResultLocations.get(jobId).setException(exceptions.isEmpty() ? null : exceptions.get(0));
notifyAll();
@@ -162,11 +165,7 @@
@Override
public synchronized Status getResultStatus(JobId jobId, ResultSetId rsId) throws HyracksDataException {
- DatasetJobRecord djr = getDatasetJobRecord(jobId);
- if (djr == null) {
- throw HyracksDataException.create(ErrorCode.NO_RESULTSET, rsId, jobId);
- }
- return djr.getStatus();
+ return getNonNullDatasetJobRecord(jobId).getStatus();
}
@Override
@@ -214,8 +213,8 @@
* TODO(madhusudancs): Think about caching (and still be stateless) instead of this ugly O(n) iterations for
* every check. This already looks very expensive.
*/
- private DatasetDirectoryRecord[] updatedRecords(JobId jobId, ResultSetId rsId, DatasetDirectoryRecord[] knownRecords)
- throws HyracksDataException {
+ private DatasetDirectoryRecord[] updatedRecords(JobId jobId, ResultSetId rsId,
+ DatasetDirectoryRecord[] knownRecords) throws HyracksDataException {
DatasetJobRecord djr = getNonNullDatasetJobRecord(jobId);
if (djr.getStatus() == Status.FAILED) {
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
index cd2ebd4..e7ac389 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
@@ -25,6 +25,7 @@
import java.util.logging.Logger;
import org.apache.hyracks.api.dataset.IDatasetManager;
+import org.apache.hyracks.api.dataset.IDatasetStateRecord;
import org.apache.hyracks.api.job.JobId;
/**
@@ -69,7 +70,8 @@
synchronized (datasetManager) {
toBeCollected.clear();
for (JobId jobId : datasetManager.getJobIds()) {
- if (System.currentTimeMillis() > datasetManager.getState(jobId).getTimestamp() + resultTTL) {
+ final IDatasetStateRecord state = datasetManager.getState(jobId);
+ if (state != null && System.currentTimeMillis() > state.getTimestamp() + resultTTL) {
toBeCollected.add(jobId);
}
}