Repository: asterixdb Updated Branches: refs/heads/master 235b21861 -> 3c764a421
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 <jenk...@fulliautomatix.ics.uci.edu> Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Yingyi Bu <buyin...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/3c764a42 Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/3c764a42 Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/3c764a42 Branch: refs/heads/master Commit: 3c764a421941ad713304301383890f5278861bbe Parents: 235b218 Author: Till Westmann <ti...@apache.org> Authored: Sat Feb 25 22:57:39 2017 -0800 Committer: Till Westmann <ti...@apache.org> Committed: Mon Feb 27 15:34:00 2017 -0800 ---------------------------------------------------------------------- .../http/server/AbstractQueryApiServlet.java | 85 ++++++++++++++++++ .../api/http/server/QueryResultApiServlet.java | 82 ++++++----------- .../api/http/server/QueryStatusApiServlet.java | 92 +++++--------------- .../api/http/servlet/HyracksProperties.java | 56 ------------ .../apache/asterix/app/result/ResultReader.java | 10 +-- .../asterix/app/translator/QueryTranslator.java | 3 +- .../src/test/resources/runtimets/api.xml | 24 +++++ .../query_result_1/query_result_1.1.get.http | 25 ++++++ .../query_result_2/query_result_2.1.get.http | 25 ++++++ .../query_result_3/query_result_3.1.get.http | 25 ++++++ .../query_result_4/query_result_4.1.get.http | 25 ++++++ .../asterix/common/exceptions/ErrorCode.java | 2 + .../main/resources/asx_errormsg/en.properties | 1 + .../src/main/resources/errormsg/en.properties | 2 +- .../client/dataset/HyracksDatasetReader.java | 2 + .../cc/dataset/DatasetDirectoryService.java | 33 ++++--- .../common/dataset/ResultStateSweeper.java | 4 +- 17 files changed, 283 insertions(+), 213 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/AbstractQueryApiServlet.java ---------------------------------------------------------------------- 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; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryResultApiServlet.java ---------------------------------------------------------------------- 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 @@ public class QueryResultApiServlet extends AbstractServlet { } @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 @@ public class QueryResultApiServlet extends AbstractServlet { // 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 + "\""); } } - } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryStatusApiServlet.java ---------------------------------------------------------------------- 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 @@ public class QueryStatusApiServlet extends AbstractServlet { } @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()); - - 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); + JobId jobId = new JobId(handle.get(0).asLong()); + ResultSetId rsId = new ResultSetId(handle.get(1).asLong()); - 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()); + IHyracksDataset hds = getHyracksDataset(); + ResultReader resultReader = new ResultReader(hds, jobId, rsId); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Failure handling a request", e); - out.println(e.getMessage()); - } - } - - 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 + "\""); - } + 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; } - 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()); } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/servlet/HyracksProperties.java ---------------------------------------------------------------------- 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; - } -} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultReader.java ---------------------------------------------------------------------- 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.api.job.JobId; 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 class ResultReader { 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(); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java ---------------------------------------------------------------------- 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 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen 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()); }); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/test/resources/runtimets/api.xml ---------------------------------------------------------------------- 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> http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_1/query_result_1.1.get.http ---------------------------------------------------------------------- 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]} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_2/query_result_2.1.get.http ---------------------------------------------------------------------- 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] http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_3/query_result_3.1.get.http ---------------------------------------------------------------------- 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 http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/query_result_4/query_result_4.1.get.http ---------------------------------------------------------------------- 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]} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java ---------------------------------------------------------------------- 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 class ErrorCode { 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; http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties ---------------------------------------------------------------------- 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 http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties ---------------------------------------------------------------------- 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. http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/hyracks-fullstack/hyracks/hyracks-client/src/main/java/org/apache/hyracks/client/dataset/HyracksDatasetReader.java ---------------------------------------------------------------------- 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 @@ public class HyracksDatasetReader implements IHyracksDatasetReader { resultChannel.registerMonitor(lastMonitor); resultChannel.open(datasetClientCtx); return true; + } catch (HyracksDataException e) { + throw e; } catch (Exception e) { throw new HyracksDataException(e); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/dataset/DatasetDirectoryService.java ---------------------------------------------------------------------- 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 @@ public class DatasetDirectoryService implements IDatasetDirectoryService { } @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 @@ public class DatasetDirectoryService implements IDatasetDirectoryService { 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 @@ public class DatasetDirectoryService implements IDatasetDirectoryService { @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 @@ public class DatasetDirectoryService implements IDatasetDirectoryService { @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 @@ public class DatasetDirectoryService implements IDatasetDirectoryService { * 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) { http://git-wip-us.apache.org/repos/asf/asterixdb/blob/3c764a42/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java ---------------------------------------------------------------------- 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.Level; 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 @@ public class ResultStateSweeper implements Runnable { 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); } }