summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/WeightedSetItem.java3
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java20
-rw-r--r--searchlib/src/main/java/com/yahoo/searchlib/expression/StringResultNode.java85
-rw-r--r--searchlib/src/test/java/com/yahoo/searchlib/expression/ExpressionTestCase.java88
-rw-r--r--vespa-http-client/src/main/java/com/yahoo/vespa/http/client/Result.java5
-rw-r--r--vespa-http-client/src/main/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallback.java9
-rw-r--r--vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/CommandLineArguments.java6
-rw-r--r--vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/Runner.java2
-rw-r--r--vespa-http-client/src/test/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallbackTest.java22
-rw-r--r--vespajlib/abi-spec.json1
-rw-r--r--vespajlib/pom.xml10
-rw-r--r--vespajlib/src/main/java/com/yahoo/vespa/objects/Identifiable.java9
12 files changed, 203 insertions, 57 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/WeightedSetItem.java b/container-search/src/main/java/com/yahoo/prelude/query/WeightedSetItem.java
index 84a176c2f7d..d5ca15f10b9 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/WeightedSetItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/WeightedSetItem.java
@@ -182,11 +182,12 @@ public class WeightedSetItem extends SimpleTaggableItem {
@Override
public boolean equals(Object o) {
+ if (o == this) return true;
if ( ! super.equals(o)) return false;
var other = (WeightedSetItem)o;
if ( ! Objects.equals(this.indexName, other.indexName)) return false;
if ( ! Objects.equals(this.set, other.set)) return false;
- return false;
+ return true;
}
@Override
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 18c2e794994..ebd6f230fc7 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -45,12 +45,6 @@ public class Flags {
private static volatile TreeMap<FlagId, FlagDefinition> flags = new TreeMap<>();
- public static final UnboundBooleanFlag FORCE_DISK_ENCRYPTION = defineFeatureFlag(
- "force-disk-encryption", true,
- List.of("hakonhall"), "2021-10-01", "2021-11-01",
- "Enable new conditions for when to encrypt disk.",
- "Takes effect on next host admin tick.");
-
public static final UnboundBooleanFlag MAP_USER_NAMESPACE = defineFeatureFlag(
"map-user-namespace", false,
List.of("freva"), "2021-10-18", "2021-12-01",
@@ -213,7 +207,7 @@ public class Flags {
public static final UnboundIntFlag MAX_ACTIVATION_INHIBITED_OUT_OF_SYNC_GROUPS = defineIntFlag(
"max-activation-inhibited-out-of-sync-groups", 0,
- List.of("vekterli"), "2021-02-19", "2021-11-01",
+ List.of("vekterli"), "2021-02-19", "2022-02-01",
"Allows replicas in up to N content groups to not be activated " +
"for query visibility if they are out of sync with a majority of other replicas",
"Takes effect at redeployment",
@@ -248,18 +242,6 @@ public class Flags {
"Takes effect on next internal redeployment",
APPLICATION_ID);
- public static final UnboundIntFlag MAX_ENCRYPTING_HOSTS = defineIntFlag(
- "max-encrypting-hosts", 0,
- List.of("mpolden", "hakonhall"), "2021-05-27", "2021-11-01",
- "The maximum number of hosts allowed to encrypt their disk concurrently",
- "Takes effect on next run of HostEncrypter, but any currently encrypting hosts will not be cancelled when reducing the limit");
-
- public static final UnboundListFlag<String> DEFER_APPLICATION_ENCRYPTION = defineListFlag(
- "defer-application-encryption", List.of(), String.class,
- List.of("mpolden", "hakonhall"), "2021-06-23", "2021-11-01",
- "List of applications where encryption of their host should be deferred",
- "Takes effect on next run of HostEncrypter");
-
public static final UnboundDoubleFlag MIN_NODE_RATIO_PER_GROUP = defineDoubleFlag(
"min-node-ratio-per-group", 0.0,
List.of("geirst", "vekterli"), "2021-07-16", "2021-12-01",
diff --git a/searchlib/src/main/java/com/yahoo/searchlib/expression/StringResultNode.java b/searchlib/src/main/java/com/yahoo/searchlib/expression/StringResultNode.java
index 6a84c7ff950..b90a5aadbb6 100644
--- a/searchlib/src/main/java/com/yahoo/searchlib/expression/StringResultNode.java
+++ b/searchlib/src/main/java/com/yahoo/searchlib/expression/StringResultNode.java
@@ -6,6 +6,8 @@ import com.yahoo.vespa.objects.Deserializer;
import com.yahoo.vespa.objects.ObjectVisitor;
import com.yahoo.vespa.objects.Serializer;
+import java.util.Arrays;
+
/**
* This result holds a string.
*
@@ -16,18 +18,20 @@ public class StringResultNode extends SingleResultNode {
// The global class identifier shared with C++.
public static final int classId = registerClass(0x4000 + 53, StringResultNode.class);
- private static StringResultNode negativeInfinity = new StringResultNode("");
- private static PositiveInfinityResultNode positiveInfinity = new PositiveInfinityResultNode();
+ private static final StringResultNode negativeInfinity = new StringResultNode("");
+ private static final PositiveInfinityResultNode positiveInfinity = new PositiveInfinityResultNode();
+
+ private static final byte[] EMPTY_UTF8_ARRAY = new byte[0];
- // The string value of this node.
- private String value;
+ // The string value of this node, in raw UTF-8 octets.
+ private byte[] utf8Value;
/**
* Constructs an empty result node. <b>NOTE:</b> This instance is broken until non-optional member data is set.
*/
public StringResultNode() {
super();
- value = "";
+ utf8Value = EMPTY_UTF8_ARRAY;
}
/**
@@ -40,6 +44,19 @@ public class StringResultNode extends SingleResultNode {
setValue(value);
}
+ private StringResultNode(byte[] rawUtf8Value) {
+ super();
+ utf8Value = rawUtf8Value;
+ }
+
+ /**
+ * Creates a new StringResultNode backed by an underlying byte array. The input is
+ * presumed to be in valid UTF-8 format, but is _not_ checked for validity.
+ */
+ protected static StringResultNode ofUncheckedUtf8Array(byte[] rawUtf8Value) {
+ return new StringResultNode(rawUtf8Value);
+ }
+
/**
* Sets the value of this result.
*
@@ -50,7 +67,7 @@ public class StringResultNode extends SingleResultNode {
if (value == null) {
throw new IllegalArgumentException("Value can not be null.");
}
- this.value = value;
+ this.utf8Value = Utf8.toBytes(value);
return this;
}
@@ -68,13 +85,14 @@ public class StringResultNode extends SingleResultNode {
@Override
protected void onDeserialize(Deserializer buf) {
- value = getUtf8(buf);
+ // We expect the UTF-8 we get from the backend to be pre-checked and valid.
+ utf8Value = getRawUtf8Bytes(buf);
}
@Override
public long getInteger() {
try {
- return Integer.valueOf(value);
+ return Integer.valueOf(getString());
} catch (java.lang.NumberFormatException e) {
return 0;
}
@@ -83,7 +101,7 @@ public class StringResultNode extends SingleResultNode {
@Override
public double getFloat() {
try {
- return Double.valueOf(value);
+ return Double.valueOf(getString());
} catch (java.lang.NumberFormatException e) {
return 0;
}
@@ -91,50 +109,53 @@ public class StringResultNode extends SingleResultNode {
@Override
public String getString() {
- return value;
+ return Utf8.toString(utf8Value);
}
@Override
public byte[] getRaw() {
- return Utf8.toBytes(value);
+ return utf8Value;
}
@Override
protected int onCmp(ResultNode rhs) {
return (rhs instanceof PositiveInfinityResultNode)
? -1
- : value.compareTo(rhs.getString());
+ : internalNonPositiveInfinityCompareTo(rhs);
}
@Override
public int hashCode() {
- return super.hashCode() + value.hashCode();
+ return super.hashCode() + Arrays.hashCode(utf8Value);
}
@Override
public void visitMembers(ObjectVisitor visitor) {
super.visitMembers(visitor);
- visitor.visit("value", value);
+ visitor.visit("value", getString());
}
+ @Override
public void add(ResultNode rhs) {
- value += rhs.getString();
+ setValue(getString() + rhs.getString());
}
+ @Override
public void min(ResultNode rhs) {
- if (value.compareTo(rhs.getString()) > 0) {
- value = rhs.getString();
+ if (internalNonPositiveInfinityCompareTo(rhs) > 0) {
+ set(rhs);
}
}
+ @Override
public void max(ResultNode rhs) {
- if (value.compareTo(rhs.getString()) < 0) {
- value = rhs.getString();
+ if (internalNonPositiveInfinityCompareTo(rhs) < 0) {
+ set(rhs);
}
}
public void append(ResultNode rhs) {
- value += rhs.getString();
+ setValue(getString() + rhs.getString());
}
@Override
@@ -144,16 +165,34 @@ public class StringResultNode extends SingleResultNode {
@Override
public void set(ResultNode rhs) {
- value = rhs.getString();
+ if (rhs instanceof StringResultNode) {
+ utf8Value = ((StringResultNode) rhs).utf8Value;
+ } else {
+ setValue(rhs.getString());
+ }
}
@Override
public void negate() {
- char a[] = value.toCharArray();
+ char[] a = getString().toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char)-a[i];
}
- value = new String(a);
+ setValue(new String(a));
+ }
+
+ private int internalNonPositiveInfinityCompareTo(ResultNode rhs) {
+ // Note: this may not necessarily be well-defined _semantically_ unless rhs is
+ // also a StringResultNode. The C++ implementation explicitly expects rhs to be
+ // such an instance, but this depends on a classId check that is _not_ done in
+ // the Java implementation...
+ // We use getString() instead of getRaw() to support implicit stringification
+ // (legacy Java implementation behavior), but it's not given that this is always
+ // the desired outcome.
+ var rhsAsUtf8 = (rhs instanceof StringResultNode)
+ ? ((StringResultNode)rhs).utf8Value
+ : Utf8.toBytes(rhs.getString());
+ return Arrays.compareUnsigned(utf8Value, rhsAsUtf8);
}
/**
diff --git a/searchlib/src/test/java/com/yahoo/searchlib/expression/ExpressionTestCase.java b/searchlib/src/test/java/com/yahoo/searchlib/expression/ExpressionTestCase.java
index c5adfed4974..6e034cce652 100644
--- a/searchlib/src/test/java/com/yahoo/searchlib/expression/ExpressionTestCase.java
+++ b/searchlib/src/test/java/com/yahoo/searchlib/expression/ExpressionTestCase.java
@@ -705,6 +705,21 @@ public class ExpressionTestCase {
assertEquals(0, large.compareTo(large));
}
+ private void compareAllPairwise(ResultNode... orderedNodes) {
+ for (int i = 0; i < orderedNodes.length; ++i) {
+ for (int j = 0; j < orderedNodes.length; ++j) {
+ var ctx = String.format("lhs(i=%d): %s, rhs(j=%d): %s", i, orderedNodes[i], j, orderedNodes[j]);
+ if (j < i) {
+ assertTrue(ctx, orderedNodes[i].compareTo(orderedNodes[j]) > 0);
+ } else if (j > i) {
+ assertTrue(ctx, orderedNodes[i].compareTo(orderedNodes[j]) < 0);
+ } else { // j == i
+ assertEquals(ctx, orderedNodes[i].compareTo(orderedNodes[j]), 0);
+ }
+ }
+ }
+ }
+
@Test
public void testStringResultNode() {
try {
@@ -719,16 +734,87 @@ public class ExpressionTestCase {
} catch (IllegalArgumentException e) {
// expected
}
- StringResultNode a = new StringResultNode("7.3");
+ StringResultNode a = new StringResultNode("42");
+ assertEquals(a.getInteger(), 42);
+ assertEquals(a.getFloat(), 42, delta);
+ assertEquals(a.getString(), "42");
+
+ a = new StringResultNode("7.3");
assertEquals(a.getInteger(), 0);
assertEquals(a.getFloat(), 7.3, delta);
assertEquals(a.getString(), "7.3");
+
byte[] raw = a.getRaw();
assertEquals(raw.length, 3);
+ assertEquals(Arrays.compareUnsigned(raw, Utf8.toBytes("7.3")), 0);
+
assertResultNode(a);
compare(new StringResultNode(), new StringResultNode("z"), new StringResultNode("zz"));
compare(new StringResultNode("z"), new StringResultNode("zz"), new StringResultNode("zzz"));
compare(new StringResultNode("a"), new StringResultNode("zz"), new PositiveInfinityResultNode());
+ assertEquals(new StringResultNode("zz").compareTo(new StringResultNode("zz")), 0);
+
+ // Remove this assertion if we remove support for implicit stringification
+ compare(new StringResultNode(), new StringResultNode("12"), new IntegerResultNode(13));
+
+ var node = new StringResultNode("foo");
+ node.append(new StringResultNode("bar"));
+ assertEquals(node.getString(), "foobar");
+ node.add(new StringResultNode("baz"));
+ assertEquals(node.getString(), "foobarbaz");
+
+ node.set(new StringResultNode("ABC"));
+ assertEquals(node.getString(), "ABC");
+
+ node.max(new StringResultNode("ABA"));
+ assertEquals(node.getString(), "ABC");
+
+ node.max(new StringResultNode("ABD"));
+ assertEquals(node.getString(), "ABD");
+
+ node.min(new StringResultNode("ABE"));
+ assertEquals(node.getString(), "ABD");
+
+ node.min(new StringResultNode("ABC"));
+ assertEquals(node.getString(), "ABC");
+
+ node.set(new IntegerResultNode(1234));
+ assertEquals(node.getString(), "1234");
+ }
+
+ @Test
+ public void string_result_node_comparison_is_memcmp_unsigned_byte_ordered() {
+ // Comparison is first by shared prefix (if equal), then ties are resolved by checking length.
+ // This is not actually valid UTF-8, so we depend on unchecked-ness...
+ compareAllPairwise(StringResultNode.ofUncheckedUtf8Array(new byte[] { 0 }),
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { 0, 0 }),
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { 0, 0, 1 }),
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { 1 }),
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { 127 }), // 0x7F
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { -128 }), // 0x80
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { -1 }), // 0xFF
+ StringResultNode.ofUncheckedUtf8Array(new byte[] { -1, 0 }));
+ }
+
+ // Ensure that the ordering of string nodes on the container matches that of the C++ backend.
+ // The backend directly orders on the memcmp order of UTF-8 strings, so the container must do the same.
+ // In particular, this means that UTF-16 java.lang.String sorting is a no-go.
+ @Test
+ public void string_result_node_comparison_is_utf8_byte_ordered() {
+ // UTF-8 representation of "fried shrimp" emoji U+1F364 which requires a UTF-16 surrogate pair (2 chars)
+ // Its UTF-16 representation is D83C DF64
+ var surrogateUtf8 = new byte[] { -16, -97, -115, -92 }; // F0 9F 8D A4
+ // UTF-8 representation of U+F0BA, which exists in the Unicode private usage range. Only requires 1 UTF-16 char.
+ // Its UTF-16 representation is F0BA
+ var nonSurrogateUtf8 = new byte[] { -17, -126, -70 }; // EF 82 BA
+
+ var s1 = new StringResultNode(Utf8.toString(surrogateUtf8));
+ var s2 = new StringResultNode(Utf8.toString(nonSurrogateUtf8));
+ // UTF-8: s2 < s1, since 0xEF < 0xF0
+ // UTF-16: s1 < s2, since 0xD83C < 0xF0BA
+ // Assert that ordering is defined by UTF-8, not (surrogated) UTF-16.
+ assertTrue(s2.compareTo(s1) < 0);
+ assertTrue(s1.compareTo(s2) > 0);
}
@Test
diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/Result.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/Result.java
index 4cc4c762ccf..93a3b43c211 100644
--- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/Result.java
+++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/Result.java
@@ -63,6 +63,11 @@ public class Result {
public boolean isSuccess() {
return success;
}
+ public boolean isSuccessOrConditionNotMet() {
+ return isSuccess() ||
+ details.stream().allMatch(d -> d.getResultType() == Result.ResultType.OPERATION_EXECUTED ||
+ d.getResultType() == Result.ResultType.CONDITION_NOT_MET);
+ }
public List<Detail> getDetails() { return details; }
diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallback.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallback.java
index fcc3e04af78..eba7fbef483 100644
--- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallback.java
+++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallback.java
@@ -23,6 +23,7 @@ public class SimpleLoggerResultCallback implements FeedClient.ResultCallback {
private int failureCounter = 0;
private final AtomicInteger sentDocumentCounter;
private final int printStatsForEveryXDocument;
+ private final boolean ignoreConditionNotMet;
private Instant startSampleInstant = Instant.now();
private int startSampleResultCount = 0;
@@ -36,9 +37,10 @@ public class SimpleLoggerResultCallback implements FeedClient.ResultCallback {
* @param sentDocumentCounter a counter that is increased outside this class, but can be nice to print here.
* @param printStatsForEveryXDocument how often to print stats.
*/
- public SimpleLoggerResultCallback(AtomicInteger sentDocumentCounter, int printStatsForEveryXDocument) {
+ public SimpleLoggerResultCallback(AtomicInteger sentDocumentCounter, int printStatsForEveryXDocument, boolean ignoreConditionNotMet) {
this.sentDocumentCounter = sentDocumentCounter;
this.printStatsForEveryXDocument = printStatsForEveryXDocument;
+ this.ignoreConditionNotMet = ignoreConditionNotMet;
}
/**
@@ -95,7 +97,10 @@ public class SimpleLoggerResultCallback implements FeedClient.ResultCallback {
printProgress();
}
resultCounter++;
- if (!documentResult.isSuccess()) {
+ boolean success = ignoreConditionNotMet
+ ? documentResult.isSuccessOrConditionNotMet()
+ : documentResult.isSuccess();
+ if ( ! success ) {
failureCounter++;
println("Failure: " + documentResult + (documentResult.getDetails().isEmpty() ? "" : ":"));
for (Result.Detail detail : documentResult.getDetails())
diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/CommandLineArguments.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/CommandLineArguments.java
index 4ccae25f2da..7ccdf3ebd43 100644
--- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/CommandLineArguments.java
+++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/CommandLineArguments.java
@@ -193,6 +193,10 @@ public class CommandLineArguments {
description = "Run validation tool on input files instead of feeding them.")
private boolean validateArg = false;
+ @Option(name = {"--ignoreConditionNotMet"},
+ description = "Ignore condition not met failures.")
+ private boolean ignoreConditionNotMet = false;
+
@Option(name = {"--priority"},
description = "Specify priority of sent messages, see documentation ")
private String priorityArg = null;
@@ -251,6 +255,8 @@ public class CommandLineArguments {
public boolean getVerbose() { return verboseArg; }
+ public boolean getIgnoreConditionNotMet() { return ignoreConditionNotMet; }
+
public boolean getAddRootElementToXml() { return addRootElementToXml; }
SessionParams createSessionParams(boolean useJson) {
diff --git a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/Runner.java b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/Runner.java
index 60047993f0e..e3e90c8bbfc 100644
--- a/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/Runner.java
+++ b/vespa-http-client/src/main/java/com/yahoo/vespa/http/client/runner/Runner.java
@@ -76,7 +76,7 @@ public class Runner {
? commandLineArgs.getWhenVerboseEnabledPrintMessageForEveryXDocuments()
: Integer.MAX_VALUE;
AtomicInteger numSent = new AtomicInteger(0);
- SimpleLoggerResultCallback callback = new SimpleLoggerResultCallback(numSent, intervalOfLogging);
+ SimpleLoggerResultCallback callback = new SimpleLoggerResultCallback(numSent, intervalOfLogging, commandLineArgs.getIgnoreConditionNotMet());
FeedClient feedClient = FeedClientFactory.create(commandLineArgs.createSessionParams(formatInputStream.getFormat()== FormatInputStream.Format.JSON),
callback);
diff --git a/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallbackTest.java b/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallbackTest.java
index 3582ab2696f..5f4a0fdec9a 100644
--- a/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallbackTest.java
+++ b/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/SimpleLoggerResultCallbackTest.java
@@ -8,14 +8,15 @@ import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class SimpleLoggerResultCallbackTest {
@Test
public void testAverageCalculation() {
- SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0);
+ SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0, false);
Instant now = Instant.now();
logger.newSamplingPeriod(now);
Result result = mock(Result.class);
@@ -30,7 +31,7 @@ public class SimpleLoggerResultCallbackTest {
@Test
public void testAverageCalculationExteremeValues() {
- SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0);
+ SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0, false);
Instant now = Instant.now();
logger.newSamplingPeriod(now);
// 0 duration, 0 documents
@@ -40,7 +41,7 @@ public class SimpleLoggerResultCallbackTest {
@Test
public void testOutput() {
- SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0);
+ SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(3), 0, false);
Instant now = Instant.now();
logger.newSamplingPeriod(now);
Result result = mock(Result.class);
@@ -53,11 +54,10 @@ public class SimpleLoggerResultCallbackTest {
assertEquals(rate, 15., 0.1 /* delta */);
}
- @Test
- public void testPrintout() {
+ private void verifyPrintout(boolean ignoreConditionNotMet) {
ArrayList<String> outputList = new ArrayList<>();
- SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(30), 0) {
+ SimpleLoggerResultCallback logger = new SimpleLoggerResultCallback(new AtomicInteger(30), 0, ignoreConditionNotMet) {
@Override
protected void println(String output) {
outputList.add(output);
@@ -70,9 +70,11 @@ public class SimpleLoggerResultCallbackTest {
// 2 success, 1 failure
Result result = mock(Result.class);
when(result.isSuccess()).thenReturn(true);
+ when(result.isSuccessOrConditionNotMet()).thenReturn(true);
logger.onCompletion("1", result);
logger.onCompletion("1", result);
when(result.isSuccess()).thenReturn(false);
+ when(result.isSuccessOrConditionNotMet()).thenReturn(false);
when(result.toString()).thenReturn("fooError");
logger.onCompletion("1", result);
logger.printProgress();
@@ -81,4 +83,10 @@ public class SimpleLoggerResultCallbackTest {
assertThat(outputList.toString(), containsString("Failure: fooError"));
}
+ @Test
+ public void testPrintout() {
+ verifyPrintout(false);
+ verifyPrintout(true);
+ }
+
}
diff --git a/vespajlib/abi-spec.json b/vespajlib/abi-spec.json
index c426195bc37..5eeee267cf6 100644
--- a/vespajlib/abi-spec.json
+++ b/vespajlib/abi-spec.json
@@ -3428,6 +3428,7 @@
"protected static com.yahoo.vespa.objects.Identifiable deserializeOptional(com.yahoo.vespa.objects.Deserializer)",
"protected static boolean equals(java.lang.Object, java.lang.Object)",
"public void visitMembers(com.yahoo.vespa.objects.ObjectVisitor)",
+ "protected static byte[] getRawUtf8Bytes(com.yahoo.vespa.objects.Deserializer)",
"protected java.lang.String getUtf8(com.yahoo.vespa.objects.Deserializer)",
"protected void putUtf8(com.yahoo.vespa.objects.Serializer, java.lang.String)",
"public bridge synthetic java.lang.Object clone()"
diff --git a/vespajlib/pom.xml b/vespajlib/pom.xml
index 7be95661d9a..236e33b3a70 100644
--- a/vespajlib/pom.xml
+++ b/vespajlib/pom.xml
@@ -122,6 +122,16 @@
</configuration>
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <!-- Illegal reflective access by com.yahoo.io.NativeIO -->
+ <argLine>
+ --add-opens=java.base/java.io=ALL-UNNAMED
+ </argLine>
+ </configuration>
+ </plugin>
+ <plugin>
<groupId>com.yahoo.vespa</groupId>
<artifactId>abi-check-plugin</artifactId>
</plugin>
diff --git a/vespajlib/src/main/java/com/yahoo/vespa/objects/Identifiable.java b/vespajlib/src/main/java/com/yahoo/vespa/objects/Identifiable.java
index 8c11a0cbda1..947b312ac3b 100644
--- a/vespajlib/src/main/java/com/yahoo/vespa/objects/Identifiable.java
+++ b/vespajlib/src/main/java/com/yahoo/vespa/objects/Identifiable.java
@@ -354,10 +354,13 @@ public class Identifiable extends Selectable implements Cloneable {
}
}
- protected String getUtf8(Deserializer buf) {
+ protected static byte[] getRawUtf8Bytes(Deserializer buf) {
int len = buf.getInt(null);
- byte[] arr = buf.getBytes(null, len);
- return Utf8.toString(arr);
+ return buf.getBytes(null, len);
+ }
+
+ protected String getUtf8(Deserializer buf) {
+ return Utf8.toString(getRawUtf8Bytes(buf));
}
protected void putUtf8(Serializer buf, String val) {