diff --git a/conf/asym-encrypt.xml b/conf/asym-encrypt.xml index b5331d9ff9..9f4c976549 100644 --- a/conf/asym-encrypt.xml +++ b/conf/asym-encrypt.xml @@ -6,7 +6,7 @@ - + @@ -22,5 +22,5 @@ - + diff --git a/conf/asym-ssl.xml b/conf/asym-ssl.xml index 4afebe798b..d522757d5f 100644 --- a/conf/asym-ssl.xml +++ b/conf/asym-ssl.xml @@ -26,7 +26,7 @@ - + diff --git a/conf/comment-test.xml b/conf/comment-test.xml index ed60eb4c6a..b27425757a 100644 --- a/conf/comment-test.xml +++ b/conf/comment-test.xml @@ -12,20 +12,20 @@ - thread_pool.keep_alive_time="30000"/> + thread_pool.keep_alive_time="30s"/> - + - + - - - + + diff --git a/conf/encrypt.xml b/conf/encrypt.xml index 5ea5c66517..869a81a4eb 100644 --- a/conf/encrypt.xml +++ b/conf/encrypt.xml @@ -6,7 +6,7 @@ - + diff --git a/conf/fast.xml b/conf/fast.xml index 5f4a756117..738904f3cf 100644 --- a/conf/fast.xml +++ b/conf/fast.xml @@ -15,19 +15,19 @@ mcast_port="${jgroups.udp.mcast_port:45588}" thread_pool.min_threads="2" thread_pool.max_threads="200" - thread_pool.keep_alive_time="5000"/> + thread_pool.keep_alive_time="5s"/> - + - - - - + + + - + - - - + + + diff --git a/conf/jdbc-hsql.xml b/conf/jdbc-hsql.xml index 50a4decd6d..b1908515b9 100644 --- a/conf/jdbc-hsql.xml +++ b/conf/jdbc-hsql.xml @@ -10,7 +10,7 @@ JDBC_PING2 for hsqldb port_range="50" recv_buf_size="150000" send_buf_size="640000" - sock_conn_timeout="300" + sock_conn_timeout="300ms" /> @@ -34,22 +34,22 @@ JDBC_PING2 for hsqldb call_insert_sp="call deleteAndInsert(?,?,?,?,?);" --> /> - + - + + xmit_interval="100ms"/> + xmit_interval="100ms"/> diff --git a/conf/jdbc-mysql.xml b/conf/jdbc-mysql.xml index 85654e6eef..1b224d0ade 100644 --- a/conf/jdbc-mysql.xml +++ b/conf/jdbc-mysql.xml @@ -10,11 +10,11 @@ port_range="50" recv_buf_size="150000" send_buf_size="640000" - sock_conn_timeout="300" + sock_conn_timeout="300ms" thread_pool.enabled="true" thread_pool.min_threads="1" thread_pool.max_threads="50" - thread_pool.keep_alive_time="60000" + thread_pool.keep_alive_time="60s" /> @@ -48,11 +48,11 @@ diff --git a/conf/jdbc-pg.xml b/conf/jdbc-pg.xml index eb840c3fed..f5c570e5a9 100644 --- a/conf/jdbc-pg.xml +++ b/conf/jdbc-pg.xml @@ -10,7 +10,7 @@ port_range="50" recv_buf_size="150000" send_buf_size="640000" - sock_conn_timeout="300" + sock_conn_timeout="300ms" /> @@ -36,19 +36,19 @@ - + + xmit_interval="500ms"/> + xmit_interval="500ms"/> diff --git a/conf/sym-encrypt.xml b/conf/sym-encrypt.xml index d21a2846b3..2259e05d44 100644 --- a/conf/sym-encrypt.xml +++ b/conf/sym-encrypt.xml @@ -8,7 +8,7 @@ - + @@ -27,5 +27,5 @@ - + diff --git a/conf/tcp-low-latency.xml b/conf/tcp-low-latency.xml index 67940c3896..bf86b8b24f 100644 --- a/conf/tcp-low-latency.xml +++ b/conf/tcp-low-latency.xml @@ -28,16 +28,16 @@ bundler_type="no-bundler" /> - + - + - - + - + - + - - + + - - + diff --git a/conf/tcp-nio.xml b/conf/tcp-nio.xml index 9a58b1e3bb..a7db7a1621 100644 --- a/conf/tcp-nio.xml +++ b/conf/tcp-nio.xml @@ -17,17 +17,17 @@ - + - - + + - - + - + - - + + - - + - + \ No newline at end of file diff --git a/conf/udp.xml b/conf/udp.xml index 530dd5c43c..fc53e8f064 100644 --- a/conf/udp.xml +++ b/conf/udp.xml @@ -12,20 +12,20 @@ mcast_port="${jgroups.udp.mcast_port:45588}" thread_pool.min_threads="0" thread_pool.max_threads="200" - thread_pool.keep_alive_time="30000"/> + thread_pool.keep_alive_time="30s"/> - + - + - - - + + - + `ff0e::239.5.5.5` -| jgroups.use.jdk_logger | If true, the JDK logger (`java.util.logging.Logger`) will be used -| jgroups.log_class | The fully qualified name of a class implementing a logger to be used. See <> for details. -| jgroups.msg.default_headers | System prop for defining the default number of headers in a Message (default: 4). -| jgroups.version.check | Whether or not to check the version of received messages and discard them if the versions -don't match. Default: true (version check is enabled). +| `jgroups.use.jdk_logger` | If true, the JDK logger (`java.util.logging.Logger`) will be used +| `jgroups.log_class` | The fully qualified name of a class implementing a logger to be used. See <> for details. +| `jgroups.msg.default_headers` | System prop for defining the default number of headers in a Message (default: `4`). +| `jgroups.version.check` | Whether or not to check the version of received messages and discard them if the versions +don't match. Default: `true` (version check is enabled). |=============== @@ -148,11 +149,43 @@ When `bind_addr` is `::1`, `site_local` needs to pick an IPv6 address. For dual stacks (both IPv4 and IPv6 stack is available in the JDK), these changes allow JGroups to run different configurations in the same JVM, e.g. one channel joining an IPv4 cluster, and another one joining an IPv6 cluster. +[[AttributeValues]] +=== Attribute values + +Attribute values are generally applied literally. + +==== Size units +For numeric units indicating a size, it is possible to use the following suffixes to specify a unit of measure after the value: + +* `k`, `kb`: kilo, kilobytes (1,000 == 10^3^) +* `m`, `mb`: mega, megabytes (1,000,000 == 10^6^) +* `g`, `gb`: giga, gigabytes (1,000,000,000 == 10^9^) +* `kib`: kibibytes (1,024 == 2^10^) +* `mib`: mebibytes (1,048,576 == 2^20^) +* `gib`: gibibytes (1,073,741,824 == 2^30^) + +It is also possible to use floating point numbers to indicate fractions of a unit. + +Examples: `5mb`, `10kib`, `0.5g`. + +==== Time units +If an attribute is of type `TIME`, it is possible to use the following suffixes to specify a unit of measure after the value: + +* `ms`: milliseconds +* `s`: seconds +* `m`: minutes +* `h`: hours +* `d`: days + +It is also possible to use floating point numbers to indicate fractions of a unit. + +For example: `10m`, `3s`, `500ms`, `1.5d`. + [[Transport]] === Transport -`TP` is the base class for all transports, e.g. `UDP` and `TCP`. All of the properties +`TP` is the base class for all transports, e.g. `UDP` and `TCP`. All the properties defined here are inherited by the subclasses. The properties for `TP` are: @@ -160,7 +193,7 @@ ${TP} `bind_addr` can be set to the address of a network interface, e.g. +192.168.1.5+. It can also be set for the entire stack using system property +$$-Djgroups.bind_addr$$+, which -provides a value for bind_addr unless it has already been set in the XML config. +provides a value for `bind_addr` unless it has already been set in the XML config. The following special values are also recognized for `bind_addr`: @@ -168,7 +201,7 @@ The following special values are also recognized for `bind_addr`: GLOBAL:: Picks a global IP address if available. If not, falls back to a SITE_LOCAL IP address. -SITE_LOCAL:: Picks a site local (non routable) IP address, e.g. from the +192.168.0.0+ or +SITE_LOCAL:: Picks a site local (non-routable) IP address, e.g. from the +192.168.0.0+ or +10.0.0.0+ address range. LINK_LOCAL:: Picks a link-local IP address, from +169.254.1.0+ through diff --git a/src/org/jgroups/conf/PropertyConverter.java b/src/org/jgroups/conf/PropertyConverter.java index 0fd5231e08..0ecf2ff8b5 100644 --- a/src/org/jgroups/conf/PropertyConverter.java +++ b/src/org/jgroups/conf/PropertyConverter.java @@ -17,6 +17,11 @@ public interface PropertyConverter { Object convert(Object obj, Class propertyFieldType, String propertyName, String propertyValue, boolean check_scope, StackType ip_version) throws Exception; + default Object convert(Property annotation, Object obj, Class propertyFieldType, String propertyName, String propertyValue, + boolean check_scope, StackType ip_version) throws Exception { + return convert(obj, propertyFieldType, propertyName, propertyValue, check_scope, ip_version); + } + /** * Converts the value to a string. The default is to simply invoke Object.toString(), however, some objects need * to be printed specially, e.g. a long array etc. @@ -24,4 +29,6 @@ Object convert(Object obj, Class propertyFieldType, String propertyName, Stri * @return */ String toString(Object value); + + } diff --git a/src/org/jgroups/conf/PropertyConverters.java b/src/org/jgroups/conf/PropertyConverters.java index 31ed8efad7..0749b1be56 100644 --- a/src/org/jgroups/conf/PropertyConverters.java +++ b/src/org/jgroups/conf/PropertyConverters.java @@ -1,5 +1,6 @@ package org.jgroups.conf; +import org.jgroups.annotations.Property; import org.jgroups.stack.Configurator; import org.jgroups.stack.IpAddress; import org.jgroups.stack.Policy; @@ -157,7 +158,13 @@ public String toString(Object value) { public static class Default implements PropertyConverter { - public Object convert(Object obj, Class propertyFieldType, String propertyName, String propertyValue, + @Override + public Object convert(Object obj, Class propertyFieldType, String propertyName, String propertyValue, boolean check_scope, StackType ip_version) throws Exception { + return convert(null, obj, propertyFieldType, propertyName, propertyValue, check_scope, ip_version); + } + + @Override + public Object convert(Property annotation, Object obj, Class propertyFieldType, String propertyName, String propertyValue, boolean check_scope, StackType ip_version) throws Exception { if(propertyValue == null) throw new NullPointerException("Property value cannot be null"); @@ -166,8 +173,9 @@ public Object convert(Object obj, Class propertyFieldType, String propertyNam return Boolean.parseBoolean(propertyValue); if(Integer.TYPE.equals(propertyFieldType)) return Util.readBytesInteger(propertyValue); - if(Long.TYPE.equals(propertyFieldType)) - return Util.readBytesLong(propertyValue); + if(Long.TYPE.equals(propertyFieldType)) { + return annotation != null && annotation.type() == AttributeType.TIME ? Util.readDurationLong(propertyValue, annotation.unit()) : Util.readBytesLong(propertyValue); + } if(Byte.TYPE.equals(propertyFieldType)) return Byte.parseByte(propertyValue); if(Double.TYPE.equals(propertyFieldType)) diff --git a/src/org/jgroups/conf/PropertyHelper.java b/src/org/jgroups/conf/PropertyHelper.java index 4f5f8c4ccb..b482da7fea 100644 --- a/src/org/jgroups/conf/PropertyHelper.java +++ b/src/org/jgroups/conf/PropertyHelper.java @@ -18,7 +18,7 @@ */ public final class PropertyHelper { - protected static final Log log=LogFactory.getLog(PropertyHelper.class); + private static final Log log=LogFactory.getLog(PropertyHelper.class); private PropertyHelper() { throw new InstantiationError("Must not instantiate this class"); @@ -74,17 +74,13 @@ public static Object getConvertedValue(Object obj, Field field, Map List rows=new ArrayList<>(nameToDescription.size() +1); rows.add(new String[]{"Name", "Description"}); for(Map.Entry entry: nameToDescription.entrySet()) - rows.add(new String[]{entry.getKey(), entry.getValue()}); + rows.add(new String[]{"`" + entry.getKey() + "`", entry.getValue()}); String tmp=createAsciidocTable(rows, clazz.getSimpleName(), "[align=\"left\",width=\"90%\",cols=\"2,10\",options=\"header\"]"); props.put(clazz.getSimpleName(), tmp); @@ -179,7 +179,7 @@ protected static void getDescriptions(Class clazz, final Map m desc="n/a"; String name = annotation.name(); - if(name.length() < 1) + if(name.isEmpty()) name=Util.methodNameToAttributeName(method.getName()); if(prefix != null && !prefix.isEmpty()) name=prefix + "." + name; @@ -280,13 +280,14 @@ protected static String readUntilBracket(InputStream in) throws IOException { private static String fileToString(File f) throws Exception { StringWriter output = new StringWriter(); - FileReader input = new FileReader(f); - char[] buffer = new char[8 * 1024]; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - } - return output.toString(); + try (FileReader input = new FileReader(f)) { + char[] buffer = new char[8 * 1024]; + int n; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + } + } + return output.toString(); } public static int copy(Reader input, Writer output) throws IOException { diff --git a/src/org/jgroups/util/Util.java b/src/org/jgroups/util/Util.java index 4deb09c573..f7b9015a11 100644 --- a/src/org/jgroups/util/Util.java +++ b/src/org/jgroups/util/Util.java @@ -25,6 +25,7 @@ import java.lang.annotation.Annotation; import java.lang.management.*; import java.lang.reflect.*; +import java.math.BigDecimal; import java.math.BigInteger; import java.net.*; import java.nio.ByteBuffer; @@ -2660,28 +2661,64 @@ public static double readBytesDouble(String input) { private static Tuple readBytes(String input) { input=input.trim().toLowerCase(); - int index=-1; + int index; long factor=1; if((index=input.indexOf('k')) != -1) factor=1000; else if((index=input.indexOf("kb")) != -1) factor=1000; + else if((index=input.indexOf("kib")) != -1) + factor=1024; else if((index=input.indexOf('m')) != -1) factor=1_000_000; else if((index=input.indexOf("mb")) != -1) factor=1_000_000; + else if((index=input.indexOf("mib")) != -1) + factor=1_048_576; else if((index=input.indexOf('g')) != -1) factor=1_000_000_000; else if((index=input.indexOf("gb")) != -1) factor=1_000_000_000; + else if((index=input.indexOf("gib")) != -1) + factor=1_073_741_824; + + + String str=index != -1? input.substring(0,index) : input; + return new Tuple<>(str,factor); + } + + public static long readDurationLong(String input, TimeUnit unit) { + Tuple tuple=readDuration(input); + BigDecimal num = new BigDecimal(tuple.getVal1()); + return unit.convert(num.multiply(new BigDecimal(tuple.getVal2())).longValue(), TimeUnit.MILLISECONDS); + } + + private static Tuple readDuration(String input) { + input=input.trim().toLowerCase(); + + int index; + long factor; + + if((index=input.indexOf("ms")) != -1) + factor=1; + else if((index=input.indexOf("s")) != -1) + factor=1000; + else if((index=input.indexOf('m')) != -1) + factor=60_000; + else if((index=input.indexOf("h")) != -1) + factor=3_600_000; + else if((index=input.indexOf('d')) != -1) + factor=86_400_000; + else + factor=1; String str=index != -1? input.substring(0,index) : input; return new Tuple<>(str,factor); } /** - * MB nowadays doesn't mean 1024 * 1024 bytes, but 1 million bytes, see http://en.wikipedia.org/wiki/Megabyte + * MB nowadays doesn't mean 1024 * 1024 bytes, but 1 million bytes, see http://en.wikipedia.org/wiki/Megabyte * @param bytes */ public static String printBytes(double bytes) { @@ -2714,8 +2751,6 @@ public static String[] components(String path,String separator) { if(path == null || path.isEmpty()) return null; String[] tmp=path.split(separator + "+"); // multiple separators could be present - if(tmp == null) - return null; if(tmp.length == 0) return null;