You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by mb...@apache.org on 2017/08/27 22:46:18 UTC
asterixdb git commit: [NO ISSUE][TEST][CLUS] Update cluster state on
shutdown, testfwk looping
Repository: asterixdb
Updated Branches:
refs/heads/master 71589e574 -> 016603909
[NO ISSUE][TEST][CLUS] Update cluster state on shutdown, testfwk looping
- Set ClusterState to SHUTTING_DOWN when the cluster is shutting down
- Add ability to TestExecutor to loop over test files based on iteration count
or duration
Change-Id: I2bd67cb92a60d76eabe1e7649d16193dd72615dd
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1978
Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mh...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/01660390
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/01660390
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/01660390
Branch: refs/heads/master
Commit: 016603909756fef20f4504d4645adea60a9467e4
Parents: 71589e5
Author: Michael Blow <mb...@apache.org>
Authored: Sun Aug 27 16:03:57 2017 -0400
Committer: Michael Blow <mb...@apache.org>
Committed: Sun Aug 27 15:45:42 2017 -0700
----------------------------------------------------------------------
.../asterix/api/http/server/Duration.java | 236 -------------------
.../api/http/server/NCQueryServiceServlet.java | 1 +
.../api/http/server/QueryServiceServlet.java | 1 +
.../api/http/server/ShutdownApiServlet.java | 3 +
.../hyracks/bootstrap/CCApplication.java | 8 +-
.../asterix/runtime/ParseDurationTest.java | 2 +-
.../asterix/test/common/TestExecutor.java | 121 +++++++++-
.../api/diagnostics_1/diagnostics_1.2.loop.cmd | 21 ++
.../org/apache/asterix/common/api/Duration.java | 236 +++++++++++++++++++
.../common/api/IClusterManagementWork.java | 3 +-
10 files changed, 389 insertions(+), 243 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/Duration.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/Duration.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/Duration.java
deleted file mode 100644
index bdda750..0000000
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/Duration.java
+++ /dev/null
@@ -1,236 +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.server;
-
-import org.apache.asterix.common.exceptions.ErrorCode;
-import org.apache.asterix.common.exceptions.RuntimeDataException;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.commons.lang3.tuple.Triple;
-import org.apache.hyracks.api.exceptions.HyracksDataException;
-
-public enum Duration {
- SEC("s", 9),
- MILLI("ms", 6),
- MICRO("µs", 3),
- NANO("ns", 0);
-
- static final long NANOSECONDS = 1;
- static final long MICROSECONDS = 1000 * NANOSECONDS;
- static final long MILLISECONDS = 1000 * MICROSECONDS;
- static final long SECONDS = 1000 * MILLISECONDS;
- static final long MINUTES = 60 * SECONDS;
- static final long HOURS = 60 * MINUTES;
-
- String unit;
- int nanoDigits;
-
- Duration(String unit, int nanoDigits) {
- this.unit = unit;
- this.nanoDigits = nanoDigits;
- }
-
- public static String formatNanos(long nanoTime) {
- final String strTime = String.valueOf(nanoTime);
- final int len = strTime.length();
- for (Duration tu : Duration.values()) {
- if (len > tu.nanoDigits) {
- final String integer = strTime.substring(0, len - tu.nanoDigits);
- final String fractional = strTime.substring(len - tu.nanoDigits);
- return integer + (fractional.length() > 0 ? "." + fractional : "") + tu.unit;
- }
- }
- return "illegal string value: " + strTime;
- }
-
- // ParseDuration parses a duration string.
- // A duration string is a possibly signed sequence of
- // decimal numbers, each with optional fraction and a unit suffix,
- // such as "300ms", "-1.5h" or "2h45m".
- // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
- // returns the duration in nano seconds
- public static long parseDurationStringToNanos(String orig) throws HyracksDataException {
- // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
- String s = orig;
- long d = 0;
- boolean neg = false;
- char c;
- // Consume [-+]?
- if (!s.isEmpty()) {
- c = s.charAt(0);
- if (c == '-' || c == '+') {
- neg = c == '-';
- s = s.substring(1);
- }
- }
-
- // Special case: if all that is left is "0", this is zero.
- if ("0".equals(s)) {
- return 0L;
- }
-
- if (s.isEmpty()) {
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
-
- while (!s.isEmpty()) {
- long v = 0L; // integers before decimal
- long f = 0L; // integers after decimal
- double scale = 1.0; // value = v + f/scale
- // The next character must be [0-9.]
- if (!(s.charAt(0) == '.' || '0' <= s.charAt(0) && s.charAt(0) <= '9')) {
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
- // Consume [0-9]*
- int pl = s.length();
- Pair<Long, String> pair = leadingInt(s);
- v = pair.getLeft();
- s = pair.getRight();
- boolean pre = pl != s.length(); // whether we consumed anything before a period
-
- // Consume (\.[0-9]*)?
- boolean post = false;
- if (!s.isEmpty() && s.charAt(0) == '.') {
- s = s.substring(1);
- pl = s.length();
- Triple<Long, Double, String> triple = leadingFraction(s);
- f = triple.getLeft();
- scale = triple.getMiddle();
- s = triple.getRight();
- post = pl != s.length();
- }
- if (!pre && !post) {
- // no digits (e.g. ".s" or "-.s")
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
-
- // Consume unit.
- int i = 0;
- for (; i < s.length(); i++) {
- c = s.charAt(i);
- if (c == '.' || '0' <= c && c <= '9') {
- break;
- }
- }
- if (i == 0) {
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
- String u = s.substring(0, i);
- s = s.substring(i);
- long unit = getUnit(u);
- if (v > Long.MAX_VALUE / unit) {
- // overflow
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
- v *= unit;
- if (f > 0) {
- // float64 is needed to be nanosecond accurate for fractions of hours.
- // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
- v += (long) (((double) f * (double) unit) / scale);
- if (v < 0) {
- // overflow
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
- }
- d += v;
- if (d < 0) {
- // overflow
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
- }
- }
-
- if (neg) {
- d = -d;
- }
- return d;
- }
-
- private static final long getUnit(String unit) throws HyracksDataException {
- switch (unit) {
- case "ns":
- return NANOSECONDS;
- case "us":
- case "µs":// U+00B5 = micro symbol
- case "μs":// U+03BC = Greek letter mu
- return MICROSECONDS;
- case "ms":
- return MILLISECONDS;
- case "s":
- return SECONDS;
- case "m":
- return MINUTES;
- case "h":
- return HOURS;
- default:
- throw new RuntimeDataException(ErrorCode.UNKNOWN_DURATION_UNIT, unit);
- }
- }
-
- // leadingInt consumes the leading [0-9]* from s.
- static Pair<Long, String> leadingInt(String origin) throws HyracksDataException {
- String s = origin;
- long x = 0L;
- int i = 0;
- for (; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c < '0' || c > '9') {
- break;
- }
- if (x > Long.MAX_VALUE / 10) {
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, origin);
- }
- x = x * 10 + Character.getNumericValue(c);
- if (x < 0) {
- throw new RuntimeDataException(ErrorCode.INVALID_DURATION, origin);
- }
- }
- return Pair.of(x, s.substring(i));
- }
-
- // leadingFraction consumes the leading [0-9]* from s.
- // It is used only for fractions, so does not return an error on overflow,
- // it just stops accumulating precision.
- static Triple<Long, Double, String> leadingFraction(String s) {
- int i = 0;
- long x = 0L;
- double scale = 1.0;
- boolean overflow = false;
- for (; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c < '0' || c > '9') {
- break;
- }
- if (overflow) {
- continue;
- }
- if (x > (1 << 63 - 1) / 10) {
- // It's possible for overflow to give a positive number, so take care.
- overflow = true;
- continue;
- }
- long y = x * 10 + Character.getNumericValue(c);
- if (y < 0) {
- overflow = true;
- continue;
- }
- x = y;
- scale *= 10;
- }
- return Triple.of(x, scale, s.substring(i));
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
index 69e995b..8d355ef 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NCQueryServiceServlet.java
@@ -29,6 +29,7 @@ import org.apache.asterix.app.message.CancelQueryRequest;
import org.apache.asterix.app.message.ExecuteStatementRequestMessage;
import org.apache.asterix.app.message.ExecuteStatementResponseMessage;
import org.apache.asterix.app.result.ResultReader;
+import org.apache.asterix.common.api.Duration;
import org.apache.asterix.common.api.IApplicationContext;
import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.exceptions.ErrorCode;
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
----------------------------------------------------------------------
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 c630636..fa67190 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
@@ -27,6 +27,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.asterix.algebra.base.ILangExtension;
+import org.apache.asterix.common.api.Duration;
import org.apache.asterix.common.api.IApplicationContext;
import org.apache.asterix.common.api.IClusterManagementWork;
import org.apache.asterix.common.config.GlobalConfig;
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
index 06e2383..38f6691 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
@@ -19,6 +19,7 @@
package org.apache.asterix.api.http.server;
import static org.apache.asterix.api.http.server.ServletConstants.HYRACKS_CONNECTION_ATTR;
+import static org.apache.asterix.common.api.IClusterManagementWork.ClusterState.SHUTTING_DOWN;
import java.io.IOException;
import java.io.PrintWriter;
@@ -92,6 +93,8 @@ public class ShutdownApiServlet extends AbstractServlet {
jsonObject.set("cluster", clusterState);
final PrintWriter writer = response.writer();
writer.print(JSONUtil.convertNode(jsonObject));
+ // accept no further queries once this servlet returns
+ ClusterStateManager.INSTANCE.setState(SHUTTING_DOWN);
writer.close();
} catch (Exception e) {
GlobalConfig.ASTERIX_LOGGER.log(Level.INFO, "Exception writing response", e);
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
index b08c1e2..6d817b8 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java
@@ -23,6 +23,7 @@ import static org.apache.asterix.algebra.base.ILangExtension.Language.AQL;
import static org.apache.asterix.algebra.base.ILangExtension.Language.SQLPP;
import static org.apache.asterix.api.http.server.ServletConstants.ASTERIX_APP_CONTEXT_INFO_ATTR;
import static org.apache.asterix.api.http.server.ServletConstants.HYRACKS_CONNECTION_ATTR;
+import static org.apache.asterix.common.api.IClusterManagementWork.ClusterState.SHUTTING_DOWN;
import java.util.Arrays;
import java.util.List;
@@ -187,12 +188,13 @@ public class CCApplication extends BaseCCApplication {
@Override
public void stop() throws Exception {
- if (appCtx != null) {
- ((ActiveNotificationHandler) appCtx.getActiveNotificationHandler()).stop();
- }
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.info("Stopping Asterix cluster controller");
}
+ ClusterStateManager.INSTANCE.setState(SHUTTING_DOWN);
+ if (appCtx != null) {
+ ((ActiveNotificationHandler) appCtx.getActiveNotificationHandler()).stop();
+ }
AsterixStateProxy.unregisterRemoteObject();
webManager.stop();
}
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ParseDurationTest.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ParseDurationTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ParseDurationTest.java
index 12c61d6..f2fb580 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ParseDurationTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/runtime/ParseDurationTest.java
@@ -18,7 +18,7 @@
*/
package org.apache.asterix.runtime;
-import org.apache.asterix.api.http.server.Duration;
+import org.apache.asterix.common.api.Duration;
import org.apache.hyracks.api.exceptions.HyracksDataException;
import org.junit.Assert;
import org.junit.Test;
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index e07ec72..cfd01ac 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -43,6 +43,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -56,6 +57,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.asterix.common.api.Duration;
import org.apache.asterix.common.config.GlobalConfig;
import org.apache.asterix.common.utils.Servlets;
import org.apache.asterix.test.server.ITestServer;
@@ -131,6 +133,7 @@ public class TestExecutor {
protected final List<InetSocketAddress> endpoints;
protected int endpointSelector;
protected ITestLibrarian librarian;
+ private Map<File, TestLoop> testLoops = new HashMap<>();
public TestExecutor() {
this(Inet4Address.getLoopbackAddress().getHostAddress(), 19002);
@@ -1080,6 +1083,59 @@ public class TestExecutor {
killNC(nodeId, cUnit);
}
break;
+ case "loop":
+ TestLoop testLoop = testLoops.get(testFile);
+ if (testLoop == null) {
+ lines = stripAllComments(statement).trim().split("\n");
+ String target = null;
+ int count = -1;
+ long durationSecs = -1;
+ for (String line : lines) {
+ command = line.trim().split(" ");
+ switch (command[0]) {
+ case "target":
+ if (target != null) {
+ throw new IllegalStateException("duplicate target");
+ }
+ target = command[1];
+ break;
+ case "count":
+ if (count != -1) {
+ throw new IllegalStateException("duplicate count");
+ }
+ count = Integer.parseInt(command[1]);
+ break;
+ case "duration":
+ if (durationSecs != -1) {
+ throw new IllegalStateException("duplicate duration");
+ }
+ long duration = Duration.parseDurationStringToNanos(command[1]);
+ durationSecs = TimeUnit.NANOSECONDS.toSeconds(duration);
+ if (durationSecs < 1) {
+ throw new IllegalArgumentException("duration cannot be shorter than 1s");
+ } else if (TimeUnit.SECONDS.toDays(durationSecs) > 1) {
+ throw new IllegalArgumentException("duration cannot be exceed 1d");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("unknown directive: " + command[0]);
+ }
+ }
+ if (target == null || (count == -1 && durationSecs == -1) || (count != -1 && durationSecs != -1)) {
+ throw new IllegalStateException("Must specify 'target' and exactly one of 'count', 'duration'");
+ }
+ if (count != -1) {
+ testLoop = TestLoop.createLoop(target, count);
+ } else {
+ testLoop = TestLoop.createLoop(target, durationSecs, TimeUnit.SECONDS);
+ }
+ testLoops.put(testFile, testLoop);
+ }
+ testLoop.executeLoop();
+ // we only reach here if the loop is over
+ testLoops.remove(testFile);
+ break;
+
default:
throw new IllegalArgumentException("No statements of type " + ctx.getType());
}
@@ -1089,7 +1145,7 @@ public class TestExecutor {
String reqType, File testFile, File expectedResultFile, File actualResultFile, MutableInt queryCount,
int numResultFiles, String extension, ComparisonEnum compare) throws Exception {
String handleVar = getHandleVariable(statement);
- final String trimmedPathAndQuery = stripLineComments(stripJavaComments(statement)).trim();
+ final String trimmedPathAndQuery = stripAllComments(statement).trim();
final String variablesReplaced = replaceVarRef(trimmedPathAndQuery, variableCtx);
final List<Parameter> params = extractParameters(statement);
final Predicate<Integer> statusCodePredicate = extractStatusCodePredicate(statement);
@@ -1361,13 +1417,26 @@ public class TestExecutor {
Map<String, Object> variableCtx = new HashMap<>();
List<TestFileContext> testFileCtxs = testCaseCtx.getTestFiles(cUnit);
List<TestFileContext> expectedResultFileCtxs = testCaseCtx.getExpectedResultFiles(cUnit);
- for (TestFileContext ctx : testFileCtxs) {
+ int[] savedQueryCounts = new int[numOfFiles + testFileCtxs.size()];
+ for (ListIterator<TestFileContext> iter = testFileCtxs.listIterator(); iter.hasNext();) {
+ TestFileContext ctx = iter.next();
+ savedQueryCounts[numOfFiles] = queryCount.getValue();
numOfFiles++;
final File testFile = ctx.getFile();
final String statement = readTestFile(testFile);
try {
executeTestFile(testCaseCtx, ctx, variableCtx, statement, isDmlRecoveryTest, pb, cUnit, queryCount,
expectedResultFileCtxs, testFile, actualPath);
+ } catch (TestLoop loop) {
+ // rewind the iterator until we find our target
+ while (!ctx.getFile().getName().equals(loop.getTarget())) {
+ if (!iter.hasPrevious()) {
+ throw new IllegalStateException("unable to find loop target '" + loop.getTarget() + "'!");
+ }
+ ctx = iter.previous();
+ numOfFiles--;
+ queryCount.setValue(savedQueryCounts[numOfFiles]);
+ }
} catch (Exception e) {
System.err.println("testFile " + testFile.toString() + " raised an exception: " + e);
numOfErrors++;
@@ -1442,6 +1511,10 @@ public class TestExecutor {
return JAVA_LINE_COMMENT_PATTERN.matcher(s).replaceAll("");
}
+ public static String stripAllComments(String statement) {
+ return stripLineComments(stripJavaComments(statement));
+ }
+
public void cleanup(String testCase, List<String> badtestcases) throws Exception {
try {
ArrayList<String> toBeDropped = new ArrayList<>();
@@ -1531,4 +1604,48 @@ public class TestExecutor {
LOGGER.info("Cluster state now " + desiredState);
}
+ abstract static class TestLoop extends Exception {
+
+ private final String target;
+
+ TestLoop(String target) {
+ this.target = target;
+ }
+
+ static TestLoop createLoop(String target, final int count) {
+ LOGGER.info("Starting loop '" + count + " times back to '" + target + "'...");
+ return new TestLoop(target) {
+ int remainingLoops = count;
+
+ @Override
+ void executeLoop() throws TestLoop {
+ if (remainingLoops-- > 0) {
+ throw this;
+ }
+ LOGGER.info("Loop to '" + target + "' complete!");
+ }
+ };
+ }
+
+ static TestLoop createLoop(String target, long duration, TimeUnit unit) {
+ LOGGER.info("Starting loop for " + unit.toSeconds(duration) + "s back to '" + target + "'...");
+ return new TestLoop(target) {
+ long endTime = unit.toMillis(duration) + System.currentTimeMillis();
+
+ @Override
+ void executeLoop() throws TestLoop {
+ if (System.currentTimeMillis() < endTime) {
+ throw this;
+ }
+ LOGGER.info("Loop to '" + target + "' complete!");
+ }
+ };
+ }
+
+ abstract void executeLoop() throws TestLoop;
+
+ public String getTarget() {
+ return target;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/diagnostics_1/diagnostics_1.2.loop.cmd
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/diagnostics_1/diagnostics_1.2.loop.cmd b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/diagnostics_1/diagnostics_1.2.loop.cmd
new file mode 100644
index 0000000..2660b46
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/api/diagnostics_1/diagnostics_1.2.loop.cmd
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+target diagnostics_1.1.get.http
+count 2
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/Duration.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/Duration.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/Duration.java
new file mode 100644
index 0000000..4338222
--- /dev/null
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/Duration.java
@@ -0,0 +1,236 @@
+/*
+ * 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.common.api;
+
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.exceptions.RuntimeDataException;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public enum Duration {
+ SEC("s", 9),
+ MILLI("ms", 6),
+ MICRO("µs", 3),
+ NANO("ns", 0);
+
+ static final long NANOSECONDS = 1;
+ static final long MICROSECONDS = 1000 * NANOSECONDS;
+ static final long MILLISECONDS = 1000 * MICROSECONDS;
+ static final long SECONDS = 1000 * MILLISECONDS;
+ static final long MINUTES = 60 * SECONDS;
+ static final long HOURS = 60 * MINUTES;
+
+ String unit;
+ int nanoDigits;
+
+ Duration(String unit, int nanoDigits) {
+ this.unit = unit;
+ this.nanoDigits = nanoDigits;
+ }
+
+ public static String formatNanos(long nanoTime) {
+ final String strTime = String.valueOf(nanoTime);
+ final int len = strTime.length();
+ for (Duration tu : Duration.values()) {
+ if (len > tu.nanoDigits) {
+ final String integer = strTime.substring(0, len - tu.nanoDigits);
+ final String fractional = strTime.substring(len - tu.nanoDigits);
+ return integer + (fractional.length() > 0 ? "." + fractional : "") + tu.unit;
+ }
+ }
+ return "illegal string value: " + strTime;
+ }
+
+ // ParseDuration parses a duration string.
+ // A duration string is a possibly signed sequence of
+ // decimal numbers, each with optional fraction and a unit suffix,
+ // such as "300ms", "-1.5h" or "2h45m".
+ // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+ // returns the duration in nano seconds
+ public static long parseDurationStringToNanos(String orig) throws HyracksDataException {
+ // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
+ String s = orig;
+ long d = 0;
+ boolean neg = false;
+ char c;
+ // Consume [-+]?
+ if (!s.isEmpty()) {
+ c = s.charAt(0);
+ if (c == '-' || c == '+') {
+ neg = c == '-';
+ s = s.substring(1);
+ }
+ }
+
+ // Special case: if all that is left is "0", this is zero.
+ if ("0".equals(s)) {
+ return 0L;
+ }
+
+ if (s.isEmpty()) {
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+
+ while (!s.isEmpty()) {
+ long v = 0L; // integers before decimal
+ long f = 0L; // integers after decimal
+ double scale = 1.0; // value = v + f/scale
+ // The next character must be [0-9.]
+ if (!(s.charAt(0) == '.' || '0' <= s.charAt(0) && s.charAt(0) <= '9')) {
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+ // Consume [0-9]*
+ int pl = s.length();
+ Pair<Long, String> pair = leadingInt(s);
+ v = pair.getLeft();
+ s = pair.getRight();
+ boolean pre = pl != s.length(); // whether we consumed anything before a period
+
+ // Consume (\.[0-9]*)?
+ boolean post = false;
+ if (!s.isEmpty() && s.charAt(0) == '.') {
+ s = s.substring(1);
+ pl = s.length();
+ Triple<Long, Double, String> triple = leadingFraction(s);
+ f = triple.getLeft();
+ scale = triple.getMiddle();
+ s = triple.getRight();
+ post = pl != s.length();
+ }
+ if (!pre && !post) {
+ // no digits (e.g. ".s" or "-.s")
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+
+ // Consume unit.
+ int i = 0;
+ for (; i < s.length(); i++) {
+ c = s.charAt(i);
+ if (c == '.' || '0' <= c && c <= '9') {
+ break;
+ }
+ }
+ if (i == 0) {
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+ String u = s.substring(0, i);
+ s = s.substring(i);
+ long unit = getUnit(u);
+ if (v > Long.MAX_VALUE / unit) {
+ // overflow
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+ v *= unit;
+ if (f > 0) {
+ // float64 is needed to be nanosecond accurate for fractions of hours.
+ // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
+ v += (long) (((double) f * (double) unit) / scale);
+ if (v < 0) {
+ // overflow
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+ }
+ d += v;
+ if (d < 0) {
+ // overflow
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, orig);
+ }
+ }
+
+ if (neg) {
+ d = -d;
+ }
+ return d;
+ }
+
+ private static final long getUnit(String unit) throws HyracksDataException {
+ switch (unit) {
+ case "ns":
+ return NANOSECONDS;
+ case "us":
+ case "µs":// U+00B5 = micro symbol
+ case "μs":// U+03BC = Greek letter mu
+ return MICROSECONDS;
+ case "ms":
+ return MILLISECONDS;
+ case "s":
+ return SECONDS;
+ case "m":
+ return MINUTES;
+ case "h":
+ return HOURS;
+ default:
+ throw new RuntimeDataException(ErrorCode.UNKNOWN_DURATION_UNIT, unit);
+ }
+ }
+
+ // leadingInt consumes the leading [0-9]* from s.
+ static Pair<Long, String> leadingInt(String origin) throws HyracksDataException {
+ String s = origin;
+ long x = 0L;
+ int i = 0;
+ for (; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c < '0' || c > '9') {
+ break;
+ }
+ if (x > Long.MAX_VALUE / 10) {
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, origin);
+ }
+ x = x * 10 + Character.getNumericValue(c);
+ if (x < 0) {
+ throw new RuntimeDataException(ErrorCode.INVALID_DURATION, origin);
+ }
+ }
+ return Pair.of(x, s.substring(i));
+ }
+
+ // leadingFraction consumes the leading [0-9]* from s.
+ // It is used only for fractions, so does not return an error on overflow,
+ // it just stops accumulating precision.
+ static Triple<Long, Double, String> leadingFraction(String s) {
+ int i = 0;
+ long x = 0L;
+ double scale = 1.0;
+ boolean overflow = false;
+ for (; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c < '0' || c > '9') {
+ break;
+ }
+ if (overflow) {
+ continue;
+ }
+ if (x > (1 << 63 - 1) / 10) {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true;
+ continue;
+ }
+ long y = x * 10 + Character.getNumericValue(c);
+ if (y < 0) {
+ overflow = true;
+ continue;
+ }
+ x = y;
+ scale *= 10;
+ }
+ return Triple.of(x, scale, s.substring(i));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/01660390/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterManagementWork.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterManagementWork.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterManagementWork.java
index 323df65..bdbf4a5 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterManagementWork.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/api/IClusterManagementWork.java
@@ -30,7 +30,8 @@ public interface IClusterManagementWork {
PENDING,
ACTIVE,
UNUSABLE,
- REBALANCING
+ REBALANCING,
+ SHUTTING_DOWN
}
public WorkType getClusterManagementWorkType();