Shivani's patch for VXQUERY-141 and a fix XTest results when running multiple threads.
Project: http://git-wip-us.apache.org/repos/asf/vxquery/repo Commit: http://git-wip-us.apache.org/repos/asf/vxquery/commit/c230b902 Tree: http://git-wip-us.apache.org/repos/asf/vxquery/tree/c230b902 Diff: http://git-wip-us.apache.org/repos/asf/vxquery/diff/c230b902 Branch: refs/heads/master Commit: c230b902b5bf77ea5baf409f3d5591e0707a1d3a Parents: d7fcc0e Author: Eldon Carman <[email protected]> Authored: Mon Apr 13 11:36:19 2015 -0700 Committer: Eldon Carman <[email protected]> Committed: Wed Jun 3 14:23:47 2015 -0700 ---------------------------------------------------------------------- .../functions/cast/CastToDecimalOperation.java | 6 +- .../functions/cast/CastToDoubleOperation.java | 12 +- .../functions/cast/CastToFloatOperation.java | 101 ++----- .../functions/cast/CastToStringOperation.java | 273 ++++--------------- .../java/org/apache/vxquery/xtest/XTest.java | 3 + 5 files changed, 89 insertions(+), 306 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/vxquery/blob/c230b902/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDecimalOperation.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDecimalOperation.java b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDecimalOperation.java index 03a1e14..f44a8e0 100644 --- a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDecimalOperation.java +++ b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDecimalOperation.java @@ -66,8 +66,12 @@ public class CastToDecimalOperation extends AbstractCastToOperation { throw new SystemException(ErrorCode.FORG0001); } } + if (Double.isNaN(doublep.getDouble()) || Double.isInfinite(doublep.getDouble())) { + throw new SystemException(ErrorCode.FORG0001); + } abvsInner.reset(); - castToString.convertDoubleCanonical(doublep, dOutInner); + dOutInner.write(ValueTag.XS_STRING_TAG); + dOutInner.writeUTF(Double.toString(doublep.getDouble())); stringp.set(abvsInner.getByteArray(), abvsInner.getStartOffset() + 1, abvsInner.getLength() - 1); convertStringExtra(stringp, dOut, true); } http://git-wip-us.apache.org/repos/asf/vxquery/blob/c230b902/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDoubleOperation.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDoubleOperation.java b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDoubleOperation.java index 13bb1f0..43b06ff 100644 --- a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDoubleOperation.java +++ b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToDoubleOperation.java @@ -92,14 +92,16 @@ public class CastToDoubleOperation extends AbstractCastToOperation { if (charIterator.next() != ICharacterIterator.EOS_CHAR) { throw new SystemException(ErrorCode.FORG0001); } else if (c == Character.valueOf('I') && c2 == Character.valueOf('N') && c3 == Character.valueOf('F')) { - valueDouble = Double.POSITIVE_INFINITY; + if (negativeValue) { + valueDouble = Double.NEGATIVE_INFINITY; + } else { + valueDouble = Double.POSITIVE_INFINITY; + } } else if (c == Character.valueOf('N') && c2 == Character.valueOf('a') && c3 == Character.valueOf('N')) { valueDouble = Double.NaN; } else { throw new SystemException(ErrorCode.FORG0001); } - dOut.write(ValueTag.XS_DOUBLE_TAG); - dOut.writeDouble((negativeValue ? -valueDouble : valueDouble)); } else { // We create an object to keep the conversion algorithm simple and improve precision. // While a better solution may be available this will hold us over until then. @@ -110,9 +112,9 @@ public class CastToDoubleOperation extends AbstractCastToOperation { } catch (NumberFormatException e) { throw new SystemException(ErrorCode.FORG0001); } - dOut.write(ValueTag.XS_DOUBLE_TAG); - dOut.writeDouble(valueDouble); } + dOut.write(ValueTag.XS_DOUBLE_TAG); + dOut.writeDouble(valueDouble); } @Override http://git-wip-us.apache.org/repos/asf/vxquery/blob/c230b902/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToFloatOperation.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToFloatOperation.java b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToFloatOperation.java index d311c4c..6dbf917 100644 --- a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToFloatOperation.java +++ b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToFloatOperation.java @@ -40,10 +40,6 @@ public class CastToFloatOperation extends AbstractCastToOperation { /* * All the positive powers of 10 that can be represented exactly in float. */ - private static final float powersOf10upTo10[] = { 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, 1.0e6f, 1.0e7f, - 1.0e8f, 1.0e9f, 1.0e10f }; - private static final float powersOf10from20to30[] = { 1.0e20f, 1.0e21f, 1.0e22f, 1.0e23f, 1.0e24f, 1.0e25f, - 1.0e26f, 1.0e27f, 1.0e28f, 1.0e29f, 1.0e30f }; @Override public void convertBoolean(BooleanPointable boolp, DataOutput dOut) throws SystemException, IOException { @@ -83,10 +79,8 @@ public class CastToFloatOperation extends AbstractCastToOperation { public void convertString(UTF8StringPointable stringp, DataOutput dOut) throws SystemException, IOException { ICharacterIterator charIterator = new UTF8StringCharacterIterator(stringp); charIterator.reset(); - byte decimalPlace = 0; - long value = 0; float valueFloat; - boolean pastDecimal = false, negativeValue = false; + boolean negativeValue = false; int c = ICharacterIterator.EOS_CHAR; int c2 = ICharacterIterator.EOS_CHAR; int c3 = ICharacterIterator.EOS_CHAR; @@ -104,94 +98,31 @@ public class CastToFloatOperation extends AbstractCastToOperation { if (charIterator.next() != ICharacterIterator.EOS_CHAR) { throw new SystemException(ErrorCode.FORG0001); } else if (c == Character.valueOf('I') && c2 == Character.valueOf('N') && c3 == Character.valueOf('F')) { - valueFloat = Float.NEGATIVE_INFINITY; + if (negativeValue) { + valueFloat = Float.NEGATIVE_INFINITY; + } else { + valueFloat = Float.POSITIVE_INFINITY; + } } else if (c == Character.valueOf('N') && c2 == Character.valueOf('a') && c3 == Character.valueOf('N')) { valueFloat = Float.NaN; } else { throw new SystemException(ErrorCode.FORG0001); } } else { - // Read in the number. - do { - if (Character.isDigit(c)) { - value = value * 10 - Character.getNumericValue(c); - if (pastDecimal) { - decimalPlace--; - } - } else if (c == Character.valueOf('.') && pastDecimal == false) { - pastDecimal = true; - } else if (c == Character.valueOf('E') || c == Character.valueOf('e')) { - break; - } else { - throw new SystemException(ErrorCode.FORG0001); - } - } while ((c = charIterator.next()) != ICharacterIterator.EOS_CHAR); - - // Parse the exponent. - if (c == Character.valueOf('E') || c == Character.valueOf('e')) { - int moveOffset = 0; - boolean negativeOffset = false; - // Check for the negative sign. - c = charIterator.next(); - if (c == Character.valueOf('-')) { - negativeOffset = true; - c = charIterator.next(); - } - // Process the numeric value. - do { - if (Character.isDigit(c)) { - moveOffset = moveOffset * 10 + Character.getNumericValue(c); - } else { - throw new SystemException(ErrorCode.FORG0001); - } - } while ((c = charIterator.next()) != ICharacterIterator.EOS_CHAR); - decimalPlace += (negativeOffset ? -moveOffset : moveOffset); - } - - /* - * The following conditions to create the floating point value is using known valid float values. - * In addition, each one only needs one or two operations to get the float value, further minimizing - * possible errors. (Not perfect, but pretty good.) - */ - valueFloat = (float) value; - if (decimalPlace == 0 || valueFloat == 0.0f) { - // No modification required to float value. - } else if (decimalPlace >= 0) { - if (decimalPlace <= 10) { - valueFloat *= powersOf10upTo10[decimalPlace]; - } else if (decimalPlace <= 20) { - valueFloat *= powersOf10upTo10[10]; - valueFloat *= powersOf10upTo10[decimalPlace - 10]; - } else if (decimalPlace <= 30) { - valueFloat *= powersOf10from20to30[decimalPlace]; - } else if (decimalPlace <= 38) { - valueFloat *= powersOf10from20to30[10]; - valueFloat *= powersOf10upTo10[decimalPlace - 30]; - } - } else { - if (decimalPlace >= -10) { - valueFloat /= powersOf10upTo10[-decimalPlace]; - } else if (decimalPlace >= -20) { - valueFloat /= powersOf10upTo10[10]; - valueFloat /= powersOf10upTo10[-decimalPlace - 10]; - } else if (decimalPlace >= -30) { - valueFloat /= powersOf10from20to30[-decimalPlace]; - } else if (decimalPlace >= -40) { - valueFloat /= powersOf10from20to30[10]; - valueFloat /= powersOf10upTo10[-decimalPlace - 30]; - } else if (decimalPlace >= -45) { - valueFloat /= powersOf10from20to30[0]; - valueFloat /= powersOf10from20to30[-decimalPlace - 20]; - } + // We create an object to keep the conversion algorithm simple and improve precision. + // While a better solution may be available this will hold us over until then. + StringBuilder sb = new StringBuilder(); + stringp.toString(sb); + try { + valueFloat = Float.parseFloat(sb.toString()); + } catch (NumberFormatException e) { + throw new SystemException(ErrorCode.FORG0001); } } dOut.write(ValueTag.XS_FLOAT_TAG); - if (valueFloat == 0.0f) { - dOut.writeFloat((negativeValue ? -0.0f : 0.0f)); - } else { - dOut.writeFloat((negativeValue ? valueFloat : -valueFloat)); - } + dOut.writeFloat(valueFloat); + } @Override http://git-wip-us.apache.org/repos/asf/vxquery/blob/c230b902/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToStringOperation.java ---------------------------------------------------------------------- diff --git a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToStringOperation.java b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToStringOperation.java index 3cbcd5b..5f84682 100644 --- a/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToStringOperation.java +++ b/vxquery-core/src/main/java/org/apache/vxquery/runtime/functions/cast/CastToStringOperation.java @@ -49,16 +49,6 @@ public class CastToStringOperation extends AbstractCastToOperation { private DataOutput dOutInner = abvsInner.getDataOutput(); int returnTag = ValueTag.XS_STRING_TAG; private final char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - private static final int DOUBLE_MANTISSA_BITS = 52; // size of the mantissa in bits - private static final int DOUBLE_MANTISSA_OFFSET = -1075; - private static final int DOUBLE_EXPONENT_MAX = 1023; - private static final int DOUBLE_EXPONENT_MIN = -1022; - private static final int FLOAT_MANTISSA_BITS = 23; // size of the mantissa in bits - private static final int FLOAT_MANTISSA_OFFSET = -150; - private static final int FLOAT_EXPONENT_MAX = 127; - private static final int FLOAT_EXPONENT_MIN = -126; - private static final int b = 2; // base of stored value - private static final int B = 10; // base of printed value @Override public void convertAnyURI(UTF8StringPointable stringp, DataOutput dOut) throws SystemException, IOException { @@ -151,14 +141,15 @@ public class CastToStringOperation extends AbstractCastToOperation { abvsInner.reset(); double value = doublep.getDouble(); - if (!Double.isInfinite(value) && !Double.isNaN(value) && Math.abs(value) >= 0.000001 - && Math.abs(value) <= 1000000) { - CastToDecimalOperation castToDecimal = new CastToDecimalOperation(); - castToDecimal.convertDouble(doublep, dOutInner); - XSDecimalPointable decp = (XSDecimalPointable) XSDecimalPointable.FACTORY.createPointable(); - decp.set(abvsInner.getByteArray(), abvsInner.getStartOffset() + 1, - XSDecimalPointable.TYPE_TRAITS.getFixedLength()); - convertDecimal(decp, dOut); + if (Double.isInfinite(value)) { + if (value == Double.NEGATIVE_INFINITY) { + FunctionHelper.writeCharSequence("-", dOutInner); + } + FunctionHelper.writeCharSequence("INF", dOutInner); + sendStringDataOutput(dOut); + } else if (Double.isNaN(value)) { + FunctionHelper.writeCharSequence("NaN", dOutInner); + sendStringDataOutput(dOut); } else if (value == -0.0 || value == 0.0) { long bits = Double.doubleToLongBits(value); boolean negative = ((bits >> 63) == 0) ? false : true; @@ -168,8 +159,23 @@ public class CastToStringOperation extends AbstractCastToOperation { } FunctionHelper.writeCharSequence("0", dOutInner); sendStringDataOutput(dOut); + } else if (Math.abs(value) >= 0.000001 && Math.abs(value) <= 10000000) { + //the jdk (toString function) does not output number in desired format when + //a number is between one and ten million, so we take care of this + //case separately here. + CastToDecimalOperation castToDecimal = new CastToDecimalOperation(); + castToDecimal.convertDouble(doublep, dOutInner); + XSDecimalPointable decp = (XSDecimalPointable) XSDecimalPointable.FACTORY.createPointable(); + decp.set(abvsInner.getByteArray(), abvsInner.getStartOffset() + 1, + XSDecimalPointable.TYPE_TRAITS.getFixedLength()); + if (Math.abs(value) <= 1000000) { + convertDecimal(decp, dOut); + } else { + decimalToScientificNotn(decp, dOut); + } } else { - convertDoubleCanonical(doublep, dOut); + dOut.write(returnTag); + dOut.writeUTF(Double.toString(value)); } } @@ -177,109 +183,9 @@ public class CastToStringOperation extends AbstractCastToOperation { abvsInner.reset(); double value = doublep.getDouble(); - if (Double.isInfinite(value)) { - if (value == Double.NEGATIVE_INFINITY) { - FunctionHelper.writeCharSequence("-", dOutInner); - } - FunctionHelper.writeCharSequence("INF", dOutInner); - } else if (Double.isNaN(value)) { - FunctionHelper.writeCharSequence("NaN", dOutInner); - } else { - /* - * The double to string algorithm is based on a paper by Robert G Burger and - * R Kent Dybvig titled "Print Floating-Point Numbers Quickly and Accurately". - */ - long bits = Double.doubleToLongBits(value); - boolean decimalPlaced = false; - - boolean negative = ((bits >> 63) == 0) ? false : true; - int e = (int) ((bits >> 52) & 0x7ffL); - long f = (e == 0) ? (bits & 0xfffffffffffffL) << 1 : (bits & 0xfffffffffffffL) | 0x10000000000000L; - e = e + DOUBLE_MANTISSA_OFFSET; - - if (negative) { - FunctionHelper.writeChar('-', dOutInner); - } - if (value == 0) { - FunctionHelper.writeCharSequence("0.0E0", dOutInner); - } else { - // Initialize variables - double r, s, mPlus, mMinus; - if (e >= 0) { - if (f == Math.pow(b, DOUBLE_MANTISSA_BITS - 1)) { - r = f * Math.pow(b, e) * 2; - s = 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e + 1); - } else { - r = f * Math.pow(b, e + 1) * 2; - s = b * 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e); - } - } else { - if (e == DOUBLE_EXPONENT_MIN || f != Math.pow(b, DOUBLE_MANTISSA_BITS - 1)) { - r = f * Math.pow(b, e) * 2; - s = 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e + 1); - } else { - r = f * Math.pow(b, e + 1) * 2; - s = b * 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e); - } - } - - double k = Math.ceil(Math.log10((r + mPlus) / s)); - if (k >= 0) { - s = s * Math.pow(B, k); - } else { - r = r * Math.pow(B, -k); - mPlus = mPlus * Math.pow(B, -k); - mMinus = mMinus * Math.pow(B, -k); - } - - double d; - while (!Double.isInfinite(mPlus) && !Double.isNaN(mPlus) && !Double.isInfinite(mMinus) - && !Double.isNaN(mMinus) && !Double.isInfinite(r) && !Double.isNaN(r)) { - if (s == r) { - // Special case where the value is off by a factor of ten. - d = 1; - } else { - d = Math.floor((r * B) / s); - } - r = r * B % s; - mPlus = mPlus * B; - mMinus = mMinus * B; - - if (r < mMinus && r + mPlus > s) { - if (r * 2 > s) { - d = d + 1; - } - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } else if (r + mPlus > s) { - d = d + 1; - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } else if (r < mMinus) { - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - if (!decimalPlaced) { - decimalPlaced = true; - FunctionHelper.writeChar('.', dOutInner); - } - } - - long decimalPlace = FunctionHelper.getPowerOf10(value, DOUBLE_EXPONENT_MAX, DOUBLE_EXPONENT_MIN) - 1; - FunctionHelper.writeChar('E', dOutInner); - FunctionHelper.writeNumberWithPadding(decimalPlace, 1, dOutInner); - } - } - sendStringDataOutput(dOut); + dOut.write(returnTag); + dOut.writeUTF(Double.toString(value)); + return; } @Override @@ -435,99 +341,9 @@ public class CastToStringOperation extends AbstractCastToOperation { } else if (Float.isNaN(value)) { FunctionHelper.writeCharSequence("NaN", dOutInner); } else { - /* - * The double to string algorithm is based on a paper by Robert G Burger and - * R Kent Dybvig titled "Print Floating-Point Numbers Quickly and Accurately". - */ - long bits = Float.floatToIntBits(value); - boolean decimalPlaced = false; - - boolean negative = ((bits >> 31) == 0) ? false : true; - int e = (int) ((bits >> 23) & 0xff); - int f = (int) ((e == 0) ? (bits & 0x7fffff) << 1 : (bits & 0x7fffff) | 0x800000); - e = e + FLOAT_MANTISSA_OFFSET; - - if (negative) { - FunctionHelper.writeChar('-', dOutInner); - } - if (value == 0) { - FunctionHelper.writeCharSequence("0.0E0", dOutInner); - } else { - // Initialize variables - double r, s, mPlus, mMinus; - if (e >= 0) { - if (f == Math.pow(b, FLOAT_MANTISSA_BITS - 1)) { - r = f * Math.pow(b, e) * 2; - s = 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e + 1); - } else { - r = f * Math.pow(b, e + 1) * 2; - s = b * 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e); - } - } else { - if (e == FLOAT_EXPONENT_MIN || f != Math.pow(b, FLOAT_MANTISSA_BITS - 1)) { - r = f * Math.pow(b, e) * 2; - s = 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e + 1); - } else { - r = f * Math.pow(b, e + 1) * 2; - s = b * 2; - mPlus = Math.pow(b, e); - mMinus = Math.pow(b, e); - } - } - - double k = Math.ceil(Math.log10((r + mPlus) / s)); - if (k >= 0) { - s = s * Math.pow(B, k); - } else { - r = r * Math.pow(B, -k); - mPlus = mPlus * Math.pow(B, -k); - mMinus = mMinus * Math.pow(B, -k); - } - - double d; - while (!Double.isInfinite(mPlus) && !Double.isNaN(mPlus) && !Double.isInfinite(mMinus) - && !Double.isNaN(mMinus)) { - if (s == r) { - // Special case where the value is off by a factor of ten. - d = 1; - } else { - d = Math.floor((r * B) / s); - } - r = r * B % s; - mPlus = mPlus * B; - mMinus = mMinus * B; - - if (r < mMinus && r + mPlus > s) { - if (r * 2 > s) { - d = d + 1; - } - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } else if (r + mPlus > s) { - d = d + 1; - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } else if (r < mMinus) { - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - break; - } - FunctionHelper.writeChar((char) ('0' + d), dOutInner); - if (!decimalPlaced) { - decimalPlaced = true; - FunctionHelper.writeChar('.', dOutInner); - } - } - - long decimalPlace = FunctionHelper.getPowerOf10(value, FLOAT_EXPONENT_MAX, FLOAT_EXPONENT_MIN) - 1; - FunctionHelper.writeChar('E', dOutInner); - FunctionHelper.writeNumberWithPadding(decimalPlace, 1, dOutInner); - } + dOut.write(returnTag); + dOut.writeUTF(Float.toString(value)); + return; } sendStringDataOutput(dOut); } @@ -849,4 +665,31 @@ public class CastToStringOperation extends AbstractCastToOperation { dOut.write(abvsInner.getByteArray(), abvsInner.getStartOffset(), abvsInner.getLength()); } + public void decimalToScientificNotn(XSDecimalPointable decp, DataOutput dOut) throws SystemException, IOException { + byte decimalPlace = decp.getDecimalPlace(); + long value = decp.getDecimalValue(); + byte nDigits = decp.getDigitCount(); + abvsInner.reset(); + + if (!FunctionHelper.isNumberPostive(value)) { + // Negative result, but the rest of the calculations can be based on a positive value. + FunctionHelper.writeChar('-', dOutInner); + value *= -1; + } + + if (value == 0) { + FunctionHelper.writeChar('0', dOutInner); + } else { + long pow10 = (long) Math.pow(10, nDigits - 1); + FunctionHelper.writeNumberWithPadding((value / pow10), 0, dOutInner); + FunctionHelper.writeChar('.', dOutInner); + long mod = value % pow10; + FunctionHelper.writeNumberWithPadding(mod, (nDigits - 1), dOutInner); + FunctionHelper.writeChar('E', dOutInner); + long power = (nDigits - 1) - decimalPlace; + FunctionHelper.writeNumberWithPadding(power, 0, dOutInner); + } + sendStringDataOutput(dOut); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/vxquery/blob/c230b902/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java ---------------------------------------------------------------------- diff --git a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java index 87f0687..0e2a6e0 100644 --- a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java +++ b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java @@ -90,6 +90,9 @@ public class XTest { Thread.sleep(opts.keepalive); } eSvc.shutdown(); + while (!eSvc.awaitTermination(5L, TimeUnit.SECONDS)) { + System.err.println("Failed to close all threads, trying again..."); + } for (ResultReporter r : reporters) { r.close(); }
