[NO ISSUE][CONFIG] Avoid integer overflow on option parse
- Do not use Integer.parseUnsignedInt() for nonnegative integer option parsing, as
this will result in negative numbers for values > 0x7fffffff
- Renamed (OptionTypes.)UNSIGNED_INTEGER to NONNEGATIVE_INTEGER for clarity
- Add POSITIVE_INTEGER_BYTE_UNIT & POSITIVE_LONG_BYTE_UNIT option types
(includes cherry-pick of commit 7a99fcefe3)
Change-Id: I03bc9e92c2b6ce48977e93966f6cb9160c4df893
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/10003
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Michael Blow <mblow@apache.org>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
index 9428e6f..8860495 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/CompilerProperties.java
@@ -23,7 +23,6 @@
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import static org.apache.hyracks.util.StorageUtil.StorageUnit.KILOBYTE;
import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
@@ -31,6 +30,7 @@
import org.apache.hyracks.api.config.IOption;
import org.apache.hyracks.api.config.IOptionType;
import org.apache.hyracks.api.config.Section;
+import org.apache.hyracks.control.common.config.OptionTypes;
import org.apache.hyracks.util.StorageUtil;
public class CompilerProperties extends AbstractProperties {
@@ -68,7 +68,10 @@
+ "other integer values dictate the number of query execution parallel partitions. The system will "
+ "fall back to use the number of all available CPU cores in the cluster as the degree of parallelism "
+ "if the number set by a user is too large or too small"),
- COMPILER_STRINGOFFSET(UNSIGNED_INTEGER, 0, "Position of a first character in a String/Binary (0 or 1)"),
+ COMPILER_STRINGOFFSET(
+ OptionTypes.getRangedIntegerType(0, 1),
+ 0,
+ "Position of a first character in a String/Binary (0 or 1)"),
COMPILER_SORT_PARALLEL(BOOLEAN, AlgebricksConfig.SORT_PARALLEL, "Enabling/Disabling full parallel sort"),
COMPILER_SORT_SAMPLES(
POSITIVE_INTEGER,
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
index 1533c9f..642cbd6 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ExternalProperties.java
@@ -19,9 +19,10 @@
package org.apache.asterix.common.config;
import static org.apache.hyracks.control.common.config.OptionTypes.LEVEL;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
+import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import org.apache.hyracks.api.config.IOption;
import org.apache.hyracks.api.config.IOptionType;
@@ -32,11 +33,11 @@
public class ExternalProperties extends AbstractProperties {
public enum Option implements IOption {
- WEB_PORT(UNSIGNED_INTEGER, 19001, "The listen port of the legacy query interface"),
- WEB_QUERYINTERFACE_PORT(UNSIGNED_INTEGER, 19006, "The listen port of the query web interface"),
- API_PORT(UNSIGNED_INTEGER, 19002, "The listen port of the API server"),
- ACTIVE_PORT(UNSIGNED_INTEGER, 19003, "The listen port of the active server"),
- NC_API_PORT(UNSIGNED_INTEGER, 19004, "The listen port of the node controller API server"),
+ WEB_PORT(NONNEGATIVE_INTEGER, 19001, "The listen port of the legacy query interface"),
+ WEB_QUERYINTERFACE_PORT(NONNEGATIVE_INTEGER, 19006, "The listen port of the query web interface"),
+ API_PORT(NONNEGATIVE_INTEGER, 19002, "The listen port of the API server"),
+ ACTIVE_PORT(NONNEGATIVE_INTEGER, 19003, "The listen port of the active server"),
+ NC_API_PORT(NONNEGATIVE_INTEGER, 19004, "The listen port of the node controller API server"),
LOG_LEVEL(LEVEL, Level.WARN, "The logging level for master and slave processes"),
MAX_WAIT_ACTIVE_CLUSTER(
POSITIVE_INTEGER,
@@ -46,10 +47,10 @@
CC_JAVA_OPTS(STRING, "-Xmx1024m", "The JVM options passed to the cluster controller process by managix"),
NC_JAVA_OPTS(STRING, "-Xmx1024m", "The JVM options passed to the node controller process(es) by managix"),
MAX_WEB_REQUEST_SIZE(
- UNSIGNED_INTEGER,
+ POSITIVE_INTEGER_BYTE_UNIT,
StorageUtil.getIntSizeInBytes(50, StorageUtil.StorageUnit.MEGABYTE),
"The maximum accepted web request size in bytes"),
- REQUESTS_ARCHIVE_SIZE(UNSIGNED_INTEGER, 50, "The maximum number of archived requests to maintain");
+ REQUESTS_ARCHIVE_SIZE(NONNEGATIVE_INTEGER, 50, "The maximum number of archived requests to maintain");
private final IOptionType type;
private final Object defaultValue;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
index 7a3e707..7d5ec42 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/MetadataProperties.java
@@ -18,9 +18,9 @@
*/
package org.apache.asterix.common.config;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import java.util.List;
import java.util.Map;
@@ -37,8 +37,8 @@
public enum Option implements IOption {
METADATA_NODE(STRING, null),
METADATA_REGISTRATION_TIMEOUT_SECS(POSITIVE_INTEGER, 60),
- METADATA_LISTEN_PORT(UNSIGNED_INTEGER, 0),
- METADATA_CALLBACK_PORT(UNSIGNED_INTEGER, 0);
+ METADATA_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
+ METADATA_CALLBACK_PORT(NONNEGATIVE_INTEGER, 0);
private final IOptionType type;
private final Object defaultValue;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
index 6082f30..dd42936 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/ReplicationProperties.java
@@ -21,9 +21,9 @@
import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import java.util.concurrent.TimeUnit;
@@ -51,7 +51,7 @@
TimeUnit.SECONDS.toSeconds(30),
"The time in seconds to timeout waiting for master or replica to ack"),
REPLICATION_ENABLED(BOOLEAN, false, "Whether or not data replication is enabled"),
- REPLICATION_FACTOR(UNSIGNED_INTEGER, 2, "Number of replicas (backups) to maintain per master replica"),
+ REPLICATION_FACTOR(NONNEGATIVE_INTEGER, 2, "Number of replicas (backups) to maintain per master replica"),
REPLICATION_STRATEGY(STRING, "none", "Replication strategy to choose");
private final IOptionType type;
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
index 58bc828..0bea099 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/StorageProperties.java
@@ -21,9 +21,9 @@
import static org.apache.hyracks.control.common.config.OptionTypes.DOUBLE;
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import static org.apache.hyracks.util.StorageUtil.StorageUnit.KILOBYTE;
import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
@@ -43,13 +43,13 @@
STORAGE_BUFFERCACHE_PAGESIZE(INTEGER_BYTE_UNIT, StorageUtil.getIntSizeInBytes(128, KILOBYTE)),
// By default, uses 1/4 of the maximum heap size for read cache, i.e., disk buffer cache.
STORAGE_BUFFERCACHE_SIZE(LONG_BYTE_UNIT, Runtime.getRuntime().maxMemory() / 4),
- STORAGE_BUFFERCACHE_MAXOPENFILES(UNSIGNED_INTEGER, Integer.MAX_VALUE),
+ STORAGE_BUFFERCACHE_MAXOPENFILES(NONNEGATIVE_INTEGER, Integer.MAX_VALUE),
STORAGE_MEMORYCOMPONENT_GLOBALBUDGET(LONG_BYTE_UNIT, Runtime.getRuntime().maxMemory() / 4),
STORAGE_MEMORYCOMPONENT_PAGESIZE(INTEGER_BYTE_UNIT, StorageUtil.getIntSizeInBytes(128, KILOBYTE)),
STORAGE_MEMORYCOMPONENT_NUMCOMPONENTS(POSITIVE_INTEGER, 2),
STORAGE_METADATA_MEMORYCOMPONENT_NUMPAGES(POSITIVE_INTEGER, 8),
STORAGE_LSM_BLOOMFILTER_FALSEPOSITIVERATE(DOUBLE, 0.01d),
- STORAGE_MAX_ACTIVE_WRITABLE_DATASETS(UNSIGNED_INTEGER, 8),
+ STORAGE_MAX_ACTIVE_WRITABLE_DATASETS(POSITIVE_INTEGER, 8),
STORAGE_COMPRESSION_BLOCK(STRING, "snappy"),
STORAGE_DISK_FORCE_BYTES(LONG_BYTE_UNIT, StorageUtil.getLongSizeInBytes(16, MEGABYTE)),
STORAGE_IO_SCHEDULER(STRING, "greedy");
diff --git a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
index 5ed069c..f813ac3 100644
--- a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
+++ b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/config/TransactionProperties.java
@@ -21,8 +21,8 @@
import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG_BYTE_UNIT;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import static org.apache.hyracks.util.StorageUtil.StorageUnit.MEGABYTE;
import java.util.Map;
@@ -59,9 +59,9 @@
120,
"The frequency (in seconds) the checkpoint thread should check to see if a checkpoint should be "
+ "written"),
- TXN_LOG_CHECKPOINT_HISTORY(UNSIGNED_INTEGER, 2, "The number of checkpoints to keep in the transaction log"),
+ TXN_LOG_CHECKPOINT_HISTORY(NONNEGATIVE_INTEGER, 2, "The number of checkpoints to keep in the transaction log"),
TXN_LOCK_ESCALATIONTHRESHOLD(
- UNSIGNED_INTEGER,
+ NONNEGATIVE_INTEGER,
1000,
"The maximum number of entity locks to obtain before upgrading to a dataset lock"),
TXN_LOCK_SHRINKTIMER(
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
index 7088e08..332d65b 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/config/OptionTypes.java
@@ -33,66 +33,11 @@
public class OptionTypes {
- public static final IOptionType<Integer> INTEGER_BYTE_UNIT = new IOptionType<Integer>() {
- @Override
- public Integer parse(String s) {
- if (s == null) {
- return null;
- }
- long result1 = StorageUtil.getByteValue(s);
- if (result1 > Integer.MAX_VALUE || result1 < Integer.MIN_VALUE) {
- throw new IllegalArgumentException("The given value: " + result1 + " is not within the int range.");
- }
- return (int) result1;
- }
+ public static final IOptionType<Integer> INTEGER_BYTE_UNIT = new IntegerByteUnit();
+ public static final IOptionType<Integer> POSITIVE_INTEGER_BYTE_UNIT = new IntegerByteUnit(1, Integer.MAX_VALUE);
- @Override
- public Integer parse(JsonNode node) {
- return node.isNull() ? null : parse(node.asText());
- }
-
- @Override
- public Class<Integer> targetType() {
- return Integer.class;
- }
-
- @Override
- public String serializeToHumanReadable(Object value) {
- return value + " (" + StorageUtil.toHumanReadableSize((int) value) + ")";
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (int) value);
- }
- };
-
- public static final IOptionType<Long> LONG_BYTE_UNIT = new IOptionType<Long>() {
- @Override
- public Long parse(String s) {
- return s == null ? null : StorageUtil.getByteValue(s);
- }
-
- @Override
- public Long parse(JsonNode node) {
- return node.isNull() ? null : parse(node.asText());
- }
-
- @Override
- public Class<Long> targetType() {
- return Long.class;
- }
-
- @Override
- public String serializeToHumanReadable(Object value) {
- return value + " (" + StorageUtil.toHumanReadableSize((long) value) + ")";
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (long) value);
- }
- };
+ public static final IOptionType<Long> LONG_BYTE_UNIT = new LongByteUnit();
+ public static final IOptionType<Long> POSITIVE_LONG_BYTE_UNIT = new LongByteUnit(1, Long.MAX_VALUE);
public static final IOptionType<Short> SHORT = new IOptionType<Short>() {
@Override
@@ -124,27 +69,7 @@
}
};
- public static final IOptionType<Integer> INTEGER = new IOptionType<Integer>() {
- @Override
- public Integer parse(String s) {
- return Integer.parseInt(s);
- }
-
- @Override
- public Integer parse(JsonNode node) {
- return node.isNull() ? null : node.asInt();
- }
-
- @Override
- public Class<Integer> targetType() {
- return Integer.class;
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (int) value);
- }
- };
+ public static final IOptionType<Integer> INTEGER = new IntegerOptionType();
public static final IOptionType<Double> DOUBLE = new IOptionType<Double>() {
@Override
@@ -190,27 +115,7 @@
}
};
- public static final IOptionType<Long> LONG = new IOptionType<Long>() {
- @Override
- public Long parse(String s) {
- return Long.parseLong(s);
- }
-
- @Override
- public Long parse(JsonNode node) {
- return node.isNull() ? null : node.asLong();
- }
-
- @Override
- public Class<Long> targetType() {
- return Long.class;
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (long) value);
- }
- };
+ public static final IOptionType<Long> LONG = new LongOptionType();
public static final IOptionType<Boolean> BOOLEAN = new IOptionType<Boolean>() {
@Override
@@ -287,7 +192,7 @@
List<String> strings = new ArrayList<>();
if (node instanceof ArrayNode) {
node.elements().forEachRemaining(n -> strings.add(n.asText()));
- return strings.toArray(new String[strings.size()]);
+ return strings.toArray(new String[0]);
} else {
return parse(node.asText());
}
@@ -340,54 +245,186 @@
}
};
- public static final IOptionType<Integer> UNSIGNED_INTEGER = new IOptionType<Integer>() {
- @Override
- public Integer parse(String s) {
- return Integer.parseUnsignedInt(s);
- }
+ public static final IOptionType<Integer> NONNEGATIVE_INTEGER = getRangedIntegerType(0, Integer.MAX_VALUE);
- @Override
- public Integer parse(JsonNode node) {
- return node.isNull() ? null : parse(node.asText());
- }
-
- @Override
- public Class<Integer> targetType() {
- return Integer.class;
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (int) value);
- }
- };
-
- public static final IOptionType<Integer> POSITIVE_INTEGER = new IOptionType<Integer>() {
- @Override
- public Integer parse(String s) {
- final int value = Integer.parseUnsignedInt(s);
- if (value == 0) {
- throw new IllegalArgumentException("Value must be greater than zero");
- }
- return value;
- }
-
- @Override
- public Integer parse(JsonNode node) {
- return node.isNull() ? null : parse(node.asText());
- }
-
- @Override
- public Class<Integer> targetType() {
- return Integer.class;
- }
-
- @Override
- public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
- node.put(fieldName, (int) value);
- }
- };
+ public static final IOptionType<Integer> POSITIVE_INTEGER = getRangedIntegerType(1, Integer.MAX_VALUE);
private OptionTypes() {
}
+
+ public static IOptionType<Integer> getRangedIntegerType(final int minValueInclusive, final int maxValueInclusive) {
+ return new RangedIntegerOptionType(minValueInclusive, maxValueInclusive);
+ }
+
+ public static class IntegerOptionType implements IOptionType<Integer> {
+ @Override
+ public Integer parse(String s) {
+ return Integer.parseInt(s);
+ }
+
+ @Override
+ public Integer parse(JsonNode node) {
+ return node.isNull() ? null : node.asInt();
+ }
+
+ @Override
+ public Class<Integer> targetType() {
+ return Integer.class;
+ }
+
+ @Override
+ public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
+ node.put(fieldName, (int) value);
+ }
+ }
+
+ private static class RangedIntegerOptionType extends IntegerOptionType {
+ private final int minValue;
+ private final int maxValue;
+
+ RangedIntegerOptionType(int minValue, int maxValue) {
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ @Override
+ public Integer parse(String value) {
+ int intValue = super.parse(value);
+ rangeCheck(intValue);
+ return intValue;
+ }
+
+ void rangeCheck(long intValue) {
+ if (intValue < minValue || intValue > maxValue) {
+ if (maxValue == Integer.MAX_VALUE) {
+ if (minValue == 0) {
+ throw new IllegalArgumentException("integer value must not be negative, but was " + intValue);
+ } else if (minValue == 1) {
+ throw new IllegalArgumentException(
+ "integer value must be greater than zero, but was " + intValue);
+ }
+ }
+ throw new IllegalArgumentException(
+ "integer value must be between " + minValue + "-" + maxValue + " (inclusive)");
+ }
+ }
+ }
+
+ private static class IntegerByteUnit extends RangedIntegerOptionType {
+
+ IntegerByteUnit() {
+ this(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ IntegerByteUnit(int minValue, int maxValue) {
+ super(minValue, maxValue);
+ }
+
+ @Override
+ public Integer parse(String s) {
+ if (s == null) {
+ return null;
+ }
+ long result = StorageUtil.getByteValue(s);
+ rangeCheck(result);
+ return (int) result;
+ }
+
+ @Override
+ public Integer parse(JsonNode node) {
+ // TODO: we accept human readable sizes from json- why not emit human readable sizes?
+ return node.isNull() ? null : parse(node.asText());
+ }
+
+ @Override
+ public String serializeToHumanReadable(Object value) {
+ return value + " (" + StorageUtil.toHumanReadableSize((int) value) + ")";
+ }
+ }
+
+ private static class RangedLongOptionType extends LongOptionType {
+ private final long minValue;
+ private final long maxValue;
+
+ RangedLongOptionType(long minValue, long maxValue) {
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ }
+
+ @Override
+ public Long parse(String value) {
+ long longValue = super.parse(value);
+ rangeCheck(longValue);
+ return longValue;
+ }
+
+ void rangeCheck(long longValue) {
+ if (longValue < minValue || longValue > maxValue) {
+ if (maxValue == Long.MAX_VALUE) {
+ if (minValue == 0) {
+ throw new IllegalArgumentException("long value must not be negative, but was " + longValue);
+ } else if (minValue == 1) {
+ throw new IllegalArgumentException(
+ "long value must be greater than zero, but was " + longValue);
+ }
+ }
+ throw new IllegalArgumentException(
+ "long value must be between " + minValue + "-" + maxValue + " (inclusive)");
+ }
+ }
+ }
+
+ private static class LongByteUnit extends RangedLongOptionType {
+
+ LongByteUnit() {
+ this(Long.MIN_VALUE, Long.MAX_VALUE);
+ }
+
+ LongByteUnit(long minValue, long maxValue) {
+ super(minValue, maxValue);
+ }
+
+ @Override
+ public Long parse(String s) {
+ if (s == null) {
+ return null;
+ }
+ long result = StorageUtil.getByteValue(s);
+ rangeCheck(result);
+ return result;
+ }
+
+ @Override
+ public Long parse(JsonNode node) {
+ // TODO: we accept human readable sizes from json- why not emit human readable sizes?
+ return node.isNull() ? null : parse(node.asText());
+ }
+
+ @Override
+ public String serializeToHumanReadable(Object value) {
+ return value + " (" + StorageUtil.toHumanReadableSize((long) value) + ")";
+ }
+ }
+
+ private static class LongOptionType implements IOptionType<Long> {
+ @Override
+ public Long parse(String s) {
+ return Long.parseLong(s);
+ }
+
+ @Override
+ public Long parse(JsonNode node) {
+ return node.isNull() ? null : node.asLong();
+ }
+
+ @Override
+ public Class<Long> targetType() {
+ return Long.class;
+ }
+
+ @Override
+ public void serializeJSONField(String fieldName, Object value, ObjectNode node) {
+ node.put(fieldName, (long) value);
+ }
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
index 0de75d9..17be02e 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/CCConfig.java
@@ -20,10 +20,10 @@
import static org.apache.hyracks.control.common.config.OptionTypes.BOOLEAN;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.SHORT;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import java.io.File;
import java.net.InetAddress;
@@ -49,22 +49,22 @@
ADDRESS(STRING, InetAddress.getLoopbackAddress().getHostAddress()),
PUBLIC_ADDRESS(STRING, ADDRESS),
CLUSTER_LISTEN_ADDRESS(STRING, ADDRESS),
- CLUSTER_LISTEN_PORT(UNSIGNED_INTEGER, 1099),
+ CLUSTER_LISTEN_PORT(NONNEGATIVE_INTEGER, 1099),
CLUSTER_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- CLUSTER_PUBLIC_PORT(UNSIGNED_INTEGER, CLUSTER_LISTEN_PORT),
+ CLUSTER_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLUSTER_LISTEN_PORT),
CLIENT_LISTEN_ADDRESS(STRING, ADDRESS),
- CLIENT_LISTEN_PORT(UNSIGNED_INTEGER, 1098),
+ CLIENT_LISTEN_PORT(NONNEGATIVE_INTEGER, 1098),
CLIENT_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- CLIENT_PUBLIC_PORT(UNSIGNED_INTEGER, CLIENT_LISTEN_PORT),
+ CLIENT_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLIENT_LISTEN_PORT),
CONSOLE_LISTEN_ADDRESS(STRING, ADDRESS),
- CONSOLE_LISTEN_PORT(UNSIGNED_INTEGER, 16001),
+ CONSOLE_LISTEN_PORT(NONNEGATIVE_INTEGER, 16001),
CONSOLE_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- CONSOLE_PUBLIC_PORT(UNSIGNED_INTEGER, CONSOLE_LISTEN_PORT),
+ CONSOLE_PUBLIC_PORT(NONNEGATIVE_INTEGER, CONSOLE_LISTEN_PORT),
HEARTBEAT_PERIOD(LONG, 10000L), // TODO (mblow): add time unit
- HEARTBEAT_MAX_MISSES(UNSIGNED_INTEGER, 5),
+ HEARTBEAT_MAX_MISSES(NONNEGATIVE_INTEGER, 5),
DEAD_NODE_SWEEP_THRESHOLD(LONG, HEARTBEAT_PERIOD),
- PROFILE_DUMP_PERIOD(UNSIGNED_INTEGER, 0),
- JOB_HISTORY_SIZE(UNSIGNED_INTEGER, 10),
+ PROFILE_DUMP_PERIOD(NONNEGATIVE_INTEGER, 0),
+ JOB_HISTORY_SIZE(NONNEGATIVE_INTEGER, 10),
RESULT_TTL(LONG, 86400000L), // TODO(mblow): add time unit
RESULT_SWEEP_THRESHOLD(LONG, 60000L), // TODO(mblow): add time unit
@SuppressWarnings("RedundantCast") // not redundant- false positive from IDEA
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
index e947d7a..ef244c59 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/controllers/NCConfig.java
@@ -21,10 +21,10 @@
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.INTEGER_BYTE_UNIT;
import static org.apache.hyracks.control.common.config.OptionTypes.LONG;
+import static org.apache.hyracks.control.common.config.OptionTypes.NONNEGATIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.POSITIVE_INTEGER;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING;
import static org.apache.hyracks.control.common.config.OptionTypes.STRING_ARRAY;
-import static org.apache.hyracks.control.common.config.OptionTypes.UNSIGNED_INTEGER;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -45,31 +45,31 @@
ADDRESS(STRING, InetAddress.getLoopbackAddress().getHostAddress()),
PUBLIC_ADDRESS(STRING, ADDRESS),
CLUSTER_LISTEN_ADDRESS(STRING, ADDRESS),
- CLUSTER_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+ CLUSTER_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
NCSERVICE_ADDRESS(STRING, PUBLIC_ADDRESS),
NCSERVICE_PORT(INTEGER, 9090),
CLUSTER_ADDRESS(STRING, (String) null),
- CLUSTER_PORT(UNSIGNED_INTEGER, 1099),
+ CLUSTER_PORT(NONNEGATIVE_INTEGER, 1099),
CLUSTER_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- CLUSTER_PUBLIC_PORT(UNSIGNED_INTEGER, CLUSTER_LISTEN_PORT),
+ CLUSTER_PUBLIC_PORT(NONNEGATIVE_INTEGER, CLUSTER_LISTEN_PORT),
NODE_ID(STRING, (String) null),
DATA_LISTEN_ADDRESS(STRING, ADDRESS),
- DATA_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+ DATA_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
DATA_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- DATA_PUBLIC_PORT(UNSIGNED_INTEGER, DATA_LISTEN_PORT),
+ DATA_PUBLIC_PORT(NONNEGATIVE_INTEGER, DATA_LISTEN_PORT),
RESULT_LISTEN_ADDRESS(STRING, ADDRESS),
- RESULT_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+ RESULT_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
RESULT_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- RESULT_PUBLIC_PORT(UNSIGNED_INTEGER, RESULT_LISTEN_PORT),
+ RESULT_PUBLIC_PORT(NONNEGATIVE_INTEGER, RESULT_LISTEN_PORT),
MESSAGING_LISTEN_ADDRESS(STRING, ADDRESS),
- MESSAGING_LISTEN_PORT(UNSIGNED_INTEGER, 0),
+ MESSAGING_LISTEN_PORT(NONNEGATIVE_INTEGER, 0),
MESSAGING_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- MESSAGING_PUBLIC_PORT(UNSIGNED_INTEGER, MESSAGING_LISTEN_PORT),
+ MESSAGING_PUBLIC_PORT(NONNEGATIVE_INTEGER, MESSAGING_LISTEN_PORT),
REPLICATION_LISTEN_ADDRESS(STRING, ADDRESS),
- REPLICATION_LISTEN_PORT(UNSIGNED_INTEGER, 2000),
+ REPLICATION_LISTEN_PORT(NONNEGATIVE_INTEGER, 2000),
REPLICATION_PUBLIC_ADDRESS(STRING, PUBLIC_ADDRESS),
- REPLICATION_PUBLIC_PORT(UNSIGNED_INTEGER, REPLICATION_LISTEN_PORT),
- CLUSTER_CONNECT_RETRIES(UNSIGNED_INTEGER, 5),
+ REPLICATION_PUBLIC_PORT(NONNEGATIVE_INTEGER, REPLICATION_LISTEN_PORT),
+ CLUSTER_CONNECT_RETRIES(NONNEGATIVE_INTEGER, 5),
IODEVICES(
STRING_ARRAY,
appConfig -> new String[] {