summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java1
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java7
-rw-r--r--config-model/src/main/java/com/yahoo/searchdefinition/processing/AddExtraFieldsToDocument.java24
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java9
-rw-r--r--config-model/src/test/derived/multiplesummaries/ilscripts.cfg4
-rw-r--r--config-model/src/test/derived/multiplesummaries/index-info.cfg24
-rw-r--r--config-model/src/test/derived/multiplesummaries/multiplesummaries.sd19
-rw-r--r--config-model/src/test/derived/multiplesummaries/summary.cfg22
-rw-r--r--config-model/src/test/derived/multiplesummaries/summarymap.cfg6
-rw-r--r--config-model/src/test/examples/nextgen/summaryfield.sd10
-rw-r--r--config-model/src/test/java/com/yahoo/searchdefinition/processing/ImplicitSchemaFieldsTestCase.java4
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java18
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java3
-rw-r--r--eval/CMakeLists.txt1
-rw-r--r--eval/src/apps/analyze_onnx_model/CMakeLists.txt3
-rw-r--r--eval/src/apps/analyze_onnx_model/analyze_onnx_model.cpp44
-rw-r--r--eval/src/tests/apps/analyze_onnx_model/CMakeLists.txt9
-rw-r--r--eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp137
-rw-r--r--eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp22
-rw-r--r--eval/src/tests/tensor/onnx_wrapper/probe_model.onnx30
-rwxr-xr-xeval/src/tests/tensor/onnx_wrapper/probe_model.py35
-rw-r--r--eval/src/vespa/eval/eval/test/CMakeLists.txt1
-rw-r--r--eval/src/vespa/eval/eval/test/eval_onnx.cpp54
-rw-r--r--eval/src/vespa/eval/eval/test/eval_onnx.h13
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java2
-rw-r--r--searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp18
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attributevector.cpp33
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attributevector.h2
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h3
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp7
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.cpp6
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.h3
-rw-r--r--searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp2
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp13
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h6
37 files changed, 558 insertions, 49 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
index 638a66db03f..19daa43de13 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -109,6 +109,7 @@ public interface ModelContext {
@ModelFeatureFlag(owners = {"vekterli"}) default String mergeThrottlingPolicy() { throw new UnsupportedOperationException("TODO specify default value"); }
@ModelFeatureFlag(owners = {"vekterli"}) default double persistenceThrottlingWsDecrementFactor() { throw new UnsupportedOperationException("TODO specify default value"); }
@ModelFeatureFlag(owners = {"vekterli"}) default double persistenceThrottlingWsBackoff() { throw new UnsupportedOperationException("TODO specify default value"); }
+ @ModelFeatureFlag(owners = {"geirst", "vekterli"}) default boolean inhibitDefaultMergesWhenGlobalMergesPending() { return false; }
@ModelFeatureFlag(owners = {"arnej"}) default boolean useQrserverServiceName() { return true; }
@ModelFeatureFlag(owners = {"bjorncs", "baldersheim"}) default boolean enableJdiscPreshutdownCommand() { return true; }
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index c9ddcdf38eb..0cde8c361a7 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -72,6 +72,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private String mergeThrottlingPolicy = "STATIC";
private double persistenceThrottlingWsDecrementFactor = 1.2;
private double persistenceThrottlingWsBackoff = 0.95;
+ private boolean inhibitDefaultMergesWhenGlobalMergesPending = false;
private boolean useV8GeoPositions = false;
private List<String> environmentVariables = List.of();
@@ -126,6 +127,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
@Override public String mergeThrottlingPolicy() { return mergeThrottlingPolicy; }
@Override public double persistenceThrottlingWsDecrementFactor() { return persistenceThrottlingWsDecrementFactor; }
@Override public double persistenceThrottlingWsBackoff() { return persistenceThrottlingWsBackoff; }
+ @Override public boolean inhibitDefaultMergesWhenGlobalMergesPending() { return inhibitDefaultMergesWhenGlobalMergesPending; }
@Override public boolean useV8GeoPositions() { return useV8GeoPositions; }
@Override public List<String> environmentVariables() { return environmentVariables; }
@@ -330,6 +332,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
+ public TestProperties inhibitDefaultMergesWhenGlobalMergesPending(boolean value) {
+ this.inhibitDefaultMergesWhenGlobalMergesPending = value;
+ return this;
+ }
+
public TestProperties setUseV8GeoPositions(boolean value) {
this.useV8GeoPositions = value;
return this;
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddExtraFieldsToDocument.java b/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddExtraFieldsToDocument.java
index 9d933b8439d..51defffa00b 100644
--- a/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddExtraFieldsToDocument.java
+++ b/config-model/src/main/java/com/yahoo/searchdefinition/processing/AddExtraFieldsToDocument.java
@@ -26,11 +26,6 @@ public class AddExtraFieldsToDocument extends Processor {
super(schema, deployLogger, rankProfileRegistry, queryProfiles);
}
- //TODO This is a tempoarry hack to avoid producing illegal code for fields not wanted anyway.
- private boolean dirtyLegalFieldNameCheck(String fieldName) {
- return ! fieldName.contains(".") && !"rankfeatures".equals(fieldName) && !"summaryfeatures".equals(fieldName);
- }
-
@Override
public void process(boolean validate, boolean documentsOnly) {
SDDocumentType document = schema.getDocument();
@@ -38,10 +33,21 @@ public class AddExtraFieldsToDocument extends Processor {
for (SDField field : schema.extraFieldList()) {
addSdField(schema, document, field, validate);
}
- //TODO Vespa 8 or sooner we should avoid the dirty addition of fields from dirty 'default' summary to document at all
- for (SummaryField field : schema.getSummary("default").getSummaryFields().values()) {
- if (dirtyLegalFieldNameCheck(field.getName())) {
- addSummaryField(schema, document, field, validate);
+ for (var docsum : schema.getSummaries().values()) {
+ for (var summaryField : docsum.getSummaryFields().values()) {
+ switch (summaryField.getTransform()) {
+ case NONE:
+ case BOLDED:
+ case DYNAMICBOLDED:
+ case DYNAMICTEASER:
+ case TEXTEXTRACTOR:
+ addSummaryField(schema, document, summaryField, validate);
+ break;
+ default:
+ // skip: generated from attribute or similar,
+ // so does not need to be included as an extra
+ // field in the document type
+ }
}
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
index b8d2a4f91fe..3f01f5610f1 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/DistributorCluster.java
@@ -43,6 +43,7 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
private final boolean useThreePhaseUpdates;
private final int maxActivationInhibitedOutOfSyncGroups;
private final boolean unorderedMergeChaining;
+ private final boolean inhibitDefaultMergesWhenGlobalMergesPending;
public static class Builder extends VespaDomBuilder.DomConfigProducerBuilder<DistributorCluster> {
@@ -106,11 +107,12 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
boolean useThreePhaseUpdates = deployState.getProperties().featureFlags().useThreePhaseUpdates();
int maxInhibitedGroups = deployState.getProperties().featureFlags().maxActivationInhibitedOutOfSyncGroups();
boolean unorderedMergeChaining = deployState.getProperties().featureFlags().unorderedMergeChaining();
+ boolean inhibitDefaultMerges = deployState.getProperties().featureFlags().inhibitDefaultMergesWhenGlobalMergesPending();
return new DistributorCluster(parent,
new BucketSplitting.Builder().build(new ModelElement(producerSpec)), gc,
hasIndexedDocumentType, useThreePhaseUpdates,
- maxInhibitedGroups, unorderedMergeChaining);
+ maxInhibitedGroups, unorderedMergeChaining, inhibitDefaultMerges);
}
}
@@ -118,7 +120,8 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
GcOptions gc, boolean hasIndexedDocumentType,
boolean useThreePhaseUpdates,
int maxActivationInhibitedOutOfSyncGroups,
- boolean unorderedMergeChaining)
+ boolean unorderedMergeChaining,
+ boolean inhibitDefaultMergesWhenGlobalMergesPending)
{
super(parent, "distributor");
this.parent = parent;
@@ -128,6 +131,7 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
this.useThreePhaseUpdates = useThreePhaseUpdates;
this.maxActivationInhibitedOutOfSyncGroups = maxActivationInhibitedOutOfSyncGroups;
this.unorderedMergeChaining = unorderedMergeChaining;
+ this.inhibitDefaultMergesWhenGlobalMergesPending = inhibitDefaultMergesWhenGlobalMergesPending;
}
@Override
@@ -142,6 +146,7 @@ public class DistributorCluster extends AbstractConfigProducer<Distributor> impl
builder.enable_metadata_only_fetch_phase_for_inconsistent_updates(useThreePhaseUpdates);
builder.max_activation_inhibited_out_of_sync_groups(maxActivationInhibitedOutOfSyncGroups);
builder.use_unordered_merge_chaining(unorderedMergeChaining);
+ builder.inhibit_default_merges_when_global_merges_pending(inhibitDefaultMergesWhenGlobalMergesPending);
bucketSplitting.getConfig(builder);
}
diff --git a/config-model/src/test/derived/multiplesummaries/ilscripts.cfg b/config-model/src/test/derived/multiplesummaries/ilscripts.cfg
index 64d4bd3ba0a..5434b0770f7 100644
--- a/config-model/src/test/derived/multiplesummaries/ilscripts.cfg
+++ b/config-model/src/test/derived/multiplesummaries/ilscripts.cfg
@@ -12,14 +12,16 @@ ilscript[].docfield[7] "f"
ilscript[].docfield[8] "g"
ilscript[].docfield[9] "h"
ilscript[].docfield[10] "loc"
+ilscript[].docfield[11] "mytags"
ilscript[].content[0] "clear_state | guard { input loc | to_pos | zcurve | attribute loc_pos_zcurve; }"
ilscript[].content[1] "clear_state | guard { input a | tokenize normalize stem:\"BEST\" | summary abolded2 | summary aboldeddynamic | summary adynamic2 | attribute a; }"
ilscript[].content[2] "clear_state | guard { input adynamic | tokenize normalize stem:\"BEST\" | summary adynamic | attribute adynamic; }"
ilscript[].content[3] "clear_state | guard { input abolded | tokenize normalize stem:\"BEST\" | summary abolded | attribute abolded; }"
-ilscript[].content[4] "clear_state | guard { input b | summary b; }"
+ilscript[].content[4] "clear_state | guard { input b | summary anotherb | summary b; }"
ilscript[].content[5] "clear_state | guard { input c | summary c | attribute c; }"
ilscript[].content[6] "clear_state | guard { input d | tokenize normalize stem:\"BEST\" | summary d; }"
ilscript[].content[7] "clear_state | guard { input e | tokenize normalize stem:\"BEST\" | summary dynamice | summary e; }"
ilscript[].content[8] "clear_state | guard { input f | summary f; }"
ilscript[].content[9] "clear_state | guard { input g | summary g; }"
ilscript[].content[10] "clear_state | guard { input h | summary h; }"
+ilscript[].content[11] "clear_state | guard { input mytags | for_each { tokenize normalize stem:\"BEST\" } | index mytags; }"
diff --git a/config-model/src/test/derived/multiplesummaries/index-info.cfg b/config-model/src/test/derived/multiplesummaries/index-info.cfg
index 9c53a66549c..d5002535761 100644
--- a/config-model/src/test/derived/multiplesummaries/index-info.cfg
+++ b/config-model/src/test/derived/multiplesummaries/index-info.cfg
@@ -71,6 +71,20 @@ indexinfo[].command[].indexname "loc"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "loc"
indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "lowercase"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "stem:BEST"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "normalize"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "plain-tokens"
+indexinfo[].command[].indexname "mytags"
+indexinfo[].command[].command "type Array<string>"
indexinfo[].command[].indexname "abolded2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "abolded2"
@@ -83,6 +97,16 @@ indexinfo[].command[].indexname "adynamic2"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "adynamic2"
indexinfo[].command[].command "type string"
+indexinfo[].command[].indexname "alltags"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "alltags"
+indexinfo[].command[].command "multivalue"
+indexinfo[].command[].indexname "alltags"
+indexinfo[].command[].command "type Array<string>"
+indexinfo[].command[].indexname "anotherb"
+indexinfo[].command[].command "index"
+indexinfo[].command[].indexname "anotherb"
+indexinfo[].command[].command "type string"
indexinfo[].command[].indexname "dynamice"
indexinfo[].command[].command "index"
indexinfo[].command[].indexname "dynamice"
diff --git a/config-model/src/test/derived/multiplesummaries/multiplesummaries.sd b/config-model/src/test/derived/multiplesummaries/multiplesummaries.sd
index a1454a8d8a4..ae0e2fe92bc 100644
--- a/config-model/src/test/derived/multiplesummaries/multiplesummaries.sd
+++ b/config-model/src/test/derived/multiplesummaries/multiplesummaries.sd
@@ -67,6 +67,10 @@ search multiplesummaries {
field loc type string {
}
+
+ field mytags type array<string> {
+ indexing: index
+ }
}
field loc_pos type position {
@@ -120,7 +124,7 @@ search multiplesummaries {
}
# Since a here is a dynamic summary, it will be fetched from disk
- document-summary notattributesonly2 {
+ document-summary anothernotattributesonly2 {
summary adynamic2 type string { # Should still be dynamic here
source: a
@@ -130,6 +134,19 @@ search multiplesummaries {
summary c type string {
}
+ summary alltags type array<string> {
+ source: mytags
+ }
+ summary sometags type array<string> {
+ source: mytags
+ matched-elements-only
+ }
+ summary anothera type string {
+ source: a
+ }
+ summary anotherb type string {
+ source: b
+ }
}
# Not attributes only because d is bolded
diff --git a/config-model/src/test/derived/multiplesummaries/summary.cfg b/config-model/src/test/derived/multiplesummaries/summary.cfg
index ec5e0610385..1c8fc47878b 100644
--- a/config-model/src/test/derived/multiplesummaries/summary.cfg
+++ b/config-model/src/test/derived/multiplesummaries/summary.cfg
@@ -1,6 +1,6 @@
-defaultsummaryid 2038247029
+defaultsummaryid 456145241
usev8geopositions false
-classes[].id 2038247029
+classes[].id 456145241
classes[].name "default"
classes[].omitsummaryfeatures false
classes[].fields[].name "loc_pos"
@@ -37,6 +37,12 @@ classes[].fields[].name "e"
classes[].fields[].type "longstring"
classes[].fields[].name "adynamic2"
classes[].fields[].type "longstring"
+classes[].fields[].name "alltags"
+classes[].fields[].type "jsonstring"
+classes[].fields[].name "sometags"
+classes[].fields[].type "jsonstring"
+classes[].fields[].name "anotherb"
+classes[].fields[].type "longstring"
classes[].fields[].name "abolded2"
classes[].fields[].type "longstring"
classes[].fields[].name "aboldeddynamic"
@@ -86,13 +92,21 @@ classes[].fields[].name "rankfeatures"
classes[].fields[].type "featuredata"
classes[].fields[].name "summaryfeatures"
classes[].fields[].type "featuredata"
-classes[].id 1527097108
-classes[].name "notattributesonly2"
+classes[].id 1609068631
+classes[].name "anothernotattributesonly2"
classes[].omitsummaryfeatures false
classes[].fields[].name "adynamic2"
classes[].fields[].type "longstring"
classes[].fields[].name "c"
classes[].fields[].type "longstring"
+classes[].fields[].name "alltags"
+classes[].fields[].type "jsonstring"
+classes[].fields[].name "sometags"
+classes[].fields[].type "jsonstring"
+classes[].fields[].name "anothera"
+classes[].fields[].type "longstring"
+classes[].fields[].name "anotherb"
+classes[].fields[].type "longstring"
classes[].fields[].name "rankfeatures"
classes[].fields[].type "featuredata"
classes[].fields[].name "summaryfeatures"
diff --git a/config-model/src/test/derived/multiplesummaries/summarymap.cfg b/config-model/src/test/derived/multiplesummaries/summarymap.cfg
index adf0770a835..94adc250c54 100644
--- a/config-model/src/test/derived/multiplesummaries/summarymap.cfg
+++ b/config-model/src/test/derived/multiplesummaries/summarymap.cfg
@@ -20,6 +20,12 @@ override[].arguments "c"
override[].field "adynamic2"
override[].command "dynamicteaser"
override[].arguments "adynamic2"
+override[].field "sometags"
+override[].command "matchedelementsfilter"
+override[].arguments "mytags"
+override[].field "anothera"
+override[].command "attribute"
+override[].arguments "a"
override[].field "anotdynamic"
override[].command "attribute"
override[].arguments "adynamic"
diff --git a/config-model/src/test/examples/nextgen/summaryfield.sd b/config-model/src/test/examples/nextgen/summaryfield.sd
index 9b3cc6862b9..99c73d1be53 100644
--- a/config-model/src/test/examples/nextgen/summaryfield.sd
+++ b/config-model/src/test/examples/nextgen/summaryfield.sd
@@ -5,11 +5,21 @@ search summaryfield {
indexing: index | summary
summary bar: full
}
+ field mytags type array<string> {
+ indexing: index
+ }
}
document-summary baz {
summary cox type string {
source: bar
}
+ summary alltags type array<string> {
+ source: mytags
+ }
+ summary sometags type array<string> {
+ source: mytags
+ matched-elements-only
+ }
}
}
diff --git a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImplicitSchemaFieldsTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImplicitSchemaFieldsTestCase.java
index b0b9ce81cc7..833a6effe4a 100644
--- a/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImplicitSchemaFieldsTestCase.java
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/processing/ImplicitSchemaFieldsTestCase.java
@@ -38,7 +38,9 @@ public class ImplicitSchemaFieldsTestCase extends AbstractSchemaTestCase {
assertNotNull(docType.getField("foo"));
assertNotNull(docType.getField("bar"));
assertNotNull(docType.getField("cox"));
- assertEquals(3, docType.getFieldCount());
+ assertNotNull(docType.getField("mytags"));
+ assertNotNull(docType.getField("alltags"));
+ assertEquals(5, docType.getFieldCount());
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
index 88073d281c5..9f571167d8c 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java
@@ -1159,6 +1159,24 @@ public class ContentClusterTest extends ContentBaseTest {
}
@Test
+ public void inhibit_default_merges_when_global_merges_pending_controlled_by_properties() throws Exception {
+ assertFalse(resolveInhibitDefaultMergesConfig(Optional.empty()));
+ assertFalse(resolveInhibitDefaultMergesConfig(Optional.of(false)));
+ assertTrue(resolveInhibitDefaultMergesConfig(Optional.of(true)));
+ }
+
+ private boolean resolveInhibitDefaultMergesConfig(Optional<Boolean> inhibitDefaultMerges) throws Exception {
+ var props = new TestProperties();
+ if (inhibitDefaultMerges.isPresent()) {
+ props.inhibitDefaultMergesWhenGlobalMergesPending(inhibitDefaultMerges.get());
+ }
+ var cluster = createOneNodeCluster(props);
+ var builder = new StorDistributormanagerConfig.Builder();
+ cluster.getDistributorNodes().getConfig(builder);
+ return (new StorDistributormanagerConfig(builder)).inhibit_default_merges_when_global_merges_pending();
+ }
+
+ @Test
public void testDedicatedClusterControllers() {
VespaModel noContentModel = createEnd2EndOneNode(new TestProperties().setHostedVespa(true)
.setMultitenant(true),
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 7cc5f5edd14..6028d559473 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -203,6 +203,7 @@ public class ModelContextImpl implements ModelContext {
private final String mergeThrottlingPolicy;
private final double persistenceThrottlingWsDecrementFactor;
private final double persistenceThrottlingWsBackoff;
+ private final boolean inhibitDefaultMergesWhenGlobalMergesPending;
private final boolean useQrserverServiceName;
public FeatureFlags(FlagSource source, ApplicationId appId) {
@@ -245,6 +246,7 @@ public class ModelContextImpl implements ModelContext {
this.mergeThrottlingPolicy = flagValue(source, appId, Flags.MERGE_THROTTLING_POLICY);
this.persistenceThrottlingWsDecrementFactor = flagValue(source, appId, Flags.PERSISTENCE_THROTTLING_WS_DECREMENT_FACTOR);
this.persistenceThrottlingWsBackoff = flagValue(source, appId, Flags.PERSISTENCE_THROTTLING_WS_BACKOFF);
+ this.inhibitDefaultMergesWhenGlobalMergesPending = flagValue(source, appId, Flags.INHIBIT_DEFAULT_MERGES_WHEN_GLOBAL_MERGES_PENDING);
this.useQrserverServiceName = flagValue(source, appId, Flags.USE_QRSERVER_SERVICE_NAME);
}
@@ -289,6 +291,7 @@ public class ModelContextImpl implements ModelContext {
@Override public String mergeThrottlingPolicy() { return mergeThrottlingPolicy; }
@Override public double persistenceThrottlingWsDecrementFactor() { return persistenceThrottlingWsDecrementFactor; }
@Override public double persistenceThrottlingWsBackoff() { return persistenceThrottlingWsBackoff; }
+ @Override public boolean inhibitDefaultMergesWhenGlobalMergesPending() { return inhibitDefaultMergesWhenGlobalMergesPending; }
@Override public boolean useQrserverServiceName() { return useQrserverServiceName; }
private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) {
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index eed4fa5ce66..e6669e3fde8 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -12,6 +12,7 @@ vespa_define_module(
TESTS
src/tests/ann
+ src/tests/apps/analyze_onnx_model
src/tests/apps/eval_expr
src/tests/eval/addr_to_symbol
src/tests/eval/aggr
diff --git a/eval/src/apps/analyze_onnx_model/CMakeLists.txt b/eval/src/apps/analyze_onnx_model/CMakeLists.txt
index e2ed64cd8cc..dc89213f9eb 100644
--- a/eval/src/apps/analyze_onnx_model/CMakeLists.txt
+++ b/eval/src/apps/analyze_onnx_model/CMakeLists.txt
@@ -1,7 +1,8 @@
# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-vespa_add_executable(vespa-analyze-onnx-model
+vespa_add_executable(eval_analyze_onnx_model_app
SOURCES
analyze_onnx_model.cpp
+ OUTPUT_NAME vespa-analyze-onnx-model
INSTALL bin
DEPENDS
vespaeval
diff --git a/eval/src/apps/analyze_onnx_model/analyze_onnx_model.cpp b/eval/src/apps/analyze_onnx_model/analyze_onnx_model.cpp
index 2f22f903f2e..506073ae8b3 100644
--- a/eval/src/apps/analyze_onnx_model/analyze_onnx_model.cpp
+++ b/eval/src/apps/analyze_onnx_model/analyze_onnx_model.cpp
@@ -4,6 +4,7 @@
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/test/test_io.h>
#include <vespa/vespalib/util/benchmark_timer.h>
#include <vespa/vespalib/util/require.h>
#include <vespa/vespalib/util/guard.h>
@@ -11,8 +12,13 @@
using vespalib::make_string_short::fmt;
+using vespalib::Slime;
+using vespalib::slime::JsonFormat;
+using vespalib::slime::Inspector;
+using vespalib::slime::Cursor;
using vespalib::FilePointer;
using namespace vespalib::eval;
+using namespace vespalib::eval::test;
bool read_line(FilePointer &file, vespalib::string &line) {
char line_buffer[1024];
@@ -169,14 +175,50 @@ int usage(const char *self) {
fprintf(stderr, " load onnx model and report memory usage\n");
fprintf(stderr, " options are used to specify unknown values, like dimension sizes\n");
fprintf(stderr, " options are accepted in the order in which they are needed\n");
- fprintf(stderr, " tip: run without options first, to see which you need\n");
+ fprintf(stderr, " tip: run without options first, to see which you need\n\n");
+ fprintf(stderr, "usage: %s --probe-types\n", self);
+ fprintf(stderr, " use onnx model to infer/probe output types based on input types\n");
+ fprintf(stderr, " parameters are read from stdin and results are written to stdout\n");
+ fprintf(stderr, " input format (json): {model:<filename>, inputs:{<name>:vespa-type-string}}\n");
+ fprintf(stderr, " output format (json): {outputs:{<name>:vespa-type-string}}\n");
return 1;
}
+int probe_types() {
+ StdIn std_in;
+ StdOut std_out;
+ Slime params;
+ if (!JsonFormat::decode(std_in, params)) {
+ return 3;
+ }
+ Slime result;
+ auto &root = result.setObject();
+ auto &types = root.setObject("outputs");
+ Onnx model(params["model"].asString().make_string(), Onnx::Optimize::DISABLE);
+ Onnx::WirePlanner planner;
+ for (size_t i = 0; i < model.inputs().size(); ++i) {
+ auto spec = params["inputs"][model.inputs()[i].name].asString().make_string();
+ auto input_type = ValueType::from_spec(spec);
+ REQUIRE(!input_type.is_error());
+ REQUIRE(planner.bind_input_type(input_type, model.inputs()[i]));
+ }
+ planner.prepare_output_types(model);
+ for (const auto &output: model.outputs()) {
+ auto output_type = planner.make_output_type(output);
+ REQUIRE(!output_type.is_error());
+ types.setString(output.name, output_type.to_spec());
+ }
+ write_compact(result, std_out);
+ return 0;
+}
+
int my_main(int argc, char **argv) {
if (argc < 2) {
return usage(argv[0]);
}
+ if ((argc == 2) && (vespalib::string(argv[1]) == "--probe-types")) {
+ return probe_types();
+ }
Options opts;
for (int i = 2; i < argc; ++i) {
opts.add_option(argv[i]);
diff --git a/eval/src/tests/apps/analyze_onnx_model/CMakeLists.txt b/eval/src/tests/apps/analyze_onnx_model/CMakeLists.txt
new file mode 100644
index 00000000000..7b70360a622
--- /dev/null
+++ b/eval/src/tests/apps/analyze_onnx_model/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(eval_analyze_onnx_model_test_app TEST
+ SOURCES
+ analyze_onnx_model_test.cpp
+ DEPENDS
+ vespaeval
+)
+vespa_add_test(NAME eval_analyze_onnx_model_test_app COMMAND eval_analyze_onnx_model_test_app
+ DEPENDS eval_analyze_onnx_model_test_app eval_analyze_onnx_model_app)
diff --git a/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp b/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp
new file mode 100644
index 00000000000..2c1b2b21b9e
--- /dev/null
+++ b/eval/src/tests/apps/analyze_onnx_model/analyze_onnx_model_test.cpp
@@ -0,0 +1,137 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/testkit/time_bomb.h>
+#include <vespa/vespalib/util/stringfmt.h>
+#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/util/child_process.h>
+#include <vespa/vespalib/data/input.h>
+#include <vespa/vespalib/data/output.h>
+#include <vespa/vespalib/data/simple_buffer.h>
+#include <vespa/vespalib/util/size_literals.h>
+#include <vespa/eval/eval/test/test_io.h>
+
+using namespace vespalib;
+using namespace vespalib::eval::test;
+using vespalib::make_string_short::fmt;
+using vespalib::slime::JsonFormat;
+using vespalib::slime::Inspector;
+
+vespalib::string module_build_path("../../../../");
+vespalib::string binary = module_build_path + "src/apps/analyze_onnx_model/vespa-analyze-onnx-model";
+vespalib::string probe_cmd = binary + " --probe-types";
+
+std::string get_source_dir() {
+ const char *dir = getenv("SOURCE_DIRECTORY");
+ return (dir ? dir : ".");
+}
+std::string source_dir = get_source_dir();
+std::string guess_batch_model = source_dir + "/../../tensor/onnx_wrapper/guess_batch.onnx";
+
+//-----------------------------------------------------------------------------
+
+void read_until_eof(Input &input) {
+ for (auto mem = input.obtain(); mem.size > 0; mem = input.obtain()) {
+ input.evict(mem.size);
+ }
+}
+
+// Output adapter used to write to stdin of a child process
+class ChildIn : public Output {
+ ChildProcess &_child;
+ SimpleBuffer _output;
+public:
+ ChildIn(ChildProcess &child) : _child(child) {}
+ WritableMemory reserve(size_t bytes) override {
+ return _output.reserve(bytes);
+ }
+ Output &commit(size_t bytes) override {
+ _output.commit(bytes);
+ Memory buf = _output.obtain();
+ ASSERT_TRUE(_child.write(buf.data, buf.size));
+ _output.evict(buf.size);
+ return *this;
+ }
+};
+
+// Input adapter used to read from stdout of a child process
+class ChildOut : public Input {
+ ChildProcess &_child;
+ SimpleBuffer _input;
+public:
+ ChildOut(ChildProcess &child)
+ : _child(child)
+ {
+ EXPECT_TRUE(_child.running());
+ EXPECT_TRUE(!_child.failed());
+ }
+ Memory obtain() override {
+ if ((_input.get().size == 0) && !_child.eof()) {
+ WritableMemory buf = _input.reserve(4_Ki);
+ uint32_t res = _child.read(buf.data, buf.size);
+ ASSERT_TRUE((res > 0) || _child.eof());
+ _input.commit(res);
+ }
+ return _input.obtain();
+ }
+ Input &evict(size_t bytes) override {
+ _input.evict(bytes);
+ return *this;
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+void dump_message(const char *prefix, const Slime &slime) {
+ SimpleBuffer buf;
+ slime::JsonFormat::encode(slime, buf, true);
+ auto str = buf.get().make_string();
+ fprintf(stderr, "%s%s\n", prefix, str.c_str());
+}
+
+class Server {
+private:
+ TimeBomb _bomb;
+ ChildProcess _child;
+ ChildIn _child_stdin;
+ ChildOut _child_stdout;
+public:
+ Server(vespalib::string cmd)
+ : _bomb(60),
+ _child(cmd.c_str()),
+ _child_stdin(_child),
+ _child_stdout(_child) {}
+ ~Server();
+ Slime invoke(const Slime &req) {
+ dump_message("request --> ", req);
+ write_compact(req, _child_stdin);
+ Slime reply;
+ ASSERT_TRUE(JsonFormat::decode(_child_stdout, reply));
+ dump_message(" reply <-- ", reply);
+ return reply;
+ }
+};
+Server::~Server() {
+ _child.close();
+ read_until_eof(_child_stdout);
+ ASSERT_TRUE(_child.wait());
+ ASSERT_TRUE(!_child.running());
+ ASSERT_TRUE(!_child.failed());
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_F("require that output types can be probed", Server(probe_cmd)) {
+ Slime params;
+ params.setObject();
+ params.get().setString("model", guess_batch_model);
+ params.get().setObject("inputs");
+ params["inputs"].setString("in1", "tensor<float>(x[3])");
+ params["inputs"].setString("in2", "tensor<float>(x[3])");
+ Slime result = f1.invoke(params);
+ EXPECT_EQUAL(result["outputs"]["out"].asString().make_string(), vespalib::string("tensor<float>(d0[3])"));
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_MAIN_WITH_PROCESS_PROXY() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp b/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
index da957673f95..e50c41e2e09 100644
--- a/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
+++ b/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp
@@ -2,6 +2,7 @@
#include <vespa/eval/eval/tensor_spec.h>
#include <vespa/eval/eval/int8float.h>
+#include <vespa/eval/eval/test/eval_onnx.h>
#include <vespa/eval/onnx/onnx_wrapper.h>
#include <vespa/eval/onnx/onnx_model_cache.h>
#include <vespa/vespalib/util/bfloat16.h>
@@ -28,6 +29,7 @@ std::string int_types_model = source_dir + "/int_types.onnx";
std::string guess_batch_model = source_dir + "/guess_batch.onnx";
std::string unstable_types_model = source_dir + "/unstable_types.onnx";
std::string float_to_int8_model = source_dir + "/float_to_int8.onnx";
+std::string probe_model = source_dir + "/probe_model.onnx";
void dump_info(const char *ctx, const std::vector<TensorInfo> &info) {
fprintf(stderr, "%s:\n", ctx);
@@ -504,4 +506,24 @@ TEST(OnnxModelCacheTest, share_and_evict_onnx_models) {
EXPECT_EQ(OnnxModelCache::count_refs(), 0);
}
+TensorSpec val(const vespalib::string &expr) {
+ auto result = TensorSpec::from_expr(expr);
+ EXPECT_FALSE(ValueType::from_spec(result.type()).is_error());
+ return result;
+}
+
+TEST(OnnxTest, eval_onnx_with_probe_model) {
+ Onnx model(probe_model, Onnx::Optimize::ENABLE);
+ auto in1 = val("tensor<float>( x[2], y[3]):[[ 1, 2, 3],[ 4, 5, 6]]");
+ auto in2 = val("tensor<float>( x[2], y[3]):[[ 7, 8, 9],[ 4, 5, 6]]");
+ auto out1 = val("tensor<float>(d0[2],d1[3]):[[ 8,10,12],[ 8,10,12]]");
+ auto out2 = val("tensor<float>(d0[2],d1[3]):[[-6,-6,-6],[ 0, 0, 0]]");
+ auto out3 = val("tensor<float>(d0[2],d1[3]):[[ 7,16,27],[16,25,36]]");
+ auto result = test::eval_onnx(model, {in1, in2});
+ ASSERT_EQ(result.size(), 3);
+ EXPECT_EQ(result[0], out1);
+ EXPECT_EQ(result[1], out2);
+ EXPECT_EQ(result[2], out3);
+}
+
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/tensor/onnx_wrapper/probe_model.onnx b/eval/src/tests/tensor/onnx_wrapper/probe_model.onnx
new file mode 100644
index 00000000000..89dab2e7c4c
--- /dev/null
+++ b/eval/src/tests/tensor/onnx_wrapper/probe_model.onnx
@@ -0,0 +1,30 @@
+probe_model.py:’
+
+in1
+in2out1"Add
+
+in1
+in2out2"Sub
+
+in1
+in2out3"Mul probe_modelZ#
+in1
+
+ ÿÿÿÿÿÿÿÿÿ
+innerZ#
+in2
+
+outer
+ ÿÿÿÿÿÿÿÿÿb$
+out1
+
+ ÿÿÿÿÿÿÿÿÿ
+innerb$
+out2
+
+outer
+ ÿÿÿÿÿÿÿÿÿb(
+out3
+
+ ÿÿÿÿÿÿÿÿÿ
+ ÿÿÿÿÿÿÿÿÿB \ No newline at end of file
diff --git a/eval/src/tests/tensor/onnx_wrapper/probe_model.py b/eval/src/tests/tensor/onnx_wrapper/probe_model.py
new file mode 100755
index 00000000000..529fa23b2b1
--- /dev/null
+++ b/eval/src/tests/tensor/onnx_wrapper/probe_model.py
@@ -0,0 +1,35 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+import onnx
+from onnx import helper, TensorProto
+
+IN1 = helper.make_tensor_value_info('in1', TensorProto.FLOAT, [-1, 'inner'])
+IN2 = helper.make_tensor_value_info('in2', TensorProto.FLOAT, ['outer', -1])
+OUT1 = helper.make_tensor_value_info('out1', TensorProto.FLOAT, [-1, 'inner'])
+OUT2 = helper.make_tensor_value_info('out2', TensorProto.FLOAT, ['outer', -1])
+OUT3 = helper.make_tensor_value_info('out3', TensorProto.FLOAT, [-1, -1])
+
+nodes = [
+ helper.make_node(
+ 'Add',
+ ['in1', 'in2'],
+ ['out1'],
+ ),
+ helper.make_node(
+ 'Sub',
+ ['in1', 'in2'],
+ ['out2'],
+ ),
+ helper.make_node(
+ 'Mul',
+ ['in1', 'in2'],
+ ['out3'],
+ ),
+]
+graph_def = helper.make_graph(
+ nodes,
+ 'probe_model',
+ [IN1, IN2],
+ [OUT1, OUT2, OUT3],
+)
+model_def = helper.make_model(graph_def, producer_name='probe_model.py', opset_imports=[onnx.OperatorSetIdProto(version=12)])
+onnx.save(model_def, 'probe_model.onnx')
diff --git a/eval/src/vespa/eval/eval/test/CMakeLists.txt b/eval/src/vespa/eval/eval/test/CMakeLists.txt
index e8a291adf2a..ff1505a4010 100644
--- a/eval/src/vespa/eval/eval/test/CMakeLists.txt
+++ b/eval/src/vespa/eval/eval/test/CMakeLists.txt
@@ -3,6 +3,7 @@ vespa_add_library(eval_eval_test OBJECT
SOURCES
cell_type_space.cpp
eval_fixture.cpp
+ eval_onnx.cpp
eval_spec.cpp
gen_spec.cpp
reference_evaluation.cpp
diff --git a/eval/src/vespa/eval/eval/test/eval_onnx.cpp b/eval/src/vespa/eval/eval/test/eval_onnx.cpp
new file mode 100644
index 00000000000..74a83b130c2
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/eval_onnx.cpp
@@ -0,0 +1,54 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "eval_onnx.h"
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/value_codec.h>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".eval.eval.test.eval_onnx");
+
+namespace vespalib::eval::test {
+
+std::vector<TensorSpec> eval_onnx(const Onnx &model, const std::vector<TensorSpec> &params) {
+ if (params.size() != model.inputs().size()) {
+ LOG(error, "model with %zu inputs run with %zu parameters", model.inputs().size(), params.size());
+ return {}; // wrong number of parameters
+ }
+ Onnx::WirePlanner planner;
+ for (size_t i = 0; i < model.inputs().size(); ++i) {
+ if (!planner.bind_input_type(ValueType::from_spec(params[i].type()), model.inputs()[i])) {
+ LOG(error, "unable to bind input type: %s -> %s", params[i].type().c_str(), model.inputs()[i].type_as_string().c_str());
+ return {}; // inconsistent input types
+ }
+ }
+ planner.prepare_output_types(model);
+ for (size_t i = 0; i < model.outputs().size(); ++i) {
+ if (planner.make_output_type(model.outputs()[i]).is_error()) {
+ LOG(error, "unable to make output type: %s -> error", model.outputs()[i].type_as_string().c_str());
+ return {}; // unable to infer/probe output type
+ }
+ }
+ planner.prepare_output_types(model);
+ auto wire_info = planner.get_wire_info(model);
+ try {
+ Onnx::EvalContext context(model, wire_info);
+ std::vector<Value::UP> inputs;
+ for (const auto &param: params) {
+ inputs.push_back(value_from_spec(param, FastValueBuilderFactory::get()));
+ }
+ for (size_t i = 0; i < model.inputs().size(); ++i) {
+ context.bind_param(i, *inputs[i]);
+ }
+ context.eval();
+ std::vector<TensorSpec> results;
+ for (size_t i = 0; i < model.outputs().size(); ++i) {
+ results.push_back(spec_from_value(context.get_result(i)));
+ }
+ return results;
+ } catch (const Ort::Exception &ex) {
+ LOG(error, "model run failed: %s", ex.what());
+ return {}; // evaluation failed
+ }
+}
+
+} // namespace
diff --git a/eval/src/vespa/eval/eval/test/eval_onnx.h b/eval/src/vespa/eval/eval/test/eval_onnx.h
new file mode 100644
index 00000000000..bb346b7f21e
--- /dev/null
+++ b/eval/src/vespa/eval/eval/test/eval_onnx.h
@@ -0,0 +1,13 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/tensor_spec.h>
+#include <vespa/eval/onnx/onnx_wrapper.h>
+#include <vector>
+
+namespace vespalib::eval::test {
+
+std::vector<TensorSpec> eval_onnx(const Onnx &model, const std::vector<TensorSpec> &params);
+
+} // namespace
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 9c1e1776894..2e985a4fca0 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -328,6 +328,14 @@ public class Flags {
"Takes effect on redeployment",
ZONE_ID, APPLICATION_ID);
+ public static final UnboundBooleanFlag INHIBIT_DEFAULT_MERGES_WHEN_GLOBAL_MERGES_PENDING = defineFeatureFlag(
+ "inhibit-default-merges-when-global-merges-pending", false,
+ List.of("geirst", "vekterli"), "2022-02-11", "2022-06-01",
+ "Inhibits all merges to buckets in the default bucket space if the current " +
+ "cluster state bundle indicates that global merges are pending in the cluster",
+ "Takes effect on redeployment",
+ ZONE_ID, APPLICATION_ID);
+
public static final UnboundBooleanFlag CHECK_CONFIG_CONVERGENCE_BEFORE_RESTARTING = defineFeatureFlag(
"check-config-convergence-before-restart", true,
List.of("hmusum"), "2022-01-16", "2022-02-16",
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
index 57db874fb84..552db84748d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeMover.java
@@ -74,6 +74,8 @@ public abstract class NodeMover<MOVE> extends NodeRepositoryMaintainer {
if (deployedRecently(applicationId)) continue;
for (HostWithResources toHost : hostResources) {
if (toHost.node.hostname().equals(node.parentHostname().get())) continue;
+ if (toHost.node.reservedTo().isPresent() &&
+ !toHost.node.reservedTo().get().equals(applicationId.tenant())) continue; // Reserved to a different tenant
if (spares.contains(toHost.node)) continue; // Do not offer spares as a valid move as they are reserved for replacement of failed nodes
if ( ! toHost.hasCapacity(node.resources())) continue;
diff --git a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
index bddaa4f4e31..29af989d484 100644
--- a/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
+++ b/searchlib/src/tests/attribute/multi_value_mapping/multi_value_mapping_test.cpp
@@ -6,6 +6,7 @@
#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/vespalib/stllike/hash_set.h>
#include <vespa/vespalib/test/insertion_operators.h>
+#include <vespa/vespalib/test/memory_allocator_observer.h>
#include <vespa/vespalib/util/generationhandler.h>
#include <vespa/vespalib/util/rand48.h>
#include <vespa/vespalib/util/size_literals.h>
@@ -16,6 +17,8 @@ LOG_SETUP("multivaluemapping_test");
using vespalib::datastore::ArrayStoreConfig;
using vespalib::datastore::CompactionSpec;
using vespalib::datastore::CompactionStrategy;
+using vespalib::alloc::test::MemoryAllocatorObserver;
+using AllocStats = MemoryAllocatorObserver::Stats;
template <typename EntryT>
void
@@ -69,6 +72,7 @@ class MappingTestBase : public ::testing::Test {
protected:
using MvMapping = search::attribute::MultiValueMapping<EntryT>;
using AttributeType = MyAttribute<MvMapping>;
+ AllocStats _stats;
std::unique_ptr<MvMapping> _mvMapping;
std::unique_ptr<AttributeType> _attr;
uint32_t _maxSmallArraySize;
@@ -78,7 +82,8 @@ protected:
public:
using ConstArrayRef = vespalib::ConstArrayRef<EntryT>;
MappingTestBase()
- : _mvMapping(),
+ : _stats(),
+ _mvMapping(),
_attr(),
_maxSmallArraySize()
{
@@ -87,7 +92,7 @@ public:
ArrayStoreConfig config(maxSmallArraySize,
ArrayStoreConfig::AllocSpec(0, RefType::offsetSize(), 8_Ki, ALLOC_GROW_FACTOR));
config.enable_free_lists(enable_free_lists);
- _mvMapping = std::make_unique<MvMapping>(config);
+ _mvMapping = std::make_unique<MvMapping>(config, vespalib::GrowStrategy(), std::make_unique<MemoryAllocatorObserver>(_stats));
_attr = std::make_unique<AttributeType>(*_mvMapping);
_maxSmallArraySize = maxSmallArraySize;
}
@@ -95,7 +100,7 @@ public:
ArrayStoreConfig config(maxSmallArraySize,
ArrayStoreConfig::AllocSpec(minArrays, maxArrays, numArraysForNewBuffer, ALLOC_GROW_FACTOR));
config.enable_free_lists(enable_free_lists);
- _mvMapping = std::make_unique<MvMapping>(config);
+ _mvMapping = std::make_unique<MvMapping>(config, vespalib::GrowStrategy(), std::make_unique<MemoryAllocatorObserver>(_stats));
_attr = std::make_unique<AttributeType>(*_mvMapping);
_maxSmallArraySize = maxSmallArraySize;
}
@@ -129,6 +134,7 @@ public:
_mvMapping->clearDocs(lidLow, lidLimit, [this](uint32_t docId) { _attr->clearDoc(docId); });
}
size_t getTotalValueCnt() const { return _mvMapping->getTotalValueCnt(); }
+ const AllocStats &get_stats() const noexcept { return _stats; }
uint32_t countBuffers() {
using RefVector = typename MvMapping::RefCopyVector;
@@ -326,6 +332,12 @@ TEST_F(IntMappingTest, test_that_free_lists_can_be_disabled)
EXPECT_FALSE(_mvMapping->has_free_lists_enabled());
}
+TEST_F(IntMappingTest, provided_memory_allocator_is_used)
+{
+ setup(3, 64, 512, 129, true);
+ EXPECT_EQ(AllocStats(5, 0), get_stats());
+}
+
TEST_F(CompactionIntMappingTest, test_that_compaction_works)
{
setup(3, 64, 512, 129);
diff --git a/searchlib/src/vespa/searchlib/attribute/attributevector.cpp b/searchlib/src/vespa/searchlib/attribute/attributevector.cpp
index a2ac482ebf3..08721b7302e 100644
--- a/searchlib/src/vespa/searchlib/attribute/attributevector.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/attributevector.cpp
@@ -23,6 +23,7 @@
#include <vespa/searchlib/util/file_settings.h>
#include <vespa/searchlib/util/logutil.h>
#include <vespa/vespalib/util/exceptions.h>
+#include <vespa/vespalib/util/mmap_file_allocator_factory.h>
#include <vespa/vespalib/util/size_literals.h>
#include <thread>
@@ -107,6 +108,34 @@ AttributeVector::ValueModifier::~ValueModifier() {
}
}
+namespace {
+
+bool
+allow_paged(const search::attribute::Config& config)
+{
+ if (!config.paged()) {
+ return false;
+ }
+ using Type = search::attribute::BasicType::Type;
+ if (config.basicType() == Type::REFERENCE || config.basicType() == Type::PREDICATE) {
+ return false;
+ }
+ if (config.basicType() == Type::TENSOR) {
+ return (!config.tensorType().is_error() && config.tensorType().is_dense());
+ }
+ return true;
+}
+
+std::unique_ptr<vespalib::alloc::MemoryAllocator>
+make_memory_allocator(const vespalib::string& name, const search::attribute::Config& config)
+{
+ if (allow_paged(config)) {
+ return vespalib::alloc::MmapFileAllocatorFactory::instance().make_memory_allocator(name);
+ }
+ return {};
+}
+
+}
AttributeVector::AttributeVector(vespalib::stringref baseFileName, const Config &c)
: _baseFileName(baseFileName),
@@ -124,7 +153,9 @@ AttributeVector::AttributeVector(vespalib::stringref baseFileName, const Config
_compactLidSpaceGeneration(0u),
_hasEnum(false),
_loaded(false),
- _isUpdateableInMemoryOnly(attribute::isUpdateableInMemoryOnly(getName(), getConfig()))
+ _isUpdateableInMemoryOnly(attribute::isUpdateableInMemoryOnly(getName(), getConfig())),
+ _nextStatUpdateTime(),
+ _memory_allocator(make_memory_allocator(_baseFileName.getAttributeName(), c))
{
}
diff --git a/searchlib/src/vespa/searchlib/attribute/attributevector.h b/searchlib/src/vespa/searchlib/attribute/attributevector.h
index acd00413568..2bf2f3a6ed6 100644
--- a/searchlib/src/vespa/searchlib/attribute/attributevector.h
+++ b/searchlib/src/vespa/searchlib/attribute/attributevector.h
@@ -377,6 +377,7 @@ protected:
virtual vespalib::MemoryUsage getEnumStoreValuesMemoryUsage() const;
virtual void populate_address_space_usage(AddressSpaceUsage& usage) const;
+ const std::shared_ptr<vespalib::alloc::MemoryAllocator>& get_memory_allocator() const noexcept { return _memory_allocator; }
public:
DECLARE_IDENTIFIABLE_ABSTRACT(AttributeVector);
bool isLoaded() const { return _loaded; }
@@ -584,6 +585,7 @@ private:
bool _loaded;
bool _isUpdateableInMemoryOnly;
vespalib::steady_time _nextStatUpdateTime;
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> _memory_allocator;
////// Locking strategy interface. only available from the Guards.
/**
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h
index 81abaa05a45..f5f2950a59c 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.h
@@ -27,7 +27,8 @@ public:
MultiValueMapping(const MultiValueMapping &) = delete;
MultiValueMapping & operator = (const MultiValueMapping &) = delete;
MultiValueMapping(const vespalib::datastore::ArrayStoreConfig &storeCfg,
- const vespalib::GrowStrategy &gs = vespalib::GrowStrategy());
+ const vespalib::GrowStrategy &gs,
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator);
~MultiValueMapping() override;
ConstArrayRef get(uint32_t docId) const { return _store.get(_indices[docId]); }
ConstArrayRef getDataForIdx(EntryRef idx) const { return _store.get(idx); }
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp
index 339f562757d..16b29bf33cd 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping.hpp
@@ -10,16 +10,17 @@ namespace search::attribute {
template <typename EntryT, typename RefT>
MultiValueMapping<EntryT,RefT>::MultiValueMapping(const vespalib::datastore::ArrayStoreConfig &storeCfg,
- const vespalib::GrowStrategy &gs)
+ const vespalib::GrowStrategy &gs,
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wuninitialized"
#endif
- : MultiValueMappingBase(gs, _store.getGenerationHolder()),
+ : MultiValueMappingBase(gs, _store.getGenerationHolder(), memory_allocator),
#ifdef __clang__
#pragma clang diagnostic pop
#endif
- _store(storeCfg, {})
+ _store(storeCfg, std::move(memory_allocator))
{
}
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.cpp b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.cpp
index b0d50c129c6..7ad61ccedc5 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.cpp
@@ -10,8 +10,10 @@ namespace search::attribute {
using vespalib::datastore::CompactionStrategy;
MultiValueMappingBase::MultiValueMappingBase(const vespalib::GrowStrategy &gs,
- vespalib::GenerationHolder &genHolder)
- : _indices(gs, genHolder),
+ vespalib::GenerationHolder &genHolder,
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator)
+ : _memory_allocator(std::move(memory_allocator)),
+ _indices(gs, genHolder, _memory_allocator ? vespalib::alloc::Alloc::alloc_with_allocator(_memory_allocator.get()) : vespalib::alloc::Alloc::alloc()),
_totalValues(0u),
_compaction_spec()
{
diff --git a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.h b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.h
index f27a9f1667c..2b2b4d5f8a3 100644
--- a/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.h
+++ b/searchlib/src/vespa/searchlib/attribute/multi_value_mapping_base.h
@@ -27,11 +27,12 @@ public:
using RefVector = vespalib::RcuVectorBase<EntryRef>;
protected:
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> _memory_allocator;
RefVector _indices;
size_t _totalValues;
CompactionSpec _compaction_spec;
- MultiValueMappingBase(const vespalib::GrowStrategy &gs, vespalib::GenerationHolder &genHolder);
+ MultiValueMappingBase(const vespalib::GrowStrategy &gs, vespalib::GenerationHolder &genHolder, std::shared_ptr<vespalib::alloc::MemoryAllocator> memory_allocator);
virtual ~MultiValueMappingBase();
void updateValueCount(size_t oldValues, size_t newValues) {
diff --git a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
index b9ef16c6adf..c0524a4d043 100644
--- a/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
+++ b/searchlib/src/vespa/searchlib/attribute/multivalueattribute.hpp
@@ -28,7 +28,7 @@ MultiValueAttribute(const vespalib::string &baseFileName,
8 * 1024,
cfg.getGrowStrategy().getMultiValueAllocGrowFactor(),
multivalueattribute::enable_free_lists),
- cfg.getGrowStrategy().to_generic_strategy())
+ cfg.getGrowStrategy().to_generic_strategy(), {})
{
}
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
index 6dd630a6426..d376fb020be 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_attribute.cpp
@@ -99,17 +99,6 @@ BlobSequenceReader::is_present() {
return true;
}
-
-
-std::unique_ptr<vespalib::alloc::MemoryAllocator>
-make_memory_allocator(const vespalib::string& name, bool swappable)
-{
- if (swappable) {
- return vespalib::alloc::MmapFileAllocatorFactory::instance().make_memory_allocator(name);
- }
- return {};
-}
-
}
void
@@ -161,7 +150,7 @@ DenseTensorAttribute::populate_address_space_usage(AddressSpaceUsage& usage) con
DenseTensorAttribute::DenseTensorAttribute(vespalib::stringref baseFileName, const Config& cfg,
const NearestNeighborIndexFactory& index_factory)
: TensorAttribute(baseFileName, cfg, _denseTensorStore),
- _denseTensorStore(cfg.tensorType(), make_memory_allocator(getName(), cfg.paged())),
+ _denseTensorStore(cfg.tensorType(), get_memory_allocator()),
_index()
{
if (cfg.hnsw_index_params().has_value()) {
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
index ed3fb737b7d..6435ba6f27c 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.cpp
@@ -45,7 +45,7 @@ DenseTensorStore::TensorSizeCalc::TensorSizeCalc(const ValueType &type)
_aligned_size = my_align(buf_size, alignment);
}
-DenseTensorStore::BufferType::BufferType(const TensorSizeCalc &tensorSizeCalc, std::unique_ptr<vespalib::alloc::MemoryAllocator> allocator)
+DenseTensorStore::BufferType::BufferType(const TensorSizeCalc &tensorSizeCalc, std::shared_ptr<vespalib::alloc::MemoryAllocator> allocator)
: vespalib::datastore::BufferType<char>(tensorSizeCalc.alignedSize(), MIN_BUFFER_ARRAYS, RefType::offsetSize()),
_allocator(std::move(allocator))
{}
@@ -65,7 +65,7 @@ DenseTensorStore::BufferType::get_memory_allocator() const
return _allocator.get();
}
-DenseTensorStore::DenseTensorStore(const ValueType &type, std::unique_ptr<vespalib::alloc::MemoryAllocator> allocator)
+DenseTensorStore::DenseTensorStore(const ValueType &type, std::shared_ptr<vespalib::alloc::MemoryAllocator> allocator)
: TensorStore(_concreteStore),
_concreteStore(),
_tensorSizeCalc(type),
diff --git a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
index 47932fbff7e..7176edbcf08 100644
--- a/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
+++ b/searchlib/src/vespa/searchlib/tensor/dense_tensor_store.h
@@ -37,9 +37,9 @@ public:
class BufferType : public vespalib::datastore::BufferType<char>
{
using CleanContext = vespalib::datastore::BufferType<char>::CleanContext;
- std::unique_ptr<vespalib::alloc::MemoryAllocator> _allocator;
+ std::shared_ptr<vespalib::alloc::MemoryAllocator> _allocator;
public:
- BufferType(const TensorSizeCalc &tensorSizeCalc, std::unique_ptr<vespalib::alloc::MemoryAllocator> allocator);
+ BufferType(const TensorSizeCalc &tensorSizeCalc, std::shared_ptr<vespalib::alloc::MemoryAllocator> allocator);
~BufferType() override;
void cleanHold(void *buffer, size_t offset, ElemCount numElems, CleanContext cleanCtx) override;
const vespalib::alloc::MemoryAllocator* get_memory_allocator() const override;
@@ -55,7 +55,7 @@ private:
TensorStore::EntryRef
setDenseTensor(const TensorType &tensor);
public:
- DenseTensorStore(const ValueType &type, std::unique_ptr<vespalib::alloc::MemoryAllocator> allocator);
+ DenseTensorStore(const ValueType &type, std::shared_ptr<vespalib::alloc::MemoryAllocator> allocator);
~DenseTensorStore() override;
const ValueType &type() const { return _type; }