diff options
138 files changed, 988 insertions, 1654 deletions
diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java index 19dfd031dfc..fd887a4196b 100644 --- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java +++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/Reindexer.java @@ -49,10 +49,10 @@ public class Reindexer { private final ReindexingMetrics metrics; private final Clock clock; private final Phaser phaser = new Phaser(2); // Reindexer and visitor. + private final double windowSizeIncrement; - @Inject public Reindexer(Cluster cluster, Map<DocumentType, Instant> ready, ReindexingCurator database, - DocumentAccess access, Metric metric, Clock clock) { + DocumentAccess access, Metric metric, Clock clock, double windowSizeIncrement) { this(cluster, ready, database, @@ -65,11 +65,13 @@ public class Reindexer { } }, metric, - clock); + clock, + windowSizeIncrement); } Reindexer(Cluster cluster, Map<DocumentType, Instant> ready, ReindexingCurator database, - Function<VisitorParameters, Runnable> visitorSessions, Metric metric, Clock clock) { + Function<VisitorParameters, Runnable> visitorSessions, Metric metric, Clock clock, + double windowSizeIncrement) { for (DocumentType type : ready.keySet()) cluster.bucketSpaceOf(type); // Verifies this is known. @@ -79,6 +81,7 @@ public class Reindexer { this.visitorSessions = visitorSessions; this.metrics = new ReindexingMetrics(metric, cluster.name); this.clock = clock; + this.windowSizeIncrement = windowSizeIncrement; } /** Lets the reindexer abort any ongoing visit session, wait for it to complete normally, then exit. */ @@ -91,6 +94,9 @@ public class Reindexer { if (phaser.isTerminated()) throw new IllegalStateException("Already shut down"); + // Keep metrics in sync across cluster controller containers. + metrics.dump(database.readReindexing(cluster.name)); + try (Lock lock = database.lockReindexing(cluster.name())) { AtomicReference<Reindexing> reindexing = new AtomicReference<>(database.readReindexing(cluster.name())); reindexing.set(updateWithReady(ready, reindexing.get(), clock.instant())); @@ -191,7 +197,7 @@ public class Reindexer { VisitorParameters createParameters(DocumentType type, ProgressToken progress) { VisitorParameters parameters = new VisitorParameters(type.getName()); - parameters.setThrottlePolicy(new DynamicThrottlePolicy().setWindowSizeIncrement(0.2) + parameters.setThrottlePolicy(new DynamicThrottlePolicy().setWindowSizeIncrement(windowSizeIncrement) .setWindowSizeDecrementFactor(5) .setResizeRate(10) .setMinWindowSize(1)); diff --git a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java index 9a114eabbb5..8668ed037ef 100644 --- a/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java +++ b/clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java @@ -72,7 +72,8 @@ public class ReindexingMaintainer extends AbstractComponent { access.getDocumentTypeManager()), access, metric, - clock)) + clock, + reindexingConfig.windowSizeIncrement())) .collect(toUnmodifiableList()); this.executor = new ScheduledThreadPoolExecutor(reindexingConfig.clusters().size(), new DaemonThreadFactory("reindexer-")); if (reindexingConfig.enabled()) diff --git a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java index 7086c36af3f..9a88d8aad1f 100644 --- a/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java +++ b/clustercontroller-reindexer/src/test/java/ai/vespa/reindexing/ReindexerTest.java @@ -59,17 +59,12 @@ class ReindexerTest { @Test void throwsWhenUnknownBuckets() { assertThrows(NullPointerException.class, - () -> new Reindexer(new Cluster("cluster", "id", Map.of()), - Map.of(music, Instant.EPOCH), - database, - failIfCalled, - metric, - clock)); + () -> new Reindexer(new Cluster("cluster", "id", Map.of()), Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2)); } @Test void throwsWhenLockHeldElsewhere() throws InterruptedException, ExecutionException { - Reindexer reindexer = new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock); + Reindexer reindexer = new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2); Executors.newSingleThreadExecutor().submit(() -> database.lockReindexing("cluster")).get(); assertThrows(ReindexingLockException.class, reindexer::reindex); } @@ -77,13 +72,13 @@ class ReindexerTest { @Test @Timeout(10) void nothingToDoWithEmptyConfig() throws ReindexingLockException { - new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock).reindex(); + new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock, 0.2).reindex(); assertEquals(Map.of(), metric.metrics()); } @Test void testParameters() { - Reindexer reindexer = new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock); + Reindexer reindexer = new Reindexer(cluster, Map.of(), database, failIfCalled, metric, clock, 0.2); ProgressToken token = new ProgressToken(); VisitorParameters parameters = reindexer.createParameters(music, token); assertEquals("music:[document]", parameters.getFieldSet()); @@ -100,7 +95,7 @@ class ReindexerTest { void testReindexing() throws ReindexingLockException { // Reindexer is told to update "music" documents no earlier than EPOCH, which is just now. // Since "music" is a new document type, it is stored as just reindexed, and nothing else happens. - new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock).reindex(); + new Reindexer(cluster, Map.of(music, Instant.EPOCH), database, failIfCalled, metric, clock, 0.2).reindex(); Reindexing reindexing = Reindexing.empty().with(music, Status.ready(Instant.EPOCH).running().successful(Instant.EPOCH)); assertEquals(reindexing, database.readReindexing("cluster")); assertEquals(Map.of("reindexing.progress", Map.of(Map.of("documenttype", "music", @@ -124,7 +119,7 @@ class ReindexerTest { // New config tells reindexer to reindex "music" documents no earlier than at 10 millis after EPOCH, which isn't yet. // Nothing happens, since it's not yet time. This isn't supposed to happen unless high clock skew. clock.advance(Duration.ofMillis(5)); - new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, failIfCalled, metric, clock).reindex(); + new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, failIfCalled, metric, clock, 0.2).reindex(); assertEquals(reindexing, database.readReindexing("cluster")); // It's time to reindex the "music" documents — let this complete successfully. @@ -132,10 +127,10 @@ class ReindexerTest { AtomicBoolean shutDown = new AtomicBoolean(); Executor executor = Executors.newSingleThreadExecutor(); new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(10)), database, parameters -> { - database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. - executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.SUCCESS, "OK")); - return () -> shutDown.set(true); - }, metric, clock).reindex(); + database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. + executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.SUCCESS, "OK")); + return () -> shutDown.set(true); + }, metric, clock, 0.2).reindex(); reindexing = reindexing.with(music, Status.ready(clock.instant()).running().successful(clock.instant())); assertEquals(reindexing, database.readReindexing("cluster")); assertTrue(shutDown.get(), "Session was shut down"); @@ -146,14 +141,14 @@ class ReindexerTest { shutDown.set(false); AtomicReference<Reindexer> aborted = new AtomicReference<>(); aborted.set(new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(20)), database, parameters -> { - database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. - parameters.getControlHandler().onProgress(new ProgressToken()); - aborted.get().shutdown(); - return () -> { - shutDown.set(true); - parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.ABORTED, "Shut down"); - }; - }, metric, clock)); + database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. + parameters.getControlHandler().onProgress(new ProgressToken()); + aborted.get().shutdown(); + return () -> { + shutDown.set(true); + parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.ABORTED, "Shut down"); + }; + }, metric, clock, 0.2)); aborted.get().reindex(); reindexing = reindexing.with(music, Status.ready(clock.instant()).running().progressed(new ProgressToken()).halted()); assertEquals(reindexing, database.readReindexing("cluster")); @@ -168,16 +163,16 @@ class ReindexerTest { clock.advance(Duration.ofMillis(10)); shutDown.set(false); new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, parameters -> { - database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. - executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.FAILURE, "Error")); - return () -> shutDown.set(true); - }, metric, clock).reindex(); + database.writeReindexing(Reindexing.empty(), "cluster"); // Wipe database to verify we write data from reindexer. + executor.execute(() -> parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.FAILURE, "Error")); + return () -> shutDown.set(true); + }, metric, clock, 0.2).reindex(); reindexing = reindexing.with(music, Status.ready(clock.instant()).running().failed(clock.instant(), "Error")); assertEquals(reindexing, database.readReindexing("cluster")); assertTrue(shutDown.get(), "Session was shut down"); // Document type is ignored in next run, as it has failed fatally. - new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, failIfCalled, metric, clock).reindex(); + new Reindexer(cluster, Map.of(music, Instant.ofEpochMilli(30)), database, failIfCalled, metric, clock, 0.2).reindex(); assertEquals(reindexing, database.readReindexing("cluster")); } 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 3e0561a315a..381f0ace69e 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 @@ -65,9 +65,11 @@ public interface ModelContext { */ interface FeatureFlags { @ModelFeatureFlag(owners = {"bjorncs", "jonmv"}) default boolean enableAutomaticReindexing() { return false; } + @ModelFeatureFlag(owners = {"bjorncs", "jonmv"}) default double reindexerWindowSizeIncrement() { return 0.2; } @ModelFeatureFlag(owners = {"baldersheim"}, comment = "Revisit in May or June 2020") default double defaultTermwiseLimit() { throw new UnsupportedOperationException("TODO specify default value"); } @ModelFeatureFlag(owners = {"vekterli"}) default boolean useThreePhaseUpdates() { throw new UnsupportedOperationException("TODO specify default value"); } @ModelFeatureFlag(owners = {"geirst"}, comment = "Remove on 7.XXX when this is default on") default boolean useDirectStorageApiRpc() { throw new UnsupportedOperationException("TODO specify default value"); } + @ModelFeatureFlag(owners = {"geirst"}, comment = "Remove on 7.XXX when this is default on") default boolean useFastValueTensorImplementation() { throw new UnsupportedOperationException("TODO specify default value"); } @ModelFeatureFlag(owners = {"baldersheim"}, comment = "Select sequencer type use while feeding") default String feedSequencerType() { throw new UnsupportedOperationException("TODO specify default value"); } @ModelFeatureFlag(owners = {"baldersheim"}) default String responseSequencerType() { throw new UnsupportedOperationException("TODO specify default value"); } @ModelFeatureFlag(owners = {"baldersheim"}) default int defaultNumResponseThreads() { return 2; } @@ -125,6 +127,7 @@ public interface ModelContext { @Deprecated double feedConcurrency(); @Deprecated boolean useThreePhaseUpdates(); @Deprecated boolean useDirectStorageApiRpc(); + @Deprecated boolean useFastValueTensorImplementation(); @Deprecated default boolean useAccessControlTlsHandshakeClientAuth() { return false; } } 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 3a90c335c48..2b819b731a1 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 @@ -38,6 +38,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private boolean useDedicatedNodeForLogserver = false; private boolean useThreePhaseUpdates = false; private boolean useDirectStorageApiRpc = false; + private boolean useFastValueTensorImplementation = false; private double defaultTermwiseLimit = 1.0; private String jvmGCOptions = null; private String sequencerType = "LATENCY"; @@ -73,6 +74,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; } + @Override public boolean useFastValueTensorImplementation() { return useFastValueTensorImplementation; } @Override public Optional<AthenzDomain> athenzDomain() { return Optional.ofNullable(athenzDomain); } @Override public Optional<ApplicationRoles> applicationRoles() { return Optional.ofNullable(applicationRoles); } @Override public String responseSequencerType() { return responseSequencerType; } @@ -138,6 +140,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea return this; } + public TestProperties setUseFastValueTensorImplementation(boolean useFastValueTensorImplementation) { + this.useFastValueTensorImplementation = useFastValueTensorImplementation; + return this; + } + public TestProperties setApplicationId(ApplicationId applicationId) { this.applicationId = applicationId; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java index f8932b415b1..14fbeb17aaf 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java @@ -155,6 +155,7 @@ public class ClusterControllerContainer extends Container implements } builder.enabled(ctx.reindexing().enabled()); + builder.windowSizeIncrement(ctx.windowSizeIncrement()); for (String clusterId : ctx.clusterIds()) { ReindexingConfig.Clusters.Builder clusterBuilder = new ReindexingConfig.Clusters.Builder(); for (NewDocumentType type : ctx.documentTypesForCluster(clusterId)) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java index 63fc0b4515f..3fe6ce3ff27 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainerCluster.java @@ -35,7 +35,7 @@ public class ClusterControllerContainerCluster extends ContainerCluster<ClusterC Reindexing reindexing = deployState.featureFlags().enableAutomaticReindexing() ? deployState.reindexing().orElse(Reindexing.DISABLED_INSTANCE) : Reindexing.DISABLED_INSTANCE; - return new ReindexingContext(reindexing); + return new ReindexingContext(reindexing, deployState.featureFlags().reindexerWindowSizeIncrement()); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java index 712498f78cb..7380b950fb2 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ReindexingContext.java @@ -21,9 +21,11 @@ public class ReindexingContext { private final Object monitor = new Object(); private final Map<String, Set<NewDocumentType>> documentTypesPerCluster = new HashMap<>(); private final Reindexing reindexing; + private final double windowSizeIncrement; - public ReindexingContext(Reindexing reindexing) { + public ReindexingContext(Reindexing reindexing, double windowSizeIncrement) { this.reindexing = Objects.requireNonNull(reindexing); + this.windowSizeIncrement = windowSizeIncrement; } public void addDocumentType(String clusterId, NewDocumentType type) { @@ -46,4 +48,7 @@ public class ReindexingContext { } public Reindexing reindexing() { return reindexing; } + + public double windowSizeIncrement() { return windowSizeIncrement; } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java index 4b82ba92b0e..1998be3c262 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java @@ -220,6 +220,8 @@ public class VespaMetricSet { addMetric(metrics, "jdisc.http.filtering.response.handled", List.of("rate")); addMetric(metrics, "jdisc.http.filtering.response.unhandled", List.of("rate")); + addMetric(metrics, "jdisc.application.failed_component_graphs", List.of("rate")); + return metrics; } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java index b4ad8cb1267..bc1d138b6d5 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java @@ -267,7 +267,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot TransactionLogServer tls; Optional<Tuning> tuning = Optional.ofNullable(this.tuning); if (element == null) { - searchNode = SearchNode.create(parent, "" + node.getDistributionKey(), node.getDistributionKey(), spec, + searchNode = SearchNode.create(deployState.getProperties(), parent, "" + node.getDistributionKey(), node.getDistributionKey(), spec, clusterName, node, flushOnShutdown, tuning, resourceLimits, parentGroup.isHosted(), combined); searchNode.setHostResource(node.getHostResource()); searchNode.initService(deployState.getDeployLogger()); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java index 16302ddff49..9d3505e932f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java @@ -69,6 +69,7 @@ public class SearchNode extends AbstractService implements private AbstractService serviceLayerService; private final Optional<Tuning> tuning; private final Optional<ResourceLimits> resourceLimits; + private final boolean useFastValueTensorImplementation; /** Whether this search node is co-located with a container node on a hosted system */ private final boolean combined; @@ -99,31 +100,31 @@ public class SearchNode extends AbstractService implements @Override protected SearchNode doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element producerSpec) { - return new SearchNode(ancestor, name, contentNode.getDistributionKey(), nodeSpec, clusterName, contentNode, + return new SearchNode(deployState.getProperties(), ancestor, name, contentNode.getDistributionKey(), nodeSpec, clusterName, contentNode, flushOnShutdown, tuning, resourceLimits, deployState.isHosted(), combined); } } - public static SearchNode create(AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec, + public static SearchNode create(ModelContext.Properties props, AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec, String clusterName, AbstractService serviceLayerService, boolean flushOnShutdown, Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa, boolean combined) { - return new SearchNode(parent, name, distributionKey, nodeSpec, clusterName, serviceLayerService, + return new SearchNode(props, parent, name, distributionKey, nodeSpec, clusterName, serviceLayerService, flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined); } - private SearchNode(AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec, + private SearchNode(ModelContext.Properties props, AbstractConfigProducer parent, String name, int distributionKey, NodeSpec nodeSpec, String clusterName, AbstractService serviceLayerService, boolean flushOnShutdown, Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa, boolean combined) { - this(parent, name, nodeSpec, clusterName, flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined); + this(props, parent, name, nodeSpec, clusterName, flushOnShutdown, tuning, resourceLimits, isHostedVespa, combined); this.distributionKey = distributionKey; this.serviceLayerService = serviceLayerService; setPropertiesElastic(clusterName, distributionKey); } - private SearchNode(AbstractConfigProducer parent, String name, NodeSpec nodeSpec, String clusterName, + private SearchNode(ModelContext.Properties props, AbstractConfigProducer parent, String name, NodeSpec nodeSpec, String clusterName, boolean flushOnShutdown, Optional<Tuning> tuning, Optional<ResourceLimits> resourceLimits, boolean isHostedVespa, boolean combined) { super(parent, name); @@ -141,6 +142,7 @@ public class SearchNode extends AbstractService implements // Properties are set in DomSearchBuilder this.tuning = tuning; this.resourceLimits = resourceLimits; + this.useFastValueTensorImplementation = props.featureFlags().useFastValueTensorImplementation(); } private void setPropertiesElastic(String clusterName, int distributionKey) { @@ -295,6 +297,9 @@ public class SearchNode extends AbstractService implements tuning.ifPresent(t -> t.getConfig(builder)); resourceLimits.ifPresent(l -> l.getConfig(builder)); } + if (useFastValueTensorImplementation) { + builder.tensor_implementation(ProtonConfig.Tensor_implementation.FAST_VALUE); + } } @Override diff --git a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java index e270c81fe78..e4dabfaddae 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchNodeTest.java @@ -53,7 +53,7 @@ public class SearchNodeTest { private static SearchNode createSearchNode(MockRoot root, String name, int distributionKey, NodeSpec nodeSpec, boolean flushOnShutDown, boolean isHosted, boolean combined) { - return SearchNode.create(root, name, distributionKey, nodeSpec, "mycluster", null, flushOnShutDown, Optional.empty(), Optional.empty(), isHosted, combined); + return SearchNode.create(root.getDeployState().getProperties(), root, name, distributionKey, nodeSpec, "mycluster", null, flushOnShutDown, Optional.empty(), Optional.empty(), isHosted, combined); } private static SearchNode createSearchNode(MockRoot root) { diff --git a/configdefinitions/src/vespa/reindexing.def b/configdefinitions/src/vespa/reindexing.def index e020aec3f65..93dc767fed0 100644 --- a/configdefinitions/src/vespa/reindexing.def +++ b/configdefinitions/src/vespa/reindexing.def @@ -6,13 +6,16 @@ namespace=vespa.config.content.reindexing # Whether reindexing should run at all enabled bool default=false -# TODO jonmv: remove after 7.310 is gone +# TODO jonmv: remove after 7.324 is gone # The name of the content cluster to reindex documents from clusterName string default="" -# TODO jonmv: remove after 7.310 is gone +# TODO jonmv: remove after 7.324 is gone # Epoch millis after which latest reprocessing may begin, per document type status{}.readyAtMillis long # Epoch millis after which latest reprocessing may begin, per document type, per cluster clusters{}.documentTypes{}.readyAtMillis long + +# Window size increment used for the dynamic throttling policy of the reindexing visitor session +windowSizeIncrement double default=0.2 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 4a6fb4bd6bf..2d96c92bd88 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 @@ -149,9 +149,11 @@ public class ModelContextImpl implements ModelContext { public static class FeatureFlags implements ModelContext.FeatureFlags { private final boolean enableAutomaticReindexing; + private final double reindexerWindowSizeIncrement; private final double defaultTermwiseLimit; private final boolean useThreePhaseUpdates; private final boolean useDirectStorageApiRpc; + private final boolean useFastValueTensorImplementation; private final String feedSequencer; private final String responseSequencer; private final int numResponseThreads; @@ -166,26 +168,30 @@ public class ModelContextImpl implements ModelContext { public FeatureFlags(FlagSource source, ApplicationId appId) { this.enableAutomaticReindexing = flagValue(source, appId, Flags.ENABLE_AUTOMATIC_REINDEXING); - defaultTermwiseLimit = flagValue(source, appId, Flags.DEFAULT_TERM_WISE_LIMIT); - useThreePhaseUpdates = flagValue(source, appId, Flags.USE_THREE_PHASE_UPDATES); - useDirectStorageApiRpc = flagValue(source, appId, Flags.USE_DIRECT_STORAGE_API_RPC); - feedSequencer = flagValue(source, appId, Flags.FEED_SEQUENCER_TYPE); - responseSequencer = flagValue(source, appId, Flags.RESPONSE_SEQUENCER_TYPE); - numResponseThreads = flagValue(source, appId, Flags.RESPONSE_NUM_THREADS); - skipCommunicationManagerThread = flagValue(source, appId, Flags.SKIP_COMMUNICATIONMANAGER_THREAD); - skipMbusRequestThread = flagValue(source, appId, Flags.SKIP_MBUS_REQUEST_THREAD); - skipMbusReplyThread = flagValue(source, appId, Flags.SKIP_MBUS_REPLY_THREAD); + this.reindexerWindowSizeIncrement = flagValue(source, appId, Flags.REINDEXER_WINDOW_SIZE_INCREMENT); + this.defaultTermwiseLimit = flagValue(source, appId, Flags.DEFAULT_TERM_WISE_LIMIT); + this.useThreePhaseUpdates = flagValue(source, appId, Flags.USE_THREE_PHASE_UPDATES); + this.useDirectStorageApiRpc = flagValue(source, appId, Flags.USE_DIRECT_STORAGE_API_RPC); + this.useFastValueTensorImplementation = flagValue(source, appId, Flags.USE_FAST_VALUE_TENSOR_IMPLEMENTATION); + this.feedSequencer = flagValue(source, appId, Flags.FEED_SEQUENCER_TYPE); + this.responseSequencer = flagValue(source, appId, Flags.RESPONSE_SEQUENCER_TYPE); + this.numResponseThreads = flagValue(source, appId, Flags.RESPONSE_NUM_THREADS); + this.skipCommunicationManagerThread = flagValue(source, appId, Flags.SKIP_COMMUNICATIONMANAGER_THREAD); + this.skipMbusRequestThread = flagValue(source, appId, Flags.SKIP_MBUS_REQUEST_THREAD); + this.skipMbusReplyThread = flagValue(source, appId, Flags.SKIP_MBUS_REPLY_THREAD); this.useAccessControlTlsHandshakeClientAuth = flagValue(source, appId, Flags.USE_ACCESS_CONTROL_CLIENT_AUTHENTICATION); - useAsyncMessageHandlingOnSchedule = flagValue(source, appId, Flags.USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE); - contentNodeBucketDBStripeBits = flagValue(source, appId, Flags.CONTENT_NODE_BUCKET_DB_STRIPE_BITS); - mergeChunkSize = flagValue(source, appId, Flags.MERGE_CHUNK_SIZE); - feedConcurrency = flagValue(source, appId, Flags.FEED_CONCURRENCY); + this.useAsyncMessageHandlingOnSchedule = flagValue(source, appId, Flags.USE_ASYNC_MESSAGE_HANDLING_ON_SCHEDULE); + this.contentNodeBucketDBStripeBits = flagValue(source, appId, Flags.CONTENT_NODE_BUCKET_DB_STRIPE_BITS); + this.mergeChunkSize = flagValue(source, appId, Flags.MERGE_CHUNK_SIZE); + this.feedConcurrency = flagValue(source, appId, Flags.FEED_CONCURRENCY); } @Override public boolean enableAutomaticReindexing() { return enableAutomaticReindexing; } + @Override public double reindexerWindowSizeIncrement() { return reindexerWindowSizeIncrement; } @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; } + @Override public boolean useFastValueTensorImplementation() { return useFastValueTensorImplementation; } @Override public String feedSequencerType() { return feedSequencer; } @Override public String responseSequencerType() { return responseSequencer; } @Override public int defaultNumResponseThreads() { return numResponseThreads; } @@ -232,6 +238,7 @@ public class ModelContextImpl implements ModelContext { private final double defaultTermwiseLimit; private final boolean useThreePhaseUpdates; private final boolean useDirectStorageApiRpc; + private final boolean useFastValueTensorImplementation; private final String feedSequencer; private final String responseSequencer; private final int numResponseThreads; @@ -278,6 +285,7 @@ public class ModelContextImpl implements ModelContext { defaultTermwiseLimit = flagValue(flagSource, applicationId, Flags.DEFAULT_TERM_WISE_LIMIT); useThreePhaseUpdates = flagValue(flagSource, applicationId, Flags.USE_THREE_PHASE_UPDATES); useDirectStorageApiRpc = flagValue(flagSource, applicationId, Flags.USE_DIRECT_STORAGE_API_RPC); + useFastValueTensorImplementation = flagValue(flagSource, applicationId, Flags.USE_FAST_VALUE_TENSOR_IMPLEMENTATION); feedSequencer = flagValue(flagSource, applicationId, Flags.FEED_SEQUENCER_TYPE); responseSequencer = flagValue(flagSource, applicationId, Flags.RESPONSE_SEQUENCER_TYPE); numResponseThreads = flagValue(flagSource, applicationId, Flags.RESPONSE_NUM_THREADS); @@ -349,6 +357,7 @@ public class ModelContextImpl implements ModelContext { @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; } + @Override public boolean useFastValueTensorImplementation() { return useFastValueTensorImplementation; } @Override public String feedSequencerType() { return feedSequencer; } @Override public String responseSequencerType() { return responseSequencer; } @Override public int defaultNumResponseThreads() { return numResponseThreads; } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java index aa709b3bf37..7ccdf161f82 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ApplicationPackageMaintainer.java @@ -78,9 +78,9 @@ public class ApplicationPackageMaintainer extends ConfigServerMaintainer { } @Override - public void close() { + public void awaitShutdown() { connectionPool.close(); - super.close(); + super.awaitShutdown(); } private void createLocalSessionIfMissing(ApplicationId applicationId, long sessionId) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java index 21462bc4fec..837f025ec2b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/maintenance/ConfigServerMaintenance.java @@ -4,7 +4,7 @@ package com.yahoo.vespa.config.server.maintenance; import com.google.inject.Inject; import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.component.AbstractComponent; -import com.yahoo.jdisc.Metric; +import com.yahoo.concurrent.maintenance.Maintainer; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.ConfigServerBootstrap; import com.yahoo.vespa.config.server.application.ConfigConvergenceChecker; @@ -13,6 +13,8 @@ import com.yahoo.vespa.flags.FlagSource; import java.time.Clock; import java.time.Duration; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * Maintenance jobs of the config server. @@ -24,11 +26,7 @@ import java.time.Duration; */ public class ConfigServerMaintenance extends AbstractComponent { - private final TenantsMaintainer tenantsMaintainer; - private final FileDistributionMaintainer fileDistributionMaintainer; - private final SessionsMaintainer sessionsMaintainer; - private final ApplicationPackageMaintainer applicationPackageMaintainer; - private final ReindexingMaintainer reindexingMaintainer; + private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>(); @Inject public ConfigServerMaintenance(ConfigServerBootstrap configServerBootstrap, @@ -38,20 +36,17 @@ public class ConfigServerMaintenance extends AbstractComponent { FlagSource flagSource, ConfigConvergenceChecker convergence) { DefaultTimes defaults = new DefaultTimes(configserverConfig); - tenantsMaintainer = new TenantsMaintainer(applicationRepository, curator, flagSource, defaults.defaultInterval, Clock.systemUTC()); - fileDistributionMaintainer = new FileDistributionMaintainer(applicationRepository, curator, defaults.defaultInterval, flagSource); - sessionsMaintainer = new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource); - applicationPackageMaintainer = new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource); - reindexingMaintainer = new ReindexingMaintainer(applicationRepository, curator, flagSource, Duration.ofMinutes(3), convergence, Clock.systemUTC()); + maintainers.add(new TenantsMaintainer(applicationRepository, curator, flagSource, defaults.defaultInterval, Clock.systemUTC())); + maintainers.add(new FileDistributionMaintainer(applicationRepository, curator, defaults.defaultInterval, flagSource)); + maintainers.add(new SessionsMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource)); + maintainers.add(new ApplicationPackageMaintainer(applicationRepository, curator, Duration.ofSeconds(30), flagSource)); + maintainers.add(new ReindexingMaintainer(applicationRepository, curator, flagSource, Duration.ofMinutes(3), convergence, Clock.systemUTC())); } @Override public void deconstruct() { - fileDistributionMaintainer.close(); - sessionsMaintainer.close(); - applicationPackageMaintainer.close(); - tenantsMaintainer.close(); - reindexingMaintainer.close(); + maintainers.forEach(Maintainer::shutdown); + maintainers.forEach(Maintainer::awaitShutdown); } /* diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java index f32d7dfbb02..835326e0904 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java @@ -9,7 +9,6 @@ import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.concurrent.DaemonThreadFactory; import com.yahoo.config.ConfigInstance; import com.yahoo.config.subscription.ConfigInterruptedException; -import com.yahoo.config.subscription.ConfigSubscriber; import com.yahoo.container.Container; import com.yahoo.container.QrConfig; import com.yahoo.container.core.ChainsConfig; @@ -38,7 +37,6 @@ import com.yahoo.jrt.Supervisor; import com.yahoo.jrt.Transport; import com.yahoo.jrt.slobrok.api.Register; import com.yahoo.jrt.slobrok.api.SlobrokList; -import java.util.logging.Level; import com.yahoo.log.LogSetup; import com.yahoo.messagebus.network.rpc.SlobrokConfigSubscriber; import com.yahoo.net.HostName; @@ -271,11 +269,12 @@ public final class ConfiguredApplication implements Application { } catch (ConfigInterruptedException e) { break; } catch (Exception | LinkageError e) { // LinkageError: OSGi problems + tryReportFailedComponentGraphConstructionMetric(configurer, e); log.log(Level.SEVERE, "Reconfiguration failed, your application package must be fixed, unless this is a " + "JNI reload issue: " + Exceptions.toMessageString(e), e); } catch (Error e) { - com.yahoo.protect.Process.logAndDie("java.lang.Error on reconfiguration: We are probably in " + + com.yahoo.protect.Process.logAndDie("java.lang.Error on reconfiguration: We are probably in " + "a bad state and will terminate", e); } } @@ -284,6 +283,18 @@ public final class ConfiguredApplication implements Application { reconfigurerThread.start(); } + private static void tryReportFailedComponentGraphConstructionMetric(HandlersConfigurerDi configurer, Throwable error) { + try { + // We need the Metric instance from previous component graph to report metric values + // Metric may not be available if this is the initial component graph (since metric wiring is done through the config model) + Metric metric = configurer.getComponent(Metric.class); + Metric.Context metricContext = metric.createContext(Map.of("exception", error.getClass().getSimpleName())); + metric.add("jdisc.application.failed_component_graphs", 1L, metricContext); + } catch (Exception e) { + log.log(Level.WARNING, "Failed to report metric for failed component graph: " + e.getMessage(), e); + } + } + private static void installServerProviders(ContainerBuilder builder) { List<ServerProvider> serverProviders = Container.get().getServerProviderRegistry().allComponents(); for (ServerProvider server : serverProviders) { diff --git a/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js b/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js index 5531a2a4f69..762e0882ff4 100644 --- a/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js +++ b/container-search-gui/src/main/resources/gui/editarea/edit_area/plugins/autocompletion/autocompletion.js @@ -277,7 +277,7 @@ var EditArea_autocompletion= { nbMatch = 0;
for( i =0; i<limit ; i++ )
{
- if( line_string.substring( limit - i - 1, limit ) == content.substring( 0, i + 1 ) )
+ if( line_string.substring( limit - i - 1, limit ).toUpperCase() === content.substring( 0, i + 1 ).toUpperCase() )
nbMatch = i + 1;
}
// if characters match, we should include them in the selection that will be replaced
diff --git a/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js b/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js index 0a7dae862f3..545927a833a 100755 --- a/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js +++ b/container-search-gui/src/main/resources/gui/editarea/edit_area/reg_syntax/yql.js @@ -72,7 +72,7 @@ editAreaLoader.load_syntax["yql"] = { ,"CASE_SENSITIVE": false
,"MAX_TEXT_LENGTH": 50 // the maximum length of the text being analyzed before the cursor position
,"KEYWORDS": {
- '': [ // the prefix of thoses items
+ '': [ // the prefix of these items
/**
* 0 : the keyword the user is typing
* 1 : (optionnal) the string inserted in code ("{@}" being the new position of the cursor, "§" beeing the equivalent to the value the typed string indicated if the previous )
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java index 8f91a8127bd..57dafcd3291 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java @@ -12,6 +12,7 @@ import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagId; import com.yahoo.vespa.flags.json.DimensionHelper; import com.yahoo.vespa.flags.json.FlagData; +import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; import java.io.BufferedInputStream; import java.io.IOException; @@ -71,7 +72,7 @@ public class SystemFlagsDataArchive { if (!entry.isDirectory() && name.startsWith("flags/")) { Path filePath = Paths.get(name); String rawData = new String(zipIn.readAllBytes(), StandardCharsets.UTF_8); - addFile(builder, rawData, filePath); + addFile(builder, rawData, filePath, Set.of()); } } return builder.build(); @@ -80,7 +81,14 @@ public class SystemFlagsDataArchive { } } - public static SystemFlagsDataArchive fromDirectory(Path directory) { + public static SystemFlagsDataArchive fromDirectoryAndSystem(Path directory, ZoneRegistry systemDefinition) { + return fromDirectory(directory, systemDefinition); + } + + public static SystemFlagsDataArchive fromDirectory(Path directory) { return fromDirectory(directory, null); } + + private static SystemFlagsDataArchive fromDirectory(Path directory, ZoneRegistry systemDefinition) { + Set<String> filenamesForSystem = getFilenamesForSystem(systemDefinition); Path root = directory.toAbsolutePath(); Path flagsDirectory = directory.resolve("flags"); if (!Files.isDirectory(flagsDirectory)) { @@ -93,7 +101,7 @@ public class SystemFlagsDataArchive { if (!Files.isDirectory(absolutePath) && relativePath.startsWith("flags")) { String rawData = uncheck(() -> Files.readString(absolutePath, StandardCharsets.UTF_8)); - addFile(builder, rawData, relativePath); + addFile(builder, rawData, relativePath, filenamesForSystem); } }); return builder.build(); @@ -102,6 +110,7 @@ public class SystemFlagsDataArchive { } } + public void toZip(OutputStream out) { ZipOutputStream zipOut = new ZipOutputStream(out); files.forEach((flagId, fileMap) -> { @@ -152,11 +161,21 @@ public class SystemFlagsDataArchive { }); } - private static void addFile(Builder builder, String rawData, Path filePath) { + private static Set<String> getFilenamesForSystem(ZoneRegistry systemDefinition) { + if (systemDefinition == null) return Set.of(); + return FlagsTarget.getAllTargetsInSystem(systemDefinition).stream() + .flatMap(target -> target.flagDataFilesPrioritized().stream()) + .collect(Collectors.toSet()); + } + + private static void addFile(Builder builder, String rawData, Path filePath, Set<String> filenamesForSystem) { String filename = filePath.getFileName().toString(); if (filename.startsWith(".")) { return; // Ignore files starting with '.' } + if (!filenamesForSystem.isEmpty() && !filenamesForSystem.contains(filename)) { + return; // Ignore files irrelevant for system + } if (!filename.endsWith(".json")) { throw new IllegalArgumentException(String.format("Only JSON files are allowed in 'flags/' directory (found '%s')", filePath.toString())); } diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java index 771e42e85f9..d29657035c4 100644 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchiveTest.java @@ -2,16 +2,20 @@ package com.yahoo.vespa.hosted.controller.api.systemflags.v1; +import com.yahoo.config.provision.CloudName; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.zone.ZoneApi; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.config.provision.zone.ZoneList; import com.yahoo.text.JSON; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagId; import com.yahoo.vespa.flags.RawFlag; import com.yahoo.vespa.flags.json.FlagData; +import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -26,6 +30,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; @@ -35,6 +40,9 @@ import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * @author bjorncs @@ -52,6 +60,7 @@ public class SystemFlagsDataArchiveTest { public final ExpectedException expectedException = ExpectedException.none(); private static final FlagsTarget mainControllerTarget = FlagsTarget.forController(SYSTEM); + private static final FlagsTarget cdControllerTarget = FlagsTarget.forController(SystemName.cd); private static final FlagsTarget prodUsWestCfgTarget = createConfigserverTarget(Environment.prod, "us-west-1"); private static final FlagsTarget prodUsEast3CfgTarget = createConfigserverTarget(Environment.prod, "us-east-3"); private static final FlagsTarget devUsEast1CfgTarget = createConfigserverTarget(Environment.dev, "us-east-1"); @@ -260,6 +269,30 @@ public class SystemFlagsDataArchiveTest { } } + @Test + public void ignores_files_not_related_to_specified_system_definition() { + ZoneRegistry registry = createZoneRegistryMock(); + Path testDirectory = Paths.get("src/test/resources/system-flags-for-multiple-systems/"); + var archive = SystemFlagsDataArchive.fromDirectoryAndSystem(testDirectory, registry); + assertFlagDataHasValue(archive, MY_TEST_FLAG, cdControllerTarget, "default"); // Would be 'cd.controller' if files for CD system were included + assertFlagDataHasValue(archive, MY_TEST_FLAG, mainControllerTarget, "default"); + assertFlagDataHasValue(archive, MY_TEST_FLAG, prodUsWestCfgTarget, "main.prod.us-west-1"); + } + + @SuppressWarnings("unchecked") // workaround for mocking a method for generic return type + private static ZoneRegistry createZoneRegistryMock() { + // Cannot use the standard registry mock as it's located in controller-server module + ZoneRegistry registryMock = mock(ZoneRegistry.class); + when(registryMock.system()).thenReturn(SystemName.main); + when(registryMock.getConfigServerVipUri(any())).thenReturn(URI.create("http://localhost:8080/")); + when(registryMock.getConfigServerHttpsIdentity(any())).thenReturn(new AthenzService("domain", "servicename")); + ZoneList zoneListMock = mock(ZoneList.class); + when(zoneListMock.reachable()).thenReturn(zoneListMock); + when(zoneListMock.zones()).thenReturn((List)List.of(new SimpleZone("prod.us-west-1"), new SimpleZone("prod.us-east-3"))); + when(registryMock.zones()).thenReturn(zoneListMock); + return registryMock; + } + private static void assertArchiveReturnsCorrectTestFlagDataForTarget(SystemFlagsDataArchive archive) { assertFlagDataHasValue(archive, MY_TEST_FLAG, mainControllerTarget, "main.controller"); assertFlagDataHasValue(archive, MY_TEST_FLAG, prodUsWestCfgTarget, "main.prod.us-west-1"); @@ -286,4 +319,14 @@ public class SystemFlagsDataArchiveTest { .collect(toList()); } + private static class SimpleZone implements ZoneApi { + final ZoneId zoneId; + SimpleZone(String zoneId) { this.zoneId = ZoneId.from(zoneId); } + + @Override public SystemName getSystemName() { return SystemName.main; } + @Override public ZoneId getId() { return zoneId; } + @Override public CloudName getCloudName() { throw new UnsupportedOperationException(); } + @Override public String getCloudNativeRegionName() { throw new UnsupportedOperationException(); } + } + }
\ No newline at end of file diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json new file mode 100644 index 00000000000..ce3cdd43889 --- /dev/null +++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/cd.controller.json @@ -0,0 +1,8 @@ +{ + "id" : "my-test-flag", + "rules" : [ + { + "value" : "cd.controller" + } + ] +}
\ No newline at end of file diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json new file mode 100644 index 00000000000..5924eb860c0 --- /dev/null +++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/default.json @@ -0,0 +1,8 @@ +{ + "id" : "my-test-flag", + "rules" : [ + { + "value" : "default" + } + ] +}
\ No newline at end of file diff --git a/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json new file mode 100644 index 00000000000..45989773df8 --- /dev/null +++ b/controller-api/src/test/resources/system-flags-for-multiple-systems/flags/my-test-flag/main.prod.us-west-1.json @@ -0,0 +1,8 @@ +{ + "id" : "my-test-flag", + "rules" : [ + { + "value" : "main.prod.us-west-1" + } + ] +}
\ No newline at end of file diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 1dd84cfc7b4..ff2a1963967 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; +import com.yahoo.concurrent.maintenance.Maintainer; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.zone.ZoneApi; import com.yahoo.jdisc.Metric; @@ -13,6 +14,7 @@ import java.time.temporal.TemporalUnit; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; import static java.time.temporal.ChronoUnit.HOURS; @@ -28,89 +30,47 @@ import static java.time.temporal.ChronoUnit.SECONDS; */ public class ControllerMaintenance extends AbstractComponent { - private final DeploymentExpirer deploymentExpirer; - private final DeploymentIssueReporter deploymentIssueReporter; - private final MetricsReporter metricsReporter; - private final OutstandingChangeDeployer outstandingChangeDeployer; - private final VersionStatusUpdater versionStatusUpdater; private final Upgrader upgrader; - private final ReadyJobsTrigger readyJobsTrigger; - private final DeploymentMetricsMaintainer deploymentMetricsMaintainer; - private final ApplicationOwnershipConfirmer applicationOwnershipConfirmer; - private final SystemUpgrader systemUpgrader; - private final List<OsUpgrader> osUpgraders; - private final OsVersionStatusUpdater osVersionStatusUpdater; - private final JobRunner jobRunner; - private final ContactInformationMaintainer contactInformationMaintainer; - private final CostReportMaintainer costReportMaintainer; - private final ResourceMeterMaintainer resourceMeterMaintainer; - private final NameServiceDispatcher nameServiceDispatcher; - private final CloudEventReporter cloudEventReporter; - private final RotationStatusUpdater rotationStatusUpdater; - private final ResourceTagMaintainer resourceTagMaintainer; - private final SystemRoutingPolicyMaintainer systemRoutingPolicyMaintainer; - private final ApplicationMetaDataGarbageCollector applicationMetaDataGarbageCollector; - private final ContainerImageExpirer containerImageExpirer; - private final HostSwitchUpdater hostSwitchUpdater; + private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>(); @Inject @SuppressWarnings("unused") // instantiated by Dependency Injection public ControllerMaintenance(Controller controller, Metric metric) { Intervals intervals = new Intervals(controller.system()); - deploymentExpirer = new DeploymentExpirer(controller, intervals.defaultInterval); - deploymentIssueReporter = new DeploymentIssueReporter(controller, controller.serviceRegistry().deploymentIssues(), intervals.defaultInterval); - metricsReporter = new MetricsReporter(controller, metric); - outstandingChangeDeployer = new OutstandingChangeDeployer(controller, intervals.outstandingChangeDeployer); - versionStatusUpdater = new VersionStatusUpdater(controller, intervals.versionStatusUpdater); upgrader = new Upgrader(controller, intervals.defaultInterval); - readyJobsTrigger = new ReadyJobsTrigger(controller, intervals.readyJobsTrigger); - deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, intervals.deploymentMetricsMaintainer); - applicationOwnershipConfirmer = new ApplicationOwnershipConfirmer(controller, intervals.applicationOwnershipConfirmer, controller.serviceRegistry().ownershipIssues()); - systemUpgrader = new SystemUpgrader(controller, intervals.systemUpgrader); - jobRunner = new JobRunner(controller, intervals.jobRunner); - osUpgraders = osUpgraders(controller, intervals.osUpgrader); - osVersionStatusUpdater = new OsVersionStatusUpdater(controller, intervals.defaultInterval); - contactInformationMaintainer = new ContactInformationMaintainer(controller, intervals.contactInformationMaintainer); - nameServiceDispatcher = new NameServiceDispatcher(controller, intervals.nameServiceDispatcher); - costReportMaintainer = new CostReportMaintainer(controller, intervals.costReportMaintainer, controller.serviceRegistry().costReportConsumer()); - resourceMeterMaintainer = new ResourceMeterMaintainer(controller, intervals.resourceMeterMaintainer, metric, controller.serviceRegistry().meteringService()); - cloudEventReporter = new CloudEventReporter(controller, intervals.cloudEventReporter, metric); - rotationStatusUpdater = new RotationStatusUpdater(controller, intervals.defaultInterval); - resourceTagMaintainer = new ResourceTagMaintainer(controller, intervals.resourceTagMaintainer, controller.serviceRegistry().resourceTagger()); - systemRoutingPolicyMaintainer = new SystemRoutingPolicyMaintainer(controller, intervals.systemRoutingPolicyMaintainer); - applicationMetaDataGarbageCollector = new ApplicationMetaDataGarbageCollector(controller, intervals.applicationMetaDataGarbageCollector); - containerImageExpirer = new ContainerImageExpirer(controller, intervals.containerImageExpirer); - hostSwitchUpdater = new HostSwitchUpdater(controller, intervals.hostSwitchUpdater); + maintainers.add(upgrader); + maintainers.addAll(osUpgraders(controller, intervals.osUpgrader)); + maintainers.add(new DeploymentExpirer(controller, intervals.defaultInterval)); + maintainers.add(new DeploymentIssueReporter(controller, controller.serviceRegistry().deploymentIssues(), intervals.defaultInterval)); + maintainers.add(new MetricsReporter(controller, metric)); + maintainers.add(new OutstandingChangeDeployer(controller, intervals.outstandingChangeDeployer)); + maintainers.add(new VersionStatusUpdater(controller, intervals.versionStatusUpdater)); + maintainers.add(new ReadyJobsTrigger(controller, intervals.readyJobsTrigger)); + maintainers.add(new DeploymentMetricsMaintainer(controller, intervals.deploymentMetricsMaintainer)); + maintainers.add(new ApplicationOwnershipConfirmer(controller, intervals.applicationOwnershipConfirmer, controller.serviceRegistry().ownershipIssues())); + maintainers.add(new SystemUpgrader(controller, intervals.systemUpgrader)); + maintainers.add(new JobRunner(controller, intervals.jobRunner)); + maintainers.add(new OsVersionStatusUpdater(controller, intervals.defaultInterval)); + maintainers.add(new ContactInformationMaintainer(controller, intervals.contactInformationMaintainer)); + maintainers.add(new NameServiceDispatcher(controller, intervals.nameServiceDispatcher)); + maintainers.add(new CostReportMaintainer(controller, intervals.costReportMaintainer, controller.serviceRegistry().costReportConsumer())); + maintainers.add(new ResourceMeterMaintainer(controller, intervals.resourceMeterMaintainer, metric, controller.serviceRegistry().meteringService())); + maintainers.add(new CloudEventReporter(controller, intervals.cloudEventReporter, metric)); + maintainers.add(new RotationStatusUpdater(controller, intervals.defaultInterval)); + maintainers.add(new ResourceTagMaintainer(controller, intervals.resourceTagMaintainer, controller.serviceRegistry().resourceTagger())); + maintainers.add(new SystemRoutingPolicyMaintainer(controller, intervals.systemRoutingPolicyMaintainer)); + maintainers.add(new ApplicationMetaDataGarbageCollector(controller, intervals.applicationMetaDataGarbageCollector)); + maintainers.add(new ContainerImageExpirer(controller, intervals.containerImageExpirer)); + maintainers.add(new HostSwitchUpdater(controller, intervals.hostSwitchUpdater)); + maintainers.add(new ReindexingTriggerer(controller, intervals.reindexingTriggerer)); } public Upgrader upgrader() { return upgrader; } @Override public void deconstruct() { - deploymentExpirer.close(); - deploymentIssueReporter.close(); - metricsReporter.close(); - outstandingChangeDeployer.close(); - versionStatusUpdater.close(); - upgrader.close(); - readyJobsTrigger.close(); - deploymentMetricsMaintainer.close(); - applicationOwnershipConfirmer.close(); - systemUpgrader.close(); - osUpgraders.forEach(ControllerMaintainer::close); - osVersionStatusUpdater.close(); - jobRunner.close(); - contactInformationMaintainer.close(); - costReportMaintainer.close(); - resourceMeterMaintainer.close(); - nameServiceDispatcher.close(); - cloudEventReporter.close(); - rotationStatusUpdater.close(); - resourceTagMaintainer.close(); - systemRoutingPolicyMaintainer.close(); - applicationMetaDataGarbageCollector.close(); - containerImageExpirer.close(); - hostSwitchUpdater.close(); + maintainers.forEach(Maintainer::shutdown); + maintainers.forEach(Maintainer::awaitShutdown); } /** Create one OS upgrader per cloud found in the zone registry of controller */ @@ -148,6 +108,7 @@ public class ControllerMaintenance extends AbstractComponent { private final Duration applicationMetaDataGarbageCollector; private final Duration containerImageExpirer; private final Duration hostSwitchUpdater; + private final Duration reindexingTriggerer; public Intervals(SystemName system) { this.system = Objects.requireNonNull(system); @@ -170,6 +131,7 @@ public class ControllerMaintenance extends AbstractComponent { this.applicationMetaDataGarbageCollector = duration(12, HOURS); this.containerImageExpirer = duration(2, HOURS); this.hostSwitchUpdater = duration(12, HOURS); + this.reindexingTriggerer = duration(1, HOURS); } private Duration duration(long amount, TemporalUnit unit) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java index f08a23ab8ed..d6739581c79 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java @@ -56,9 +56,14 @@ public class JobRunner extends ControllerMaintainer { } @Override - public void close() { - super.close(); + public void shutdown() { + super.shutdown(); executors.shutdown(); + } + + @Override + public void awaitShutdown() { + super.awaitShutdown(); try { if ( ! executors.awaitTermination(10, TimeUnit.SECONDS)) { executors.shutdownNow(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java new file mode 100644 index 00000000000..96e9f087a67 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggerer.java @@ -0,0 +1,79 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.maintenance; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing; +import com.yahoo.vespa.hosted.controller.application.Deployment; +import com.yahoo.yolean.Exceptions; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Periodically triggers reindexing for all hosted Vespa applications. + * + * Since reindexing is meant to be a background effort, exactly when things are triggered is not critical, + * and a hash of id of each deployment is used to spread triggering out across the reindexing period. + * Only deployments within a window of opportunity of two maintainer periods are considered in each run. + * Reindexing is triggered for a deployment if it was last triggered more than half a period ago, and + * if no reindexing is currently ongoing. This means an application may skip reindexing during a period + * if it happens to reindex, e.g., a particular document type in its window of opportunity. This is fine. + * + * @author jonmv + */ +public class ReindexingTriggerer extends ControllerMaintainer { + + static final Duration reindexingPeriod = Duration.ofDays(91); // 13 weeks — four times a year. + + private static final Logger log = Logger.getLogger(ReindexingTriggerer.class.getName()); + + public ReindexingTriggerer(Controller controller, Duration duration) { + super(controller, duration); + } + + @Override + protected boolean maintain() { + try { + Instant now = controller().clock().instant(); + for (Application application : controller().applications().asList()) + application.productionDeployments().forEach((name, deployments) -> { + ApplicationId id = application.id().instance(name); + for (Deployment deployment : deployments) + if ( inWindowOfOpportunity(now, interval(), id, deployment.zone()) + && reindexingIsReady(controller().applications().applicationReindexing(id, deployment.zone()), now)) + controller().applications().reindex(id, deployment.zone(), List.of(), List.of()); + }); + return true; + } + catch (RuntimeException e) { + log.log(Level.WARNING, "Failed to trigger reindexing: " + Exceptions.toMessageString(e)); + return false; + } + } + + static boolean inWindowOfOpportunity(Instant now, Duration interval, ApplicationId id, ZoneId zone) { + long lastPeriodStartMillis = now.toEpochMilli() - (now.toEpochMilli() % reindexingPeriod.toMillis()); + Instant windowCenter = Instant.ofEpochMilli(lastPeriodStartMillis).plus(offset(id, zone)); + return windowCenter.minus(interval).isBefore(now) && now.isBefore(windowCenter.plus(interval)); + } + + static Duration offset(ApplicationId id, ZoneId zone) { + double relativeOffset = ((id.serializedForm() + zone.value()).hashCode() & (-1 >>> 1)) / (double) (-1 >>> 1); + return Duration.ofMillis((long) (reindexingPeriod.toMillis() * relativeOffset)); + } + + static boolean reindexingIsReady(ApplicationReindexing reindexing, Instant now) { + if (reindexing.clusters().values().stream().flatMap(cluster -> cluster.ready().values().stream()) + .anyMatch(status -> status.startedAt().isPresent() && status.endedAt().isEmpty())) + return false; + + return reindexing.common().readyAt().orElse(Instant.EPOCH).isBefore(now.minus(reindexingPeriod.dividedBy(2))); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java new file mode 100644 index 00000000000..c12b82524e4 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ReindexingTriggererTest.java @@ -0,0 +1,78 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.maintenance; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing.Cluster; +import com.yahoo.vespa.hosted.controller.api.integration.configserver.ApplicationReindexing.Status; +import org.junit.Test; + +import java.time.Duration; +import java.time.Instant; +import java.util.Map; + +import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.inWindowOfOpportunity; +import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.reindexingIsReady; +import static com.yahoo.vespa.hosted.controller.maintenance.ReindexingTriggerer.reindexingPeriod; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ReindexingTriggererTest { + + @Test + public void testWindowOfOpportunity() { + Duration interval = Duration.ofHours(1); + Instant now = Instant.now(); + Instant doom = now.plus(ReindexingTriggerer.reindexingPeriod); + int triggered = 0; + while (now.isBefore(doom)) { + if (inWindowOfOpportunity(now, interval, ApplicationId.defaultId(), ZoneId.defaultId())) + triggered++; + now = now.plus(interval); + } + assertEquals("Should be in window of opportunity exactly twice each period", 2, triggered); + } + + @Test + public void testReindexingIsReady() { + Instant then = Instant.now(); + ApplicationReindexing reindexing = new ApplicationReindexing(true, + new Status(then), + Map.of()); + + Instant now = then; + assertFalse("Should not be ready less than one half-period after last triggering", + reindexingIsReady(reindexing, now)); + + now = now.plus(reindexingPeriod.dividedBy(2)); + assertFalse("Should not be ready one half-period after last triggering", + reindexingIsReady(reindexing, now)); + + now = now.plusMillis(1); + assertTrue("Should be ready more than one half-period after last triggering", + reindexingIsReady(reindexing, now)); + + reindexing = new ApplicationReindexing(true, + new Status(then), + Map.of("cluster", + new Cluster(new Status(then), + Map.of(), + Map.of("type", + new Status(then, then, null, null, null, null))))); + assertFalse("Should not be ready when reindexing is already running", + reindexingIsReady(reindexing, now)); + + reindexing = new ApplicationReindexing(true, + new Status(then), + Map.of("cluster", + new Cluster(new Status(then), + Map.of("type", 123L), + Map.of("type", + new Status(then, then, now, null, null, null))))); + assertTrue("Should be ready when reindexing is no longer running", + reindexingIsReady(reindexing, now)); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index b6b45bd76e0..5af91e17bb7 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -52,6 +52,9 @@ "name": "ReadyJobsTrigger" }, { + "name": "ReindexingTriggerer" + }, + { "name": "ResourceMeterMaintainer" }, { diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt index 36796faa2fe..c2dd847e715 100644 --- a/eval/CMakeLists.txt +++ b/eval/CMakeLists.txt @@ -36,6 +36,7 @@ vespa_define_module( src/tests/eval/value_cache src/tests/eval/value_codec src/tests/eval/value_type + src/tests/eval/typed_cells src/tests/gp/ponder_nov2017 src/tests/instruction/dense_xw_product_function src/tests/instruction/generic_concat @@ -53,22 +54,21 @@ vespa_define_module( src/tests/instruction/dense_tensor_peek_function src/tests/instruction/index_lookup_table src/tests/instruction/join_with_number + src/tests/instruction/dense_add_dimension_optimizer + src/tests/instruction/dense_fast_rename_optimizer + src/tests/instruction/dense_inplace_join_function + src/tests/instruction/dense_pow_as_map_optimizer + src/tests/instruction/dense_remove_dimension_optimizer + src/tests/instruction/dense_replace_type_function + src/tests/instruction/dense_simple_join_function + src/tests/instruction/dense_simple_map_function + src/tests/instruction/dense_single_reduce_function + src/tests/instruction/dense_tensor_create_function + src/tests/instruction/vector_from_doubles_function src/tests/streamed/value - src/tests/tensor/dense_add_dimension_optimizer - src/tests/tensor/dense_fast_rename_optimizer - src/tests/tensor/dense_inplace_join_function - src/tests/tensor/dense_pow_as_map_optimizer - src/tests/tensor/dense_remove_dimension_optimizer - src/tests/tensor/dense_replace_type_function - src/tests/tensor/dense_simple_join_function - src/tests/tensor/dense_simple_map_function - src/tests/tensor/dense_single_reduce_function - src/tests/tensor/dense_tensor_create_function src/tests/tensor/instruction_benchmark src/tests/tensor/onnx_wrapper src/tests/tensor/tensor_conformance - src/tests/tensor/typed_cells - src/tests/tensor/vector_from_doubles_function LIBS src/vespa/eval diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp index 73a3648a34c..7094686e399 100644 --- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp +++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp @@ -4,10 +4,10 @@ #include <vespa/eval/eval/tensor_function.h> #include <vespa/eval/eval/simple_value.h> #include <vespa/eval/eval/fast_value.h> -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> #include <vespa/eval/instruction/dense_cell_range_function.h> #include <vespa/eval/instruction/dense_lambda_peek_function.h> -#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> #include <vespa/eval/eval/tensor_nodes.h> @@ -62,7 +62,7 @@ void verify_generic(const vespalib::string &expr, const vespalib::string &expect } void verify_reshape(const vespalib::string &expr, const vespalib::string &expect) { - verify_impl<tensor::DenseReplaceTypeFunction>(expr, expect); + verify_impl<DenseReplaceTypeFunction>(expr, expect); } void verify_range(const vespalib::string &expr, const vespalib::string &expect) { diff --git a/eval/src/tests/tensor/typed_cells/CMakeLists.txt b/eval/src/tests/eval/typed_cells/CMakeLists.txt index d57ff33eda6..d57ff33eda6 100644 --- a/eval/src/tests/tensor/typed_cells/CMakeLists.txt +++ b/eval/src/tests/eval/typed_cells/CMakeLists.txt diff --git a/eval/src/tests/tensor/typed_cells/typed_cells_test.cpp b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp index ccb522fd496..ccb522fd496 100644 --- a/eval/src/tests/tensor/typed_cells/typed_cells_test.cpp +++ b/eval/src/tests/eval/typed_cells/typed_cells_test.cpp diff --git a/eval/src/tests/tensor/dense_add_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt index 1bc9f93b1a2..1bc9f93b1a2 100644 --- a/eval/src/tests/tensor/dense_add_dimension_optimizer/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_add_dimension_optimizer/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp b/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp index 0e8e50daae5..e7660ce8933 100644 --- a/eval/src/tests/tensor/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp +++ b/eval/src/tests/instruction/dense_add_dimension_optimizer/dense_add_dimension_optimizer_test.cpp @@ -3,8 +3,8 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/fast_value.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> -#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -14,7 +14,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_fast_rename_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt index 32cf6c45d1e..32cf6c45d1e 100644 --- a/eval/src/tests/tensor/dense_fast_rename_optimizer/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_fast_rename_optimizer/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp b/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp index 52afde0e92c..043c8814c72 100644 --- a/eval/src/tests/tensor/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp +++ b/eval/src/tests/instruction/dense_fast_rename_optimizer/dense_fast_rename_optimizer_test.cpp @@ -2,8 +2,8 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> -#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -13,7 +13,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_inplace_join_function/CMakeLists.txt b/eval/src/tests/instruction/dense_inplace_join_function/CMakeLists.txt index 2808675bc78..2808675bc78 100644 --- a/eval/src/tests/tensor/dense_inplace_join_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_inplace_join_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_inplace_join_function/dense_inplace_join_function_test.cpp b/eval/src/tests/instruction/dense_inplace_join_function/dense_inplace_join_function_test.cpp index 853607ae76d..68aa72428b9 100644 --- a/eval/src/tests/tensor/dense_inplace_join_function/dense_inplace_join_function_test.cpp +++ b/eval/src/tests/instruction/dense_inplace_join_function/dense_inplace_join_function_test.cpp @@ -11,7 +11,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_pow_as_map_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_pow_as_map_optimizer/CMakeLists.txt index d6ce9f1924c..d6ce9f1924c 100644 --- a/eval/src/tests/tensor/dense_pow_as_map_optimizer/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_pow_as_map_optimizer/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp b/eval/src/tests/instruction/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp index d00744bcfaf..67567b4e289 100644 --- a/eval/src/tests/tensor/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp +++ b/eval/src/tests/instruction/dense_pow_as_map_optimizer/dense_pow_as_map_optimizer_test.cpp @@ -2,7 +2,7 @@ #include <vespa/eval/eval/fast_value.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_simple_map_function.h> +#include <vespa/eval/instruction/dense_simple_map_function.h> #include <vespa/eval/eval/test/eval_fixture.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/vespalib/gtest/gtest.h> @@ -11,7 +11,6 @@ using namespace vespalib::eval::operation; using namespace vespalib::eval::tensor_function; using namespace vespalib::eval::test; using namespace vespalib::eval; -using namespace vespalib::tensor; //using namespace vespalib; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_remove_dimension_optimizer/CMakeLists.txt b/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt index c945bd31609..c945bd31609 100644 --- a/eval/src/tests/tensor/dense_remove_dimension_optimizer/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_remove_dimension_optimizer/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp b/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp index 69910e27b4b..4c3c86be7f8 100644 --- a/eval/src/tests/tensor/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp +++ b/eval/src/tests/instruction/dense_remove_dimension_optimizer/dense_remove_dimension_optimizer_test.cpp @@ -2,8 +2,8 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> -#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -13,7 +13,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_replace_type_function/CMakeLists.txt b/eval/src/tests/instruction/dense_replace_type_function/CMakeLists.txt index dd4a8a58082..dd4a8a58082 100644 --- a/eval/src/tests/tensor/dense_replace_type_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_replace_type_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp index 2612869e72f..6b8e6faecf4 100644 --- a/eval/src/tests/tensor/dense_replace_type_function/dense_replace_type_function_test.cpp +++ b/eval/src/tests/instruction/dense_replace_type_function/dense_replace_type_function_test.cpp @@ -4,18 +4,17 @@ #include <vespa/eval/eval/fast_value.h> #include <vespa/eval/eval/value_codec.h> #include <vespa/eval/eval/interpreted_function.h> -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> #include <vespa/eval/eval/test/tensor_model.hpp> using namespace vespalib::eval::tensor_function; using namespace vespalib::eval::test; using namespace vespalib::eval; -using namespace vespalib::tensor; using namespace vespalib; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); -TypedCells getCellsRef(const eval::Value &value) { +TypedCells getCellsRef(const Value &value) { return value.cells(); } diff --git a/eval/src/tests/tensor/dense_simple_join_function/CMakeLists.txt b/eval/src/tests/instruction/dense_simple_join_function/CMakeLists.txt index 8a2df392145..8a2df392145 100644 --- a/eval/src/tests/tensor/dense_simple_join_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_simple_join_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_simple_join_function/dense_simple_join_function_test.cpp b/eval/src/tests/instruction/dense_simple_join_function/dense_simple_join_function_test.cpp index 6ad60d2e3f5..2186d49385e 100644 --- a/eval/src/tests/tensor/dense_simple_join_function/dense_simple_join_function_test.cpp +++ b/eval/src/tests/instruction/dense_simple_join_function/dense_simple_join_function_test.cpp @@ -2,7 +2,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_simple_join_function.h> +#include <vespa/eval/instruction/dense_simple_join_function.h> #include <vespa/eval/eval/test/eval_fixture.h> #include <vespa/eval/eval/test/tensor_model.hpp> @@ -11,7 +11,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; using vespalib::make_string_short::fmt; @@ -19,7 +18,7 @@ using vespalib::make_string_short::fmt; using Primary = DenseSimpleJoinFunction::Primary; using Overlap = DenseSimpleJoinFunction::Overlap; -namespace vespalib::tensor { +namespace vespalib::eval { std::ostream &operator<<(std::ostream &os, Primary primary) { diff --git a/eval/src/tests/tensor/dense_simple_map_function/CMakeLists.txt b/eval/src/tests/instruction/dense_simple_map_function/CMakeLists.txt index 8d3bb8c92aa..8d3bb8c92aa 100644 --- a/eval/src/tests/tensor/dense_simple_map_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_simple_map_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_simple_map_function/dense_simple_map_function_test.cpp b/eval/src/tests/instruction/dense_simple_map_function/dense_simple_map_function_test.cpp index 53164ad59c8..13a24c13a2e 100644 --- a/eval/src/tests/tensor/dense_simple_map_function/dense_simple_map_function_test.cpp +++ b/eval/src/tests/instruction/dense_simple_map_function/dense_simple_map_function_test.cpp @@ -1,7 +1,7 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_simple_map_function.h> +#include <vespa/eval/instruction/dense_simple_map_function.h> #include <vespa/eval/eval/test/eval_fixture.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/vespalib/gtest/gtest.h> @@ -10,7 +10,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; using namespace vespalib::eval::tensor_function; -using namespace vespalib::tensor; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_single_reduce_function/CMakeLists.txt b/eval/src/tests/instruction/dense_single_reduce_function/CMakeLists.txt index 42b00699c31..42b00699c31 100644 --- a/eval/src/tests/tensor/dense_single_reduce_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_single_reduce_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_single_reduce_function/dense_single_reduce_function_test.cpp b/eval/src/tests/instruction/dense_single_reduce_function/dense_single_reduce_function_test.cpp index 347228269cf..c6da0b94de3 100644 --- a/eval/src/tests/tensor/dense_single_reduce_function/dense_single_reduce_function_test.cpp +++ b/eval/src/tests/instruction/dense_single_reduce_function/dense_single_reduce_function_test.cpp @@ -3,7 +3,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> #include <vespa/eval/eval/operation.h> -#include <vespa/eval/tensor/dense/dense_single_reduce_function.h> +#include <vespa/eval/instruction/dense_single_reduce_function.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -13,7 +13,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_tensor_create_function/CMakeLists.txt b/eval/src/tests/instruction/dense_tensor_create_function/CMakeLists.txt index 883f331bda8..883f331bda8 100644 --- a/eval/src/tests/tensor/dense_tensor_create_function/CMakeLists.txt +++ b/eval/src/tests/instruction/dense_tensor_create_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/dense_tensor_create_function/dense_tensor_create_function_test.cpp b/eval/src/tests/instruction/dense_tensor_create_function/dense_tensor_create_function_test.cpp index edf999e97b3..25bbe5b422c 100644 --- a/eval/src/tests/tensor/dense_tensor_create_function/dense_tensor_create_function_test.cpp +++ b/eval/src/tests/instruction/dense_tensor_create_function/dense_tensor_create_function_test.cpp @@ -2,7 +2,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/dense_tensor_create_function.h> +#include <vespa/eval/instruction/dense_tensor_create_function.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -12,7 +12,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/vector_from_doubles_function/CMakeLists.txt b/eval/src/tests/instruction/vector_from_doubles_function/CMakeLists.txt index 5b2e47ec498..5b2e47ec498 100644 --- a/eval/src/tests/tensor/vector_from_doubles_function/CMakeLists.txt +++ b/eval/src/tests/instruction/vector_from_doubles_function/CMakeLists.txt diff --git a/eval/src/tests/tensor/vector_from_doubles_function/vector_from_doubles_function_test.cpp b/eval/src/tests/instruction/vector_from_doubles_function/vector_from_doubles_function_test.cpp index c3e1f2f248e..4f4829c3ae1 100644 --- a/eval/src/tests/tensor/vector_from_doubles_function/vector_from_doubles_function_test.cpp +++ b/eval/src/tests/instruction/vector_from_doubles_function/vector_from_doubles_function_test.cpp @@ -2,7 +2,7 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/eval/tensor_function.h> -#include <vespa/eval/tensor/dense/vector_from_doubles_function.h> +#include <vespa/eval/instruction/vector_from_doubles_function.h> #include <vespa/eval/eval/test/tensor_model.hpp> #include <vespa/eval/eval/test/eval_fixture.h> @@ -12,7 +12,6 @@ using namespace vespalib; using namespace vespalib::eval; using namespace vespalib::eval::test; -using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get(); diff --git a/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt b/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt deleted file mode 100644 index eaee8ebb4e4..00000000000 --- a/eval/src/tests/tensor/dense_dimension_combiner/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -vespa_add_executable(eval_dense_dimension_combiner_test_app TEST - SOURCES - dense_dimension_combiner_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_dense_dimension_combiner_test_app COMMAND eval_dense_dimension_combiner_test_app) diff --git a/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp b/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp deleted file mode 100644 index b8949e3a7e6..00000000000 --- a/eval/src/tests/tensor/dense_dimension_combiner/dense_dimension_combiner_test.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2019 Oath Inc. 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/eval/tensor/dense/dense_dimension_combiner.h> - -using namespace vespalib; -using namespace vespalib::eval; -using namespace vespalib::tensor; - -void verifyLeft(DenseDimensionCombiner &d, size_t last) { - d.commonReset(); - d.leftReset(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); - size_t expect = 0; - while (d.leftInRange()) { - d.stepLeft(); - EXPECT_GREATER(d.leftIdx(), expect); - expect = d.leftIdx(); - } - EXPECT_FALSE(d.leftInRange()); - EXPECT_EQUAL(expect, last); - d.leftReset(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); -} - -void verifyRight(DenseDimensionCombiner &d, size_t last) { - d.commonReset(); - d.rightReset(); - EXPECT_TRUE(d.rightInRange()); - EXPECT_EQUAL(d.rightIdx(), 0u); - size_t expect = 0; - while (d.rightInRange()) { - d.stepRight(); - EXPECT_GREATER(d.rightIdx(), expect); - expect = d.rightIdx(); - } - EXPECT_FALSE(d.rightInRange()); - EXPECT_EQUAL(expect, last); - d.rightReset(); - EXPECT_TRUE(d.rightInRange()); - EXPECT_EQUAL(d.rightIdx(), 0u); -} - - -TEST("require that one left, one common, one right dimension works") { - ValueType t12_lc = ValueType::tensor_type({{"d1_l", 3},{"d2_c", 4}}); - ValueType t23_cr = ValueType::tensor_type({{"d2_c", 4},{"d3_r", 5}}); - - DenseDimensionCombiner d(t12_lc, t23_cr); - - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); - EXPECT_EQUAL(d.rightIdx(), 0u); - EXPECT_EQUAL(d.outputIdx(), 0u); - - d.stepCommon(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 1u); - EXPECT_EQUAL(d.rightIdx(), 5u); - EXPECT_EQUAL(d.outputIdx(), 5u); - - d.stepRight(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 1u); - EXPECT_EQUAL(d.rightIdx(), 6u); - EXPECT_EQUAL(d.outputIdx(), 6u); - - d.stepLeft(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 5u); - EXPECT_EQUAL(d.rightIdx(), 6u); - EXPECT_EQUAL(d.outputIdx(), 26u); - - d.stepLeft(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 9u); - EXPECT_EQUAL(d.rightIdx(), 6u); - EXPECT_EQUAL(d.outputIdx(), 46u); - - d.stepLeft(); - EXPECT_FALSE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 13u); - EXPECT_EQUAL(d.rightIdx(), 6u); - EXPECT_EQUAL(d.outputIdx(), 6u); - - d.leftReset(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 1u); - EXPECT_EQUAL(d.rightIdx(), 6u); - EXPECT_EQUAL(d.outputIdx(), 6u); - - d.stepCommon(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 2u); - EXPECT_EQUAL(d.rightIdx(), 11u); - EXPECT_EQUAL(d.outputIdx(), 11u); - - d.stepRight(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 2u); - EXPECT_EQUAL(d.rightIdx(), 12u); - EXPECT_EQUAL(d.outputIdx(), 12u); - - TEST_DO(verifyLeft(d, 12)); - TEST_DO(verifyRight(d, 20)); -} - -TEST("require that two left, no common, two right dimensions works") { - ValueType t12_ll = ValueType::tensor_type({{"d1_l", 3},{"d2_l", 4}}); - ValueType t34_rr = ValueType::tensor_type({{"d3_r", 5},{"d4_r", 2}}); - - DenseDimensionCombiner d(t12_ll, t34_rr); - - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); - EXPECT_EQUAL(d.rightIdx(), 0u); - EXPECT_EQUAL(d.outputIdx(), 0u); - - d.stepCommon(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_FALSE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); - EXPECT_EQUAL(d.rightIdx(), 0u); - EXPECT_EQUAL(d.outputIdx(), 120u); - - d.commonReset(); - d.stepRight(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 0u); - EXPECT_EQUAL(d.rightIdx(), 1u); - EXPECT_EQUAL(d.outputIdx(), 1u); - - d.stepLeft(); - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 1u); - EXPECT_EQUAL(d.rightIdx(), 1u); - EXPECT_EQUAL(d.outputIdx(), 11u); - - d.stepLeft(); - d.stepLeft(); - d.stepLeft(); - d.stepLeft(); - d.stepLeft(); - d.stepLeft(); - d.stepLeft(); - - EXPECT_TRUE(d.leftInRange()); - EXPECT_TRUE(d.rightInRange()); - EXPECT_TRUE(d.commonInRange()); - EXPECT_EQUAL(d.leftIdx(), 8u); - EXPECT_EQUAL(d.rightIdx(), 1u); - EXPECT_EQUAL(d.outputIdx(), 81u); - - TEST_DO(verifyLeft(d, 12)); - TEST_DO(verifyRight(d, 10)); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt b/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt deleted file mode 100644 index 00ff230fadd..00000000000 --- a/eval/src/tests/tensor/direct_sparse_tensor_builder/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(eval_direct_sparse_tensor_builder_test_app TEST - SOURCES - direct_sparse_tensor_builder_test.cpp - DEPENDS - vespaeval -) -vespa_add_test(NAME eval_direct_sparse_tensor_builder_test_app COMMAND eval_direct_sparse_tensor_builder_test_app) diff --git a/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp b/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp deleted file mode 100644 index bcee6471f76..00000000000 --- a/eval/src/tests/tensor/direct_sparse_tensor_builder/direct_sparse_tensor_builder_test.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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/eval/tensor/sparse/direct_sparse_tensor_builder.h> -#include <vespa/eval/tensor/sparse/sparse_tensor_address_combiner.h> -#include <vespa/vespalib/test/insertion_operators.h> - -using namespace vespalib::tensor; -using namespace vespalib::tensor::sparse; -using vespalib::eval::TensorSpec; -using vespalib::eval::CellType; -using vespalib::eval::ValueType; - -void -assertCellValue(double expValue, const TensorAddress &address, - const ValueType &type, - const SparseTensor &tensor) -{ - SparseTensorAddressBuilder addressBuilder; - auto dimsItr = type.dimensions().cbegin(); - auto dimsItrEnd = type.dimensions().cend(); - for (const auto &element : address.elements()) { - while ((dimsItr < dimsItrEnd) && (dimsItr->name < element.dimension())) { - addressBuilder.add(""); - ++dimsItr; - } - assert((dimsItr != dimsItrEnd) && (dimsItr->name == element.dimension())); - addressBuilder.add(element.label()); - ++dimsItr; - } - while (dimsItr < dimsItrEnd) { - addressBuilder.add(""); - ++dimsItr; - } - SparseTensorAddressRef addressRef(addressBuilder.getAddressRef()); - size_t idx; - bool found = tensor.index().lookup_address(addressRef, idx); - EXPECT_TRUE(found); - auto cells = tensor.cells(); - if (EXPECT_TRUE(cells.type == CellType::DOUBLE)) { - auto arr = cells.typify<double>(); - EXPECT_EQUAL(expValue, arr[idx]); - } -} - -Tensor::UP -buildTensor() -{ - DirectSparseTensorBuilder<double> builder(ValueType::from_spec("tensor(a{},b{},c{},d{})")); - SparseTensorAddressBuilder address; - address.set({"1", "2", "", ""}); - builder.insertCell(address, 10); - address.set({"", "", "3", "4"}); - builder.insertCell(address, 20); - return builder.build(); -} - -TEST("require that tensor can be constructed") -{ - Tensor::UP tensor = buildTensor(); - const SparseTensor &sparseTensor = dynamic_cast<const SparseTensor &>(*tensor); - const ValueType &type = sparseTensor.type(); - const auto & index = sparseTensor.index(); - EXPECT_EQUAL(2u, index.size()); - assertCellValue(10, TensorAddress({{"a","1"},{"b","2"}}), type, sparseTensor); - assertCellValue(20, TensorAddress({{"c","3"},{"d","4"}}), type, sparseTensor); -} - -TEST("require that tensor can be converted to tensor spec") -{ - Tensor::UP tensor = buildTensor(); - TensorSpec expSpec("tensor(a{},b{},c{},d{})"); - expSpec.add({{"a", "1"}, {"b", "2"}, {"c", ""}, {"d", ""}}, 10). - add({{"a", ""},{"b",""},{"c", "3"}, {"d", "4"}}, 20); - TensorSpec actSpec = tensor->toSpec(); - EXPECT_EQUAL(expSpec, actSpec); -} - -TEST("require that dimensions are extracted") -{ - Tensor::UP tensor = buildTensor(); - const SparseTensor &sparseTensor = dynamic_cast<const SparseTensor &>(*tensor); - const auto &dims = sparseTensor.type().dimensions(); - EXPECT_EQUAL(4u, dims.size()); - EXPECT_EQUAL("a", dims[0].name); - EXPECT_EQUAL("b", dims[1].name); - EXPECT_EQUAL("c", dims[2].name); - EXPECT_EQUAL("d", dims[3].name); - EXPECT_EQUAL("tensor(a{},b{},c{},d{})", sparseTensor.type().to_spec()); -} - -void verifyAddressCombiner(const ValueType & a, const ValueType & b, size_t numDim, size_t numOverlapping) { - TensorAddressCombiner combiner(a, b); - EXPECT_EQUAL(numDim, combiner.numDimensions()); - EXPECT_EQUAL(numOverlapping, combiner.numOverlappingDimensions()); -} -TEST("Test sparse tensor address combiner") { - verifyAddressCombiner(ValueType::tensor_type({{"a"}}), ValueType::tensor_type({{"b"}}), 2, 0); - verifyAddressCombiner(ValueType::tensor_type({{"a"}, {"b"}}), ValueType::tensor_type({{"b"}}), 2, 1); - verifyAddressCombiner(ValueType::tensor_type({{"a"}, {"b"}}), ValueType::tensor_type({{"b"}, {"c"}}), 3, 1); - -} - -TEST("Test essential object sizes") { - EXPECT_EQUAL(16u, sizeof(SparseTensorAddressRef)); - EXPECT_EQUAL(24u, sizeof(std::pair<SparseTensorAddressRef, double>)); - EXPECT_EQUAL(32u, sizeof(vespalib::hash_node<std::pair<SparseTensorAddressRef, double>>)); - Tensor::UP tensor = buildTensor(); - size_t used = tensor->get_memory_usage().usedBytes(); - EXPECT_GREATER(used, sizeof(SparseTensor)); - EXPECT_LESS(used, 10000u); - size_t allocated = tensor->get_memory_usage().allocatedBytes(); - EXPECT_GREATER(allocated, used); - EXPECT_LESS(allocated, 50000u); - fprintf(stderr, "tensor using %zu bytes of %zu allocated\n", - used, allocated); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/eval/src/tests/tensor/instruction_benchmark/.gitignore b/eval/src/tests/tensor/instruction_benchmark/.gitignore index dc5c408cf29..5b3eab59ff6 100644 --- a/eval/src/tests/tensor/instruction_benchmark/.gitignore +++ b/eval/src/tests/tensor/instruction_benchmark/.gitignore @@ -1 +1,3 @@ vespa-tensor-instructions-benchmark +/result.json +/ghost.json diff --git a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp index 3bddf69f53f..aa1da07bc91 100644 --- a/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp +++ b/eval/src/tests/tensor/instruction_benchmark/instruction_benchmark.cpp @@ -39,15 +39,20 @@ #include <vespa/vespalib/objects/nbostream.h> #include <vespa/vespalib/util/stash.h> #include <vespa/vespalib/gtest/gtest.h> +#include <vespa/vespalib/io/mapped_file_input.h> +#include <vespa/vespalib/io/fileutil.h> +#include <vespa/vespalib/data/slime/slime.h> +#include <vespa/vespalib/data/smart_buffer.h> #include <optional> #include <algorithm> using namespace vespalib; using namespace vespalib::eval; -using namespace vespalib::tensor; using namespace vespalib::eval::instruction; using vespalib::make_string_short::fmt; +using vespalib::slime::JsonFormat; + using Instruction = InterpretedFunction::Instruction; using EvalSingle = InterpretedFunction::EvalSingle; @@ -256,6 +261,8 @@ Impl optimized_fast_value_impl(0, " Optimized FastValue", " Impl fast_value_impl(1, " FastValue", " FastV", FastValueBuilderFactory::get(), false); Impl simple_value_impl(2, " SimpleValue", " SimpleV", SimpleValueBuilderFactory::get(), false); vespalib::string short_header("--------"); +vespalib::string ghost_name(" loaded from ghost.json"); +vespalib::string ghost_short_name(" ghost"); constexpr double budget = 5.0; constexpr double best_limit = 0.95; // everything within 95% of best performance gets a star @@ -266,6 +273,10 @@ std::vector<CREF<Impl>> impl_list = {simple_value_impl, optimized_fast_value_impl, fast_value_impl}; +Slime ghost; // loaded from 'ghost.json' +bool has_ghost = false; +Slime prod_result; // saved to 'result.json' + //----------------------------------------------------------------------------- struct BenchmarkHeader { @@ -275,6 +286,9 @@ struct BenchmarkHeader { for (const Impl &impl: impl_list) { short_names[impl.order] = impl.short_name; } + if (has_ghost) { + short_names.push_back(ghost_short_name); + } } void print_header(const vespalib::string &desc) const { for (const auto &name: short_names) { @@ -300,12 +314,17 @@ struct BenchmarkResult { ~BenchmarkResult(); void sample(size_t order, double time) { relative_perf[order] = time; - if (order == 1) { - if (ref_time.has_value()) { - ref_time = std::min(ref_time.value(), time); - } else { - ref_time = time; + if (order == 0) { + prod_result.get().setDouble(desc, time); + if (has_ghost && (relative_perf.size() == impl_list.size())) { + double ghost_time = ghost.get()[desc].asDouble(); + size_t ghost_order = relative_perf.size(); + fprintf(stderr, " %s(%s): %10.3f us\n", ghost_name.c_str(), ghost_short_name.c_str(), ghost_time); + relative_perf.resize(ghost_order + 1); + return sample(ghost_order, ghost_time); } + } else if (order == 1) { + ref_time = time; } } void normalize() { @@ -333,6 +352,23 @@ std::vector<BenchmarkResult> benchmark_results; //----------------------------------------------------------------------------- +void load_ghost(const vespalib::string &file_name) { + MappedFileInput input(file_name); + has_ghost = JsonFormat::decode(input, ghost); +} + +void save_result(const vespalib::string &file_name) { + SmartBuffer output(4096); + JsonFormat::encode(prod_result, output, false); + Memory memory = output.obtain(); + File file(file_name); + file.open(File::CREATE | File::TRUNC); + file.write(memory.data, memory.size, 0); + file.close(); +} + +//----------------------------------------------------------------------------- + struct MyParam : LazyParams { Value::UP my_value; MyParam() : my_value() {} @@ -433,8 +469,8 @@ void benchmark(const vespalib::string &desc, const std::vector<EvalOp::UP> &list } for (const auto &eval: list) { double time = eval->estimate_cost_us(loop_cnt[eval->impl.order], loop_cnt[1]); - result.sample(eval->impl.order, time); fprintf(stderr, " %s(%s): %10.3f us\n", eval->impl.name.c_str(), eval->impl.short_name.c_str(), time); + result.sample(eval->impl.order, time); } result.normalize(); benchmark_results.push_back(result); @@ -674,9 +710,9 @@ void benchmark_encode_decode(const vespalib::string &desc, const TensorSpec &pro } double encode_us = encode_timer.min_time() * 1000.0 * 1000.0 / double(loop_cnt); double decode_us = decode_timer.min_time() * 1000.0 * 1000.0 / double(loop_cnt); - fprintf(stderr, " %s (%s) <encode>: %10.3f us\n", impl.name.c_str(), impl.short_name.c_str(), encode_us); - fprintf(stderr, " %s (%s) <decode>: %10.3f us\n", impl.name.c_str(), impl.short_name.c_str(), decode_us); + fprintf(stderr, " %s(%s): %10.3f us <encode>\n", impl.name.c_str(), impl.short_name.c_str(), encode_us); encode_result.sample(impl.order, encode_us); + fprintf(stderr, " %s(%s): %10.3f us <decode>\n", impl.name.c_str(), impl.short_name.c_str(), decode_us); decode_result.sample(impl.order, decode_us); } encode_result.normalize(); @@ -1077,16 +1113,26 @@ void print_summary() { } int main(int argc, char **argv) { + prod_result.setObject(); + load_ghost("ghost.json"); const std::string run_only_prod_option = "--limit-implementations"; + const std::string ghost_mode_option = "--ghost-mode"; if ((argc > 1) && (argv[1] == run_only_prod_option )) { impl_list.clear(); impl_list.push_back(optimized_fast_value_impl); impl_list.push_back(fast_value_impl); ++argv; --argc; + } else if ((argc > 1) && (argv[1] == ghost_mode_option )) { + impl_list.clear(); + impl_list.push_back(optimized_fast_value_impl); + has_ghost = true; + ++argv; + --argc; } ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); + save_result("result.json"); print_summary(); return result; } 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 7e204f1ea06..b474d2458b9 100644 --- a/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp +++ b/eval/src/tests/tensor/onnx_wrapper/onnx_wrapper_test.cpp @@ -6,7 +6,6 @@ #include <vespa/vespalib/gtest/gtest.h> using namespace vespalib::eval; -using namespace vespalib::tensor; using vespalib::make_string_short::fmt; using TensorInfo = Onnx::TensorInfo; diff --git a/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp b/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp index c12b7071d02..a0a062c4322 100644 --- a/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp +++ b/eval/src/tests/tensor/tensor_address/tensor_address_test.cpp @@ -3,8 +3,6 @@ #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/eval/tensor/tensor_address.h> -using namespace vespalib::tensor; - void assertSortOrder(const TensorAddress::Elements &exp, const TensorAddress::Elements &input) diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp index ed0b122196d..cbd4192a84f 100644 --- a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp +++ b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp @@ -8,18 +8,18 @@ #include <vespa/eval/instruction/dense_xw_product_function.h> #include <vespa/eval/instruction/dense_matmul_function.h> #include <vespa/eval/instruction/dense_multi_matmul_function.h> -#include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> -#include <vespa/eval/tensor/dense/dense_add_dimension_optimizer.h> -#include <vespa/eval/tensor/dense/dense_single_reduce_function.h> -#include <vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h> +#include <vespa/eval/instruction/dense_fast_rename_optimizer.h> +#include <vespa/eval/instruction/dense_add_dimension_optimizer.h> +#include <vespa/eval/instruction/dense_single_reduce_function.h> +#include <vespa/eval/instruction/dense_remove_dimension_optimizer.h> #include <vespa/eval/instruction/dense_lambda_peek_optimizer.h> #include <vespa/eval/instruction/dense_simple_expand_function.h> -#include <vespa/eval/tensor/dense/dense_simple_join_function.h> +#include <vespa/eval/instruction/dense_simple_join_function.h> #include <vespa/eval/instruction/join_with_number_function.h> -#include <vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h> -#include <vespa/eval/tensor/dense/dense_simple_map_function.h> -#include <vespa/eval/tensor/dense/vector_from_doubles_function.h> -#include <vespa/eval/tensor/dense/dense_tensor_create_function.h> +#include <vespa/eval/instruction/dense_pow_as_map_optimizer.h> +#include <vespa/eval/instruction/dense_simple_map_function.h> +#include <vespa/eval/instruction/vector_from_doubles_function.h> +#include <vespa/eval/instruction/dense_tensor_create_function.h> #include <vespa/eval/instruction/dense_tensor_peek_function.h> #include <vespa/log/log.h> @@ -29,8 +29,6 @@ namespace vespalib::eval { namespace { -using namespace vespalib::tensor; - const TensorFunction &optimize_for_factory(const ValueBuilderFactory &factory, const TensorFunction &expr, Stash &stash) { if (&factory == &SimpleValueBuilderFactory::get()) { // never optimize simple value evaluation diff --git a/eval/src/vespa/eval/eval/tensor_function.h b/eval/src/vespa/eval/eval/tensor_function.h index 26d28bac350..ed1106cccc1 100644 --- a/eval/src/vespa/eval/eval/tensor_function.h +++ b/eval/src/vespa/eval/eval/tensor_function.h @@ -21,9 +21,6 @@ namespace vespalib { class Stash; class ObjectVisitor; -// TODO: remove this type injection when the 'tensor' namespace is removed -namespace tensor { using ValueBuilderFactory = vespalib::eval::ValueBuilderFactory; } - namespace eval { class Tensor; diff --git a/eval/src/vespa/eval/eval/value_type.cpp b/eval/src/vespa/eval/eval/value_type.cpp index 05ec65bf292..a5960a8de4b 100644 --- a/eval/src/vespa/eval/eval/value_type.cpp +++ b/eval/src/vespa/eval/eval/value_type.cpp @@ -138,7 +138,7 @@ struct Renamer { bool matched_all() const { return (match_cnt == from.size()); } }; -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> constexpr ValueType::Dimension::size_type ValueType::Dimension::npos; diff --git a/eval/src/vespa/eval/instruction/CMakeLists.txt b/eval/src/vespa/eval/instruction/CMakeLists.txt index 4f2c59e34e1..42f88c0ee52 100644 --- a/eval/src/vespa/eval/instruction/CMakeLists.txt +++ b/eval/src/vespa/eval/instruction/CMakeLists.txt @@ -22,4 +22,14 @@ vespa_add_library(eval_instruction OBJECT generic_rename.cpp index_lookup_table.cpp join_with_number_function.cpp + dense_add_dimension_optimizer.cpp + dense_fast_rename_optimizer.cpp + dense_pow_as_map_optimizer.cpp + dense_remove_dimension_optimizer.cpp + dense_replace_type_function.cpp + dense_simple_join_function.cpp + dense_simple_map_function.cpp + dense_single_reduce_function.cpp + dense_tensor_create_function.cpp + vector_from_doubles_function.cpp ) diff --git a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp index 9cd7cc88907..ccccb595c6d 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.cpp @@ -8,13 +8,10 @@ #include <vespa/log/log.h> LOG_SETUP(".eval.tensor.dense.add_dimension_optimizer"); -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::ValueType; -using eval::TensorFunction; -using eval::as; -using namespace eval::tensor_function; -using namespace eval::operation; +using namespace tensor_function; +using namespace operation; namespace { @@ -34,10 +31,10 @@ bool is_unit_constant(const TensorFunction &node) { return false; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> const TensorFunction & -DenseAddDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash) +DenseAddDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) { if (auto join = as<Join>(expr)) { const TensorFunction &lhs = join->lhs(); @@ -57,4 +54,4 @@ DenseAddDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &st return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.h b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h index 4b5cf296292..99ab20614a2 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_add_dimension_optimizer.h +++ b/eval/src/vespa/eval/instruction/dense_add_dimension_optimizer.h @@ -4,14 +4,15 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function optimizer for efficient adding of dimensions with * size 1 for dense tensors. + * TODO: extend to mixed tensors. **/ struct DenseAddDimensionOptimizer { - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp index bd84fc4c51a..a4ef32f4701 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.cpp @@ -4,13 +4,9 @@ #include "dense_replace_type_function.h" #include <vespa/eval/eval/value.h> -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::Value; -using eval::ValueType; -using eval::TensorFunction; -using eval::as; -using namespace eval::tensor_function; +using namespace tensor_function; namespace { @@ -35,10 +31,10 @@ bool is_dense_stable_rename(const ValueType &from_type, const ValueType &to_type return true; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> const TensorFunction & -DenseFastRenameOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash) +DenseFastRenameOptimizer::optimize(const TensorFunction &expr, Stash &stash) { if (auto rename = as<Rename>(expr)) { const ValueType &from_type = rename->child().result_type(); @@ -51,4 +47,4 @@ DenseFastRenameOptimizer::optimize(const eval::TensorFunction &expr, Stash &stas return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.h b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h index bbcb38e1f80..2882cdf6f30 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_fast_rename_optimizer.h +++ b/eval/src/vespa/eval/instruction/dense_fast_rename_optimizer.h @@ -4,14 +4,15 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function optimizer for efficient non-transposing rename of a * dense tensor. + * TODO: extend to mixed tensors. **/ struct DenseFastRenameOptimizer { - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp index 6853b1a078f..f8ce886ae1f 100644 --- a/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_lambda_peek_optimizer.cpp @@ -3,7 +3,7 @@ #include "dense_lambda_peek_optimizer.h" #include "dense_lambda_peek_function.h" #include "dense_cell_range_function.h" -#include <vespa/eval/tensor/dense/dense_replace_type_function.h> +#include <vespa/eval/instruction/dense_replace_type_function.h> #include <vespa/eval/eval/value.h> #include <vespa/eval/eval/node_tools.h> #include <vespa/eval/eval/basic_nodes.h> @@ -182,7 +182,7 @@ DenseLambdaPeekOptimizer::optimize(const TensorFunction &expr, Stash &stash) if (result.cell_range && (dst_type.cell_type() == src_type.cell_type())) { auto cell_range = result.cell_range.value(); if (cell_range.is_full(src_type.dense_subspace_size())) { - return tensor::DenseReplaceTypeFunction::create_compact(dst_type, get_param, stash); + return DenseReplaceTypeFunction::create_compact(dst_type, get_param, stash); } else { return stash.create<DenseCellRangeFunction>(dst_type, get_param, cell_range.offset, cell_range.length); diff --git a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.cpp index f78c23c80ac..61ef2243480 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.cpp @@ -4,13 +4,10 @@ #include "dense_simple_map_function.h" #include <vespa/eval/eval/operation.h> -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::TensorFunction; -using eval::as; - -using namespace eval::tensor_function; -using namespace eval::operation; +using namespace tensor_function; +using namespace operation; const TensorFunction & DensePowAsMapOptimizer::optimize(const TensorFunction &expr, Stash &stash) @@ -35,4 +32,4 @@ DensePowAsMapOptimizer::optimize(const TensorFunction &expr, Stash &stash) return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.h index 4849a10c070..e61069b87b0 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_pow_as_map_optimizer.h +++ b/eval/src/vespa/eval/instruction/dense_pow_as_map_optimizer.h @@ -4,15 +4,16 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function optimizer for converting join expressions on the * form 'join(tensor,<small integer constant>,f(x,y)(pow(x,y))' to * expressions on the form 'map(tensor,f(x)(x*x...))'. + * TODO: extend to mixed tensors. **/ struct DensePowAsMapOptimizer { - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.cpp b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp index a48527e83f5..fc7f31fb421 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.cpp +++ b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.cpp @@ -4,13 +4,9 @@ #include "dense_replace_type_function.h" #include <vespa/eval/eval/value_type.h> -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::Aggr; -using eval::ValueType; -using eval::TensorFunction; -using eval::as; -using namespace eval::tensor_function; +using namespace tensor_function; namespace { @@ -25,16 +21,16 @@ bool is_trivial_dim_list(const ValueType &type, const std::vector<vespalib::stri return true; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> const TensorFunction & -DenseRemoveDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash &stash) +DenseRemoveDimensionOptimizer::optimize(const TensorFunction &expr, Stash &stash) { if (auto reduce = as<Reduce>(expr)) { const TensorFunction &child = reduce->child(); if (expr.result_type().is_dense() && child.result_type().is_dense() && - eval::aggr::is_ident(reduce->aggr()) && + aggr::is_ident(reduce->aggr()) && is_trivial_dim_list(child.result_type(), reduce->dimensions())) { assert(expr.result_type().cell_type() == child.result_type().cell_type()); @@ -44,4 +40,4 @@ DenseRemoveDimensionOptimizer::optimize(const eval::TensorFunction &expr, Stash return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h index 64b057a62d8..2b4e3588caf 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_remove_dimension_optimizer.h +++ b/eval/src/vespa/eval/instruction/dense_remove_dimension_optimizer.h @@ -4,14 +4,15 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function optimizer for efficient removal of dimensions with * size 1 for dense tensors. + * TODO: extend to mixed tensors. **/ struct DenseRemoveDimensionOptimizer { - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp b/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp new file mode 100644 index 00000000000..81d3ca67880 --- /dev/null +++ b/eval/src/vespa/eval/instruction/dense_replace_type_function.cpp @@ -0,0 +1,48 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "dense_replace_type_function.h" +#include <vespa/eval/eval/value.h> + +namespace vespalib::eval { + +using namespace tensor_function; + +namespace { + +void my_replace_type_op(InterpretedFunction::State &state, uint64_t param) { + const ValueType &type = unwrap_param<ValueType>(param); + TypedCells cells = state.peek(0).cells(); + state.pop_push(state.stash.create<DenseValueView>(type, cells)); +} + +} // namespace vespalib::eval::<unnamed> + +DenseReplaceTypeFunction::DenseReplaceTypeFunction(const ValueType &result_type, + const TensorFunction &child) + : tensor_function::Op1(result_type, child) +{ +} + +DenseReplaceTypeFunction::~DenseReplaceTypeFunction() +{ +} + +InterpretedFunction::Instruction +DenseReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const +{ + return InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type())); +} + +const DenseReplaceTypeFunction & +DenseReplaceTypeFunction::create_compact(const ValueType &result_type, + const TensorFunction &child, + Stash &stash) +{ + if (auto replace = as<DenseReplaceTypeFunction>(child)) { + return stash.create<DenseReplaceTypeFunction>(result_type, replace->child()); + } else { + return stash.create<DenseReplaceTypeFunction>(result_type, child); + } +} + +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h b/eval/src/vespa/eval/instruction/dense_replace_type_function.h index adf5023b0cb..78ce163aceb 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.h +++ b/eval/src/vespa/eval/instruction/dense_replace_type_function.h @@ -4,23 +4,24 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function for efficient type-only modification of dense * tensor. + * TODO: extend to handling any tensor, dense/mixed/sparse. **/ -class DenseReplaceTypeFunction : public eval::tensor_function::Op1 +class DenseReplaceTypeFunction : public tensor_function::Op1 { public: - DenseReplaceTypeFunction(const eval::ValueType &result_type, - const eval::TensorFunction &child); + DenseReplaceTypeFunction(const ValueType &result_type, + const TensorFunction &child); ~DenseReplaceTypeFunction(); - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return child().result_is_mutable(); } - static const DenseReplaceTypeFunction &create_compact(const eval::ValueType &result_type, - const eval::TensorFunction &child, + static const DenseReplaceTypeFunction &create_compact(const ValueType &result_type, + const TensorFunction &child, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_join_function.cpp index 21b47b67291..76d020eef9d 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_simple_join_function.cpp @@ -9,28 +9,19 @@ #include <optional> #include <algorithm> -namespace vespalib::tensor { +namespace vespalib::eval { using vespalib::ArrayRef; -using eval::CellType; -using eval::DenseValueView; -using eval::TensorFunction; -using eval::TypedCells; -using eval::TypifyCellType; -using eval::Value; -using eval::ValueType; -using eval::as; - -using namespace eval::operation; -using namespace eval::tensor_function; +using namespace operation; +using namespace tensor_function; using Primary = DenseSimpleJoinFunction::Primary; using Overlap = DenseSimpleJoinFunction::Overlap; -using op_function = eval::InterpretedFunction::op_function; -using Instruction = eval::InterpretedFunction::Instruction; -using State = eval::InterpretedFunction::State; +using op_function = InterpretedFunction::op_function; +using Instruction = InterpretedFunction::Instruction; +using State = InterpretedFunction::State; namespace { @@ -67,7 +58,7 @@ template <typename LCT, typename RCT, typename Fun, bool swap, Overlap overlap, void my_simple_join_op(State &state, uint64_t param) { using PCT = typename std::conditional<swap,RCT,LCT>::type; using SCT = typename std::conditional<swap,LCT,RCT>::type; - using OCT = typename eval::UnifyCellTypes<PCT,SCT>::type; + using OCT = typename UnifyCellTypes<PCT,SCT>::type; using OP = typename std::conditional<swap,SwapArgs2<Fun>,Fun>::type; const JoinParams ¶ms = unwrap_param<JoinParams>(param); OP my_op(params.function); @@ -151,7 +142,7 @@ std::optional<Overlap> detect_overlap(const TensorFunction &lhs, const TensorFun return (primary == Primary::LHS) ? detect_overlap(lhs, rhs) : detect_overlap(rhs, lhs); } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> //----------------------------------------------------------------------------- @@ -221,4 +212,4 @@ DenseSimpleJoinFunction::optimize(const TensorFunction &expr, Stash &stash) return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h b/eval/src/vespa/eval/instruction/dense_simple_join_function.h index 4cb4a0fc4ff..8fa0be9d021 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_join_function.h +++ b/eval/src/vespa/eval/instruction/dense_simple_join_function.h @@ -5,23 +5,25 @@ #include <vespa/eval/eval/tensor_function.h> #include <vespa/eval/eval/operation.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function for simple join operations on dense tensors. + * TODO: consider if this is useful anymore, maybe we just need + * to handle inplace. **/ -class DenseSimpleJoinFunction : public eval::tensor_function::Join +class DenseSimpleJoinFunction : public tensor_function::Join { - using Super = eval::tensor_function::Join; + using Super = tensor_function::Join; public: enum class Primary : uint8_t { LHS, RHS }; enum class Overlap : uint8_t { INNER, OUTER, FULL }; - using join_fun_t = vespalib::eval::operation::op2_t; + using join_fun_t = operation::op2_t; private: Primary _primary; Overlap _overlap; public: - DenseSimpleJoinFunction(const eval::ValueType &result_type, + DenseSimpleJoinFunction(const ValueType &result_type, const TensorFunction &lhs, const TensorFunction &rhs, join_fun_t function_in, @@ -32,8 +34,8 @@ public: Overlap overlap() const { return _overlap; } bool primary_is_mutable() const; size_t factor() const; - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp b/eval/src/vespa/eval/instruction/dense_simple_map_function.cpp index 5227b67dd92..ec7d2014436 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_simple_map_function.cpp @@ -6,24 +6,16 @@ #include <vespa/eval/eval/operation.h> #include <vespa/eval/eval/inline_operation.h> -namespace vespalib::tensor { +namespace vespalib::eval { using vespalib::ArrayRef; -using eval::DenseValueView; -using eval::TensorFunction; -using eval::TypedCells; -using eval::TypifyCellType; -using eval::Value; -using eval::ValueType; -using eval::as; +using namespace operation; +using namespace tensor_function; -using namespace eval::operation; -using namespace eval::tensor_function; - -using op_function = eval::InterpretedFunction::op_function; -using Instruction = eval::InterpretedFunction::Instruction; -using State = eval::InterpretedFunction::State; +using op_function = InterpretedFunction::op_function; +using Instruction = InterpretedFunction::Instruction; +using State = InterpretedFunction::State; namespace { @@ -58,7 +50,7 @@ struct MyGetFun { using MyTypify = TypifyValue<TypifyCellType,TypifyOp1,TypifyBool>; -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> //----------------------------------------------------------------------------- @@ -90,4 +82,4 @@ DenseSimpleMapFunction::optimize(const TensorFunction &expr, Stash &stash) return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_simple_map_function.h b/eval/src/vespa/eval/instruction/dense_simple_map_function.h new file mode 100644 index 00000000000..40432f35c58 --- /dev/null +++ b/eval/src/vespa/eval/instruction/dense_simple_map_function.h @@ -0,0 +1,26 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/eval/eval/tensor_function.h> + +namespace vespalib::eval { + +/** + * Tensor function for simple map operations on dense tensors. + * TODO: Fix generic map to handle inplace, and remove this. + **/ +class DenseSimpleMapFunction : public tensor_function::Map +{ +public: + using map_fun_t = operation::op1_t; + DenseSimpleMapFunction(const ValueType &result_type, + const TensorFunction &child, + map_fun_t function_in); + ~DenseSimpleMapFunction() override; + bool inplace() const { return child().result_is_mutable(); } + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); +}; + +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp b/eval/src/vespa/eval/instruction/dense_single_reduce_function.cpp index c10fd6c0fe7..53e91f729ee 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_single_reduce_function.cpp @@ -5,21 +5,10 @@ #include <vespa/eval/eval/value.h> #include <cassert> -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::Aggr; -using eval::DenseValueView; -using eval::InterpretedFunction; -using eval::TensorFunction; -using eval::Value; -using eval::ValueType; -using eval::TypedCells; -using eval::TypifyCellType; -using eval::TypifyAggr; -using eval::as; - -using namespace eval::tensor_function; -using namespace eval::aggr; +using namespace tensor_function; +using namespace aggr; namespace { @@ -166,7 +155,7 @@ template <typename T> struct VectorLookupLoop { const T &get() const { return list[index]; } }; -DenseSingleReduceSpec extract_next(const eval::ValueType &type, eval::Aggr aggr, +DenseSingleReduceSpec extract_next(const ValueType &type, Aggr aggr, std::vector<vespalib::string> &todo) { size_t outer_size = 1; @@ -200,10 +189,10 @@ DenseSingleReduceSpec extract_next(const eval::ValueType &type, eval::Aggr aggr, return {type.reduce(do_now), outer_size, reduce_size, inner_size, aggr}; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> std::vector<DenseSingleReduceSpec> -make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr, +make_dense_single_reduce_list(const ValueType &type, Aggr aggr, const std::vector<vespalib::string> &reduce_dims) { auto res_type = type.reduce(reduce_dims); @@ -217,7 +206,7 @@ make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr, curr_type = list.back().result_type; } assert(curr_type == res_type); - if ((list.size() > 1) && !eval::aggr::is_simple(aggr)) { + if ((list.size() > 1) && !aggr::is_simple(aggr)) { return {}; } return list; @@ -261,4 +250,4 @@ DenseSingleReduceFunction::optimize(const TensorFunction &expr, Stash &stash) return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h b/eval/src/vespa/eval/instruction/dense_single_reduce_function.h index 8bdcf82d4ab..ed68bd48c15 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_single_reduce_function.h +++ b/eval/src/vespa/eval/instruction/dense_single_reduce_function.h @@ -4,14 +4,14 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { struct DenseSingleReduceSpec { - eval::ValueType result_type; + ValueType result_type; size_t outer_size; size_t reduce_size; size_t inner_size; - eval::Aggr aggr; + Aggr aggr; }; /** @@ -20,7 +20,7 @@ struct DenseSingleReduceSpec { * fails. **/ std::vector<DenseSingleReduceSpec> -make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr, +make_dense_single_reduce_list(const ValueType &type, Aggr aggr, const std::vector<vespalib::string> &reduce_dims); /** @@ -30,26 +30,28 @@ make_dense_single_reduce_list(const eval::ValueType &type, eval::Aggr aggr, * operation. Adjacent reduced dimensions will be handled is if they * were a single dimension. Trivial dimensions will be trivially * reduced along with any other dimension. + * TODO: consider if we should extend this to handling mixed tensors + * (handling the spare part as a batch dimension). **/ -class DenseSingleReduceFunction : public eval::tensor_function::Op1 +class DenseSingleReduceFunction : public tensor_function::Op1 { private: size_t _outer_size; size_t _reduce_size; size_t _inner_size; - eval::Aggr _aggr; + Aggr _aggr; public: DenseSingleReduceFunction(const DenseSingleReduceSpec &spec, - const eval::TensorFunction &child); + const TensorFunction &child); ~DenseSingleReduceFunction() override; size_t outer_size() const { return _outer_size; } size_t reduce_size() const { return _reduce_size; } size_t inner_size() const { return _inner_size; } - eval::Aggr aggr() const { return _aggr; } + Aggr aggr() const { return _aggr; } bool result_is_mutable() const override { return true; } - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp b/eval/src/vespa/eval/instruction/dense_tensor_create_function.cpp index c233a51a473..0f41158c36e 100644 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.cpp +++ b/eval/src/vespa/eval/instruction/dense_tensor_create_function.cpp @@ -3,23 +3,15 @@ #include "dense_tensor_create_function.h" #include <vespa/eval/eval/value.h> -namespace vespalib::tensor { +namespace vespalib::eval { -using eval::DenseValueView; -using eval::DoubleValue; -using eval::TensorFunction; -using eval::TensorSpec; -using eval::TypedCells; -using eval::Value; -using eval::ValueType; -using Child = eval::TensorFunction::Child; -using eval::as; -using namespace eval::tensor_function; +using Child = TensorFunction::Child; +using namespace tensor_function; namespace { template <typename CT> -void my_tensor_create_op(eval::InterpretedFunction::State &state, uint64_t param) { +void my_tensor_create_op(InterpretedFunction::State &state, uint64_t param) { const auto &self = unwrap_param<DenseTensorCreateFunction::Self>(param); size_t pending_cells = self.result_size; ArrayRef<CT> cells = state.stash.create_uninitialized_array<CT>(pending_cells); @@ -48,7 +40,7 @@ size_t get_index(const TensorSpec::Address &addr, const ValueType &type) { return cell_idx; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> DenseTensorCreateFunction::DenseTensorCreateFunction(const ValueType &res_type, std::vector<Child> children) : TensorFunction(), @@ -67,16 +59,16 @@ DenseTensorCreateFunction::push_children(std::vector<Child::CREF> &target) const } } -eval::InterpretedFunction::Instruction +InterpretedFunction::Instruction DenseTensorCreateFunction::compile_self(const ValueBuilderFactory &, Stash &) const { - using MyTypify = eval::TypifyCellType; + using MyTypify = TypifyCellType; auto op = typify_invoke<1,MyTypify,MyTensorCreateOp>(result_type().cell_type()); - return eval::InterpretedFunction::Instruction(op, wrap_param<DenseTensorCreateFunction::Self>(_self)); + return InterpretedFunction::Instruction(op, wrap_param<DenseTensorCreateFunction::Self>(_self)); } const TensorFunction & -DenseTensorCreateFunction::optimize(const eval::TensorFunction &expr, Stash &stash) +DenseTensorCreateFunction::optimize(const TensorFunction &expr, Stash &stash) { if (auto create = as<Create>(expr)) { if (expr.result_type().is_dense()) { @@ -94,4 +86,4 @@ DenseTensorCreateFunction::optimize(const eval::TensorFunction &expr, Stash &sta return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/dense_tensor_create_function.h b/eval/src/vespa/eval/instruction/dense_tensor_create_function.h new file mode 100644 index 00000000000..9af912ba788 --- /dev/null +++ b/eval/src/vespa/eval/instruction/dense_tensor_create_function.h @@ -0,0 +1,34 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include <vespa/eval/eval/tensor_function.h> + +namespace vespalib::eval { + +/** + * Tensor function for creating a dense tensor from double values. + * TODO: benchmark how useful this is, maybe we can just drop it. + */ +class DenseTensorCreateFunction : public TensorFunction +{ +public: + struct Self { + ValueType result_type; + size_t result_size; + Self(const ValueType &r, size_t n) : result_type(r), result_size(n) {} + }; +private: + Self _self; + std::vector<Child> _children; +public: + DenseTensorCreateFunction(const ValueType &res_type, std::vector<Child> children); + ~DenseTensorCreateFunction(); + const ValueType &result_type() const override { return _self.result_type; } + void push_children(std::vector<Child::CREF> &children) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + bool result_is_mutable() const override { return true; } + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); +}; + +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/instruction/generic_join.h b/eval/src/vespa/eval/instruction/generic_join.h index e5ddf388211..988286be980 100644 --- a/eval/src/vespa/eval/instruction/generic_join.h +++ b/eval/src/vespa/eval/instruction/generic_join.h @@ -12,7 +12,7 @@ namespace vespalib::eval { struct ValueBuilderFactory; } namespace vespalib::eval::instruction { -using join_fun_t = vespalib::eval::operation::op2_t; +using join_fun_t = operation::op2_t; //----------------------------------------------------------------------------- diff --git a/eval/src/vespa/eval/instruction/generic_lambda.cpp b/eval/src/vespa/eval/instruction/generic_lambda.cpp index 5685f199b9e..f4f8c84a257 100644 --- a/eval/src/vespa/eval/instruction/generic_lambda.cpp +++ b/eval/src/vespa/eval/instruction/generic_lambda.cpp @@ -59,7 +59,7 @@ struct CompiledParams { }; template <typename CT> -void my_compiled_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) { +void my_compiled_lambda_op(InterpretedFunction::State &state, uint64_t param) { const CompiledParams ¶ms = unwrap_param<CompiledParams>(param); std::vector<double> args(params.result_type.dimensions().size() + params.bindings.size(), 0.0); double *bind_next = &args[params.result_type.dimensions().size()]; @@ -98,7 +98,7 @@ struct InterpretedParams { }; template <typename CT> -void my_interpreted_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) { +void my_interpreted_lambda_op(InterpretedFunction::State &state, uint64_t param) { const InterpretedParams ¶ms = unwrap_param<InterpretedParams>(param); std::vector<double> labels(params.result_type.dimensions().size(), 0.0); ParamProxy param_proxy(labels, *state.params, params.bindings); @@ -121,7 +121,7 @@ struct MyInterpretedLambdaOp { } // namespace <unnamed> Instruction -GenericLambda::make_instruction(const eval::tensor_function::Lambda &lambda_in, +GenericLambda::make_instruction(const tensor_function::Lambda &lambda_in, const ValueBuilderFactory &factory, Stash &stash) { const ValueType & result_type = lambda_in.result_type(); diff --git a/eval/src/vespa/eval/instruction/generic_lambda.h b/eval/src/vespa/eval/instruction/generic_lambda.h index a9a490f0957..a5f4c10e214 100644 --- a/eval/src/vespa/eval/instruction/generic_lambda.h +++ b/eval/src/vespa/eval/instruction/generic_lambda.h @@ -10,7 +10,7 @@ namespace vespalib::eval::instruction { struct GenericLambda { static InterpretedFunction::Instruction - make_instruction(const eval::tensor_function::Lambda &lambda_in, + make_instruction(const tensor_function::Lambda &lambda_in, const ValueBuilderFactory &factory, Stash &stash); }; diff --git a/eval/src/vespa/eval/instruction/generic_map.h b/eval/src/vespa/eval/instruction/generic_map.h index ad29d2c1073..2c03512a922 100644 --- a/eval/src/vespa/eval/instruction/generic_map.h +++ b/eval/src/vespa/eval/instruction/generic_map.h @@ -10,7 +10,7 @@ namespace vespalib::eval { struct ValueBuilderFactory; } namespace vespalib::eval::instruction { -using map_fun_t = vespalib::eval::operation::op1_t; +using map_fun_t = operation::op1_t; struct GenericMap { static InterpretedFunction::Instruction diff --git a/eval/src/vespa/eval/instruction/join_with_number_function.h b/eval/src/vespa/eval/instruction/join_with_number_function.h index 351f9b005cb..546ff75b175 100644 --- a/eval/src/vespa/eval/instruction/join_with_number_function.h +++ b/eval/src/vespa/eval/instruction/join_with_number_function.h @@ -20,7 +20,7 @@ private: tensor_function::join_fun_t _function; public: - JoinWithNumberFunction(const vespalib::eval::tensor_function::Join &original_join, bool number_on_left); + JoinWithNumberFunction(const tensor_function::Join &original_join, bool number_on_left); ~JoinWithNumberFunction(); Primary primary() const { return _primary; } bool inplace() const; @@ -31,5 +31,5 @@ public: static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp b/eval/src/vespa/eval/instruction/vector_from_doubles_function.cpp index 19c95c9418d..40bd9e25dfc 100644 --- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.cpp +++ b/eval/src/vespa/eval/instruction/vector_from_doubles_function.cpp @@ -3,24 +3,17 @@ #include "vector_from_doubles_function.h" #include <vespa/eval/eval/value.h> -namespace vespalib::tensor { - -using eval::CellType; -using eval::DenseValueView; -using eval::TensorFunction; -using eval::TypedCells; -using eval::Value; -using eval::ValueType; -using Child = eval::TensorFunction::Child; -using eval::as; -using namespace eval::tensor_function; +namespace vespalib::eval { + +using Child = TensorFunction::Child; +using namespace tensor_function; namespace { struct CallVectorFromDoubles { template <typename CT> static TypedCells - invoke(eval::InterpretedFunction::State &state, size_t numCells) { + invoke(InterpretedFunction::State &state, size_t numCells) { ArrayRef<CT> outputCells = state.stash.create_uninitialized_array<CT>(numCells); for (size_t i = numCells; i-- > 0; ) { outputCells[i] = (CT) state.peek(0).as_double(); @@ -30,11 +23,11 @@ struct CallVectorFromDoubles { } }; -void my_vector_from_doubles_op(eval::InterpretedFunction::State &state, uint64_t param) { +void my_vector_from_doubles_op(InterpretedFunction::State &state, uint64_t param) { const auto &self = unwrap_param<VectorFromDoublesFunction::Self>(param); CellType ct = self.resultType.cell_type(); size_t numCells = self.resultSize; - using MyTypify = eval::TypifyCellType; + using MyTypify = TypifyCellType; TypedCells cells = typify_invoke<1,MyTypify,CallVectorFromDoubles>(ct, state, numCells); const Value &result = state.stash.create<DenseValueView>(self.resultType, cells); state.stack.emplace_back(result); @@ -72,7 +65,7 @@ std::vector<Child> flatten(const TensorFunction &lhs, const TensorFunction &rhs) return vec; } -} // namespace vespalib::tensor::<unnamed> +} // namespace vespalib::eval::<unnamed> VectorFromDoublesFunction::VectorFromDoublesFunction(std::vector<Child> children, const ValueType &res_type) @@ -92,14 +85,14 @@ VectorFromDoublesFunction::push_children(std::vector<Child::CREF> &target) const } } -eval::InterpretedFunction::Instruction +InterpretedFunction::Instruction VectorFromDoublesFunction::compile_self(const ValueBuilderFactory &, Stash &) const { - return eval::InterpretedFunction::Instruction(my_vector_from_doubles_op, wrap_param<VectorFromDoublesFunction::Self>(_self)); + return InterpretedFunction::Instruction(my_vector_from_doubles_op, wrap_param<VectorFromDoublesFunction::Self>(_self)); } const TensorFunction & -VectorFromDoublesFunction::optimize(const eval::TensorFunction &expr, Stash &stash) +VectorFromDoublesFunction::optimize(const TensorFunction &expr, Stash &stash) { if (auto concat = as<Concat>(expr)) { const vespalib::string &dimension = concat->dimension(); @@ -114,4 +107,4 @@ VectorFromDoublesFunction::optimize(const eval::TensorFunction &expr, Stash &sta return expr; } -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h b/eval/src/vespa/eval/instruction/vector_from_doubles_function.h index d21a339e7d9..c22ea99f41a 100644 --- a/eval/src/vespa/eval/tensor/dense/vector_from_doubles_function.h +++ b/eval/src/vespa/eval/instruction/vector_from_doubles_function.h @@ -4,35 +4,37 @@ #include <vespa/eval/eval/tensor_function.h> -namespace vespalib::tensor { +namespace vespalib::eval { /** * Tensor function for a concat forming a vector from double values + * TODO: consider removing this, since the user can write a tensor + * create expression instead. */ -class VectorFromDoublesFunction : public eval::TensorFunction +class VectorFromDoublesFunction : public TensorFunction { public: struct Self { - const eval::ValueType resultType; + const ValueType resultType; size_t resultSize; - Self(const eval::ValueType &r, size_t n) : resultType(r), resultSize(n) {} + Self(const ValueType &r, size_t n) : resultType(r), resultSize(n) {} }; private: Self _self; std::vector<Child> _children; - void add(const eval::TensorFunction &child); + void add(const TensorFunction &child); public: - VectorFromDoublesFunction(std::vector<Child> children, const eval::ValueType &res_type); + VectorFromDoublesFunction(std::vector<Child> children, const ValueType &res_type); ~VectorFromDoublesFunction(); - const eval::ValueType &result_type() const override { return _self.resultType; } + const ValueType &result_type() const override { return _self.resultType; } void push_children(std::vector<Child::CREF> &children) const override; const vespalib::string &dimension() const { return _self.resultType.dimensions()[0].name; } size_t size() const { return _self.resultSize; } - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; + InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; bool result_is_mutable() const override { return true; } - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); + static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash); }; -} // namespace vespalib::tensor +} // namespace vespalib::eval diff --git a/eval/src/vespa/eval/onnx/onnx_wrapper.cpp b/eval/src/vespa/eval/onnx/onnx_wrapper.cpp index 521d2382666..d9c0d659b1e 100644 --- a/eval/src/vespa/eval/onnx/onnx_wrapper.cpp +++ b/eval/src/vespa/eval/onnx/onnx_wrapper.cpp @@ -18,16 +18,10 @@ LOG_SETUP(".eval.onnx_wrapper"); using vespalib::ArrayRef; using vespalib::ConstArrayRef; -using vespalib::eval::CellType; -using vespalib::eval::DenseValueView; -using vespalib::eval::DenseCellsValue; -using vespalib::eval::TypedCells; -using vespalib::eval::TypifyCellType; -using vespalib::eval::ValueType; using vespalib::make_string_short::fmt; -namespace vespalib::tensor { +namespace vespalib::eval { namespace { @@ -72,23 +66,23 @@ struct CreateOnnxTensor { }; struct CreateVespaTensorRef { - template <typename T> static eval::Value::UP invoke(const eval::ValueType &type_ref, Ort::Value &value) { + template <typename T> static Value::UP invoke(const ValueType &type_ref, Ort::Value &value) { size_t num_cells = type_ref.dense_subspace_size(); ConstArrayRef<T> cells(value.GetTensorMutableData<T>(), num_cells); return std::make_unique<DenseValueView>(type_ref, TypedCells(cells)); } - eval::Value::UP operator()(const eval::ValueType &type_ref, Ort::Value &value) { + Value::UP operator()(const ValueType &type_ref, Ort::Value &value) { return typify_invoke<1,MyTypify,CreateVespaTensorRef>(type_ref.cell_type(), type_ref, value); } }; struct CreateVespaTensor { - template <typename T> static eval::Value::UP invoke(const eval::ValueType &type) { + template <typename T> static Value::UP invoke(const ValueType &type) { size_t num_cells = type.dense_subspace_size(); std::vector<T> cells(num_cells, T{}); return std::make_unique<DenseCellsValue<T>>(type, std::move(cells)); } - eval::Value::UP operator()(const eval::ValueType &type) { + Value::UP operator()(const ValueType &type) { return typify_invoke<1,MyTypify,CreateVespaTensor>(type.cell_type(), type); } }; @@ -205,7 +199,7 @@ Onnx::TensorInfo make_tensor_info(const OnnxString &name, const Ort::TypeInfo &t return Onnx::TensorInfo{vespalib::string(name.get()), make_dimensions(tensor_info), make_element_type(element_type)}; } -std::vector<int64_t> extract_sizes(const eval::ValueType &type) { +std::vector<int64_t> extract_sizes(const ValueType &type) { std::vector<int64_t> sizes; for (const auto &dim: type.dimensions()) { sizes.push_back(dim.size); @@ -246,7 +240,7 @@ Onnx::WireInfo::~WireInfo() = default; Onnx::WirePlanner::~WirePlanner() = default; bool -Onnx::WirePlanner::bind_input_type(const eval::ValueType &vespa_in, const TensorInfo &onnx_in) +Onnx::WirePlanner::bind_input_type(const ValueType &vespa_in, const TensorInfo &onnx_in) { const auto &type = vespa_in; const auto &name = onnx_in.name; @@ -275,7 +269,7 @@ Onnx::WirePlanner::bind_input_type(const eval::ValueType &vespa_in, const Tensor return true; } -eval::ValueType +ValueType Onnx::WirePlanner::make_output_type(const TensorInfo &onnx_out) const { const auto &dimensions = onnx_out.dimensions; @@ -347,7 +341,7 @@ Ort::AllocatorWithDefaultOptions Onnx::EvalContext::_alloc; template <typename T> void -Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const eval::Value ¶m) +Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const Value ¶m) { const auto &cells_ref = param.cells(); auto cells = unconstify(cells_ref.typify<T>()); @@ -357,7 +351,7 @@ Onnx::EvalContext::adapt_param(EvalContext &self, size_t idx, const eval::Value template <typename SRC, typename DST> void -Onnx::EvalContext::convert_param(EvalContext &self, size_t idx, const eval::Value ¶m) +Onnx::EvalContext::convert_param(EvalContext &self, size_t idx, const Value ¶m) { auto cells = param.cells().typify<SRC>(); size_t n = cells.size(); @@ -384,21 +378,21 @@ Onnx::EvalContext::convert_result(EvalContext &self, size_t idx) struct Onnx::EvalContext::SelectAdaptParam { template <typename ...Ts> static auto invoke() { return adapt_param<Ts...>; } - auto operator()(eval::CellType ct) { + auto operator()(CellType ct) { return typify_invoke<1,MyTypify,SelectAdaptParam>(ct); } }; struct Onnx::EvalContext::SelectConvertParam { template <typename ...Ts> static auto invoke() { return convert_param<Ts...>; } - auto operator()(eval::CellType ct, Onnx::ElementType et) { + auto operator()(CellType ct, Onnx::ElementType et) { return typify_invoke<2,MyTypify,SelectConvertParam>(ct, et); } }; struct Onnx::EvalContext::SelectConvertResult { template <typename ...Ts> static auto invoke() { return convert_result<Ts...>; } - auto operator()(Onnx::ElementType et, eval::CellType ct) { + auto operator()(Onnx::ElementType et, CellType ct) { return typify_invoke<2,MyTypify,SelectConvertResult>(et, ct); } }; @@ -452,7 +446,7 @@ Onnx::EvalContext::EvalContext(const Onnx &model, const WireInfo &wire_info) Onnx::EvalContext::~EvalContext() = default; void -Onnx::EvalContext::bind_param(size_t i, const eval::Value ¶m) +Onnx::EvalContext::bind_param(size_t i, const Value ¶m) { _param_binders[i](*this, i, param); } @@ -470,7 +464,7 @@ Onnx::EvalContext::eval() } } -const eval::Value & +const Value & Onnx::EvalContext::get_result(size_t i) const { return *_results[i]; diff --git a/eval/src/vespa/eval/onnx/onnx_wrapper.h b/eval/src/vespa/eval/onnx/onnx_wrapper.h index f42b926d17e..68c31f04cdc 100644 --- a/eval/src/vespa/eval/onnx/onnx_wrapper.h +++ b/eval/src/vespa/eval/onnx/onnx_wrapper.h @@ -16,7 +16,7 @@ namespace vespalib::eval { struct Value; } -namespace vespalib::tensor { +namespace vespalib::eval { /** * Wrapper around an ONNX model handeled by onnxruntime. @@ -72,24 +72,24 @@ public: // how the model should be wired with inputs/outputs struct WireInfo { - std::vector<eval::ValueType> vespa_inputs; + std::vector<ValueType> vespa_inputs; std::vector<Onnx::TensorType> onnx_inputs; std::vector<Onnx::TensorType> onnx_outputs; - std::vector<eval::ValueType> vespa_outputs; + std::vector<ValueType> vespa_outputs; ~WireInfo(); }; // planning how we should wire the model based on input types class WirePlanner { private: - std::map<vespalib::string,eval::ValueType> _input_types; + std::map<vespalib::string,ValueType> _input_types; std::map<vespalib::string,size_t> _symbolic_sizes; std::set<size_t> _bound_unknown_sizes; public: WirePlanner() : _input_types(), _symbolic_sizes(), _bound_unknown_sizes() {} ~WirePlanner(); - bool bind_input_type(const eval::ValueType &vespa_in, const TensorInfo &onnx_in); - eval::ValueType make_output_type(const TensorInfo &onnx_out) const; + bool bind_input_type(const ValueType &vespa_in, const TensorInfo &onnx_in); + ValueType make_output_type(const TensorInfo &onnx_out) const; WireInfo get_wire_info(const Onnx &model) const; }; @@ -98,7 +98,7 @@ public: // output values are pre-allocated and will not change class EvalContext { private: - using param_fun_t = void (*)(EvalContext &, size_t i, const eval::Value &); + using param_fun_t = void (*)(EvalContext &, size_t i, const Value &); using result_fun_t = void (*)(EvalContext &, size_t i); static Ort::AllocatorWithDefaultOptions _alloc; @@ -108,15 +108,15 @@ public: Ort::MemoryInfo _cpu_memory; std::vector<Ort::Value> _param_values; std::vector<Ort::Value> _result_values; - std::vector<eval::Value::UP> _results; + std::vector<Value::UP> _results; std::vector<param_fun_t> _param_binders; std::vector<std::pair<size_t,result_fun_t>> _result_converters; template <typename T> - static void adapt_param(EvalContext &self, size_t idx, const eval::Value ¶m); + static void adapt_param(EvalContext &self, size_t idx, const Value ¶m); template <typename SRC, typename DST> - static void convert_param(EvalContext &self, size_t idx, const eval::Value ¶m); + static void convert_param(EvalContext &self, size_t idx, const Value ¶m); template <typename SRC, typename DST> static void convert_result(EvalContext &self, size_t idx); @@ -130,9 +130,9 @@ public: ~EvalContext(); size_t num_params() const { return _param_values.size(); } size_t num_results() const { return _result_values.size(); } - void bind_param(size_t i, const eval::Value ¶m); + void bind_param(size_t i, const Value ¶m); void eval(); - const eval::Value &get_result(size_t i) const; + const Value &get_result(size_t i) const; }; private: diff --git a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt index 8e506890b20..d561df80d14 100644 --- a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt +++ b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt @@ -1,15 +1,5 @@ # Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(eval_tensor_dense OBJECT SOURCES - dense_add_dimension_optimizer.cpp - dense_fast_rename_optimizer.cpp - dense_pow_as_map_optimizer.cpp - dense_remove_dimension_optimizer.cpp - dense_replace_type_function.cpp - dense_simple_join_function.cpp - dense_simple_map_function.cpp - dense_single_reduce_function.cpp - dense_tensor_create_function.cpp mutable_dense_tensor_view.cpp - vector_from_doubles_function.cpp ) diff --git a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp deleted file mode 100644 index ed75d6fff98..00000000000 --- a/eval/src/vespa/eval/tensor/dense/dense_replace_type_function.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "dense_replace_type_function.h" -#include <vespa/eval/eval/value.h> - -namespace vespalib::tensor { - -using eval::DenseValueView; -using eval::TypedCells; -using eval::Value; -using eval::ValueType; -using eval::TensorFunction; -using eval::as; -using namespace eval::tensor_function; - -namespace { - -void my_replace_type_op(eval::InterpretedFunction::State &state, uint64_t param) { - const ValueType &type = unwrap_param<ValueType>(param); - TypedCells cells = state.peek(0).cells(); - state.pop_push(state.stash.create<DenseValueView>(type, cells)); -} - -} // namespace vespalib::tensor::<unnamed> - -DenseReplaceTypeFunction::DenseReplaceTypeFunction(const eval::ValueType &result_type, - const eval::TensorFunction &child) - : eval::tensor_function::Op1(result_type, child) -{ -} - -DenseReplaceTypeFunction::~DenseReplaceTypeFunction() -{ -} - -eval::InterpretedFunction::Instruction -DenseReplaceTypeFunction::compile_self(const ValueBuilderFactory &, Stash &) const -{ - return eval::InterpretedFunction::Instruction(my_replace_type_op, wrap_param<ValueType>(result_type())); -} - -const DenseReplaceTypeFunction & -DenseReplaceTypeFunction::create_compact(const eval::ValueType &result_type, - const eval::TensorFunction &child, - Stash &stash) -{ - if (auto replace = as<DenseReplaceTypeFunction>(child)) { - return stash.create<DenseReplaceTypeFunction>(result_type, replace->child()); - } else { - return stash.create<DenseReplaceTypeFunction>(result_type, child); - } -} - -} // namespace vespalib::tensor diff --git a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h b/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h deleted file mode 100644 index 02a81ec137b..00000000000 --- a/eval/src/vespa/eval/tensor/dense/dense_simple_map_function.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include <vespa/eval/eval/tensor_function.h> - -namespace vespalib::tensor { - -/** - * Tensor function for simple map operations on dense tensors. - **/ -class DenseSimpleMapFunction : public eval::tensor_function::Map -{ -public: - using map_fun_t = vespalib::eval::operation::op1_t; - DenseSimpleMapFunction(const eval::ValueType &result_type, - const TensorFunction &child, - map_fun_t function_in); - ~DenseSimpleMapFunction() override; - bool inplace() const { return child().result_is_mutable(); } - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); -}; - -} // namespace vespalib::tensor diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp b/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp deleted file mode 100644 index 26f9194c8ce..00000000000 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "dense_tensor.h" -#include <vespa/vespalib/util/stringfmt.h> -#include <vespa/vespalib/util/exceptions.h> - -using vespalib::eval::TensorSpec; - -namespace vespalib::tensor { - -namespace { - -size_t -calcCellsSize(const eval::ValueType &type) -{ - size_t cellsSize = 1; - for (const auto &dim : type.dimensions()) { - cellsSize *= dim.size; - } - return cellsSize; -} - -template<typename T> -void -checkCellsSize(const DenseTensor<T> &arg) -{ - auto cellsSize = calcCellsSize(arg.fast_type()); - if (arg.cells().size != cellsSize) { - throw IllegalStateException(make_string("Wrong cell size, " - "expected=%zu, " - "actual=%zu", - cellsSize, - arg.cells().size)); - } - if (arg.fast_type().cell_type() != arg.cells().type) { - throw IllegalStateException(make_string("Wrong cell type, " - "expected=%u, " - "actual=%u", - (unsigned char)arg.fast_type().cell_type(), - (unsigned char)arg.cells().type)); - } -} - -} - -template <typename CT> -DenseTensor<CT>::DenseTensor(eval::ValueType type_in, - std::vector<CT> &&cells_in) - : DenseTensorView(_type), - _type(std::move(type_in)), - _cells(std::move(cells_in)) -{ - initCellsRef(TypedCells(_cells)); - checkCellsSize(*this); -} - -template <typename CT> -DenseTensor<CT>::~DenseTensor() = default; - -template <typename CT> -template <typename RCT> -bool -DenseTensor<CT>::operator==(const DenseTensor<RCT> &rhs) const -{ - if (_type != rhs._type) return false; - if (_cells.size != rhs._cells.size) return false; - for (size_t i = 0; i < _cells.size; i++) { - if (_cells[i] != rhs._cells[i]) return false; - } - return true; -} - -template class DenseTensor<float>; -template class DenseTensor<double>; - -} diff --git a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h b/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h deleted file mode 100644 index c0c238a2a89..00000000000 --- a/eval/src/vespa/eval/tensor/dense/dense_tensor_create_function.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include <vespa/eval/eval/tensor_function.h> - -namespace vespalib::tensor { - -/** - * Tensor function for creating a dense tensor from double values. - */ -class DenseTensorCreateFunction : public eval::TensorFunction -{ -public: - struct Self { - eval::ValueType result_type; - size_t result_size; - Self(const eval::ValueType &r, size_t n) : result_type(r), result_size(n) {} - }; -private: - Self _self; - std::vector<Child> _children; -public: - DenseTensorCreateFunction(const eval::ValueType &res_type, std::vector<Child> children); - ~DenseTensorCreateFunction(); - const eval::ValueType &result_type() const override { return _self.result_type; } - void push_children(std::vector<Child::CREF> &children) const override; - eval::InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override; - bool result_is_mutable() const override { return true; } - static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); -}; - -} // namespace vespalib::tensor diff --git a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp deleted file mode 100644 index 385da6d1fcd..00000000000 --- a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - - -#include "typed_dense_tensor_builder.h" - -namespace vespalib::tensor { - -using Address = DenseTensorView::Address; -using eval::ValueType; - -namespace { - -size_t -calculateCellsSize(const ValueType &type) -{ - size_t cellsSize = 1; - for (const auto &dim : type.dimensions()) { - cellsSize *= dim.size; - } - return cellsSize; -} - -} // namespace - -template <typename CT> -TypedDenseTensorBuilder<CT>::~TypedDenseTensorBuilder() = default; - -template <typename CT> -TypedDenseTensorBuilder<CT>::TypedDenseTensorBuilder(const ValueType &type_in) - : _type(type_in), - _cells(calculateCellsSize(_type)) -{ - assert(vespalib::eval::check_cell_type<CT>(_type.cell_type())); -} - -template <typename CT> -Tensor::UP -TypedDenseTensorBuilder<CT>::build() -{ - return std::make_unique<DenseTensor<CT>>(std::move(_type), std::move(_cells)); -} - -template class TypedDenseTensorBuilder<double>; -template class TypedDenseTensorBuilder<float>; - -} // namespace diff --git a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h b/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h deleted file mode 100644 index 770ea4ae5ea..00000000000 --- a/eval/src/vespa/eval/tensor/dense/typed_dense_tensor_builder.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include "dense_tensor.h" - -namespace vespalib::tensor { - -/** - * Class for building a dense tensor by inserting cell values directly into underlying array of cells. - */ -template <typename CT> -class TypedDenseTensorBuilder -{ -public: - using Address = DenseTensorView::Address; -private: - eval::ValueType _type; - std::vector<CT> _cells; - - static size_t calculateCellAddress(const Address &address, const eval::ValueType &type) { - size_t result = 0; - for (size_t i = 0; i < address.size(); ++i) { - result *= type.dimensions()[i].size; - result += address[i]; - } - return result; - } -public: - TypedDenseTensorBuilder(const eval::ValueType &type_in); - ~TypedDenseTensorBuilder(); - void insertCell(const Address &address, CT cellValue) { - insertCell(calculateCellAddress(address, _type), cellValue); - } - void insertCell(size_t index, CT cellValue) { - _cells[index] = cellValue; - } - Tensor::UP build(); -}; - -} 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 728029b0ed9..a53c0bd6a78 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -113,6 +113,13 @@ public class Flags { "Takes effect at restart of distributor and content node process", ZONE_ID, APPLICATION_ID); + public static final UnboundBooleanFlag USE_FAST_VALUE_TENSOR_IMPLEMENTATION = defineFeatureFlag( + "use-fast-value-tensor-implementation", false, + List.of("geirst"), "2020-12-02", "2021-02-01", + "Whether to use FastValueBuilderFactory as the tensor implementation on all content nodes.", + "Takes effect at restart of content node process", + ZONE_ID, APPLICATION_ID); + public static final UnboundBooleanFlag HOST_HARDENING = defineFeatureFlag( "host-hardening", false, List.of("hakonhall"), "2020-12-02", "2021-02-01", @@ -265,6 +272,13 @@ public class Flags { "Takes effect on next internal redeployment", APPLICATION_ID); + public static final UnboundDoubleFlag REINDEXER_WINDOW_SIZE_INCREMENT = defineDoubleFlag( + "reindexer-window-size-increment", 0.2, + List.of("jonmv"), "2020-12-09", "2021-02-07", + "Window size increment for dynamic throttle policy used by reindexer visitor session — more means more aggressive reindexing", + "Takes effect on (re)deployment", + APPLICATION_ID); + public static final UnboundBooleanFlag USE_POWER_OF_TWO_CHOICES_LOAD_BALANCING = defineFeatureFlag( "use-power-of-two-choices-load-balancing", false, List.of("tokle"), "2020-12-02", "2021-02-01", diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java index 5df45bbc1b1..9ac1ca2b4c1 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ApplicationMaintainer.java @@ -95,9 +95,14 @@ public abstract class ApplicationMaintainer extends NodeRepositoryMaintainer { } @Override - public void close() { - super.close(); + public void shutdown() { + super.shutdown(); this.deploymentExecutor.shutdownNow(); + } + + @Override + public void awaitShutdown() { + super.awaitShutdown(); try { // Give deployments in progress some time to complete this.deploymentExecutor.awaitTermination(1, TimeUnit.MINUTES); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java index ad835901ebf..ac33cc2441c 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.provision.maintenance; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; +import com.yahoo.concurrent.maintenance.Maintainer; import com.yahoo.config.provision.Deployer; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostLivenessTracker; @@ -18,7 +19,8 @@ import com.yahoo.vespa.orchestrator.Orchestrator; import com.yahoo.vespa.service.monitor.ServiceMonitor; import java.time.Duration; -import java.util.Optional; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * A component which sets up all the node repo maintenance jobs. @@ -27,28 +29,7 @@ import java.util.Optional; */ public class NodeRepositoryMaintenance extends AbstractComponent { - private final NodeFailer nodeFailer; - private final NodeHealthTracker nodeHealthTracker; - private final PeriodicApplicationMaintainer periodicApplicationMaintainer; - private final OperatorChangeApplicationMaintainer operatorChangeApplicationMaintainer; - private final ReservationExpirer reservationExpirer; - private final InactiveExpirer inactiveExpirer; - private final RetiredExpirer retiredExpirer; - private final FailedExpirer failedExpirer; - private final DirtyExpirer dirtyExpirer; - private final ProvisionedExpirer provisionedExpirer; - private final NodeRebooter nodeRebooter; - private final MetricsReporter metricsReporter; - private final InfrastructureProvisioner infrastructureProvisioner; - private final Optional<LoadBalancerExpirer> loadBalancerExpirer; - private final Optional<DynamicProvisioningMaintainer> dynamicProvisioningMaintainer; - private final SpareCapacityMaintainer spareCapacityMaintainer; - private final OsUpgradeActivator osUpgradeActivator; - private final Rebalancer rebalancer; - private final NodeMetricsDbMaintainer nodeMetricsDbMaintainer; - private final AutoscalingMaintainer autoscalingMaintainer; - private final ScalingSuggestionsMaintainer scalingSuggestionsMaintainer; - private final SwitchRebalancer switchRebalancer; + private final List<Maintainer> maintainers = new CopyOnWriteArrayList<>(); @SuppressWarnings("unused") @Inject @@ -59,60 +40,45 @@ public class NodeRepositoryMaintenance extends AbstractComponent { MetricsFetcher metricsFetcher, MetricsDb metricsDb) { DefaultTimes defaults = new DefaultTimes(zone, deployer); - nodeFailer = new NodeFailer(deployer, nodeRepository, defaults.failGrace, defaults.nodeFailerInterval, orchestrator, defaults.throttlePolicy, metric); - nodeHealthTracker = new NodeHealthTracker(hostLivenessTracker, serviceMonitor, nodeRepository, defaults.nodeFailureStatusUpdateInterval, metric); - periodicApplicationMaintainer = new PeriodicApplicationMaintainer(deployer, metric, nodeRepository, - defaults.redeployMaintainerInterval, defaults.periodicRedeployInterval, flagSource); - operatorChangeApplicationMaintainer = new OperatorChangeApplicationMaintainer(deployer, metric, nodeRepository, defaults.operatorChangeRedeployInterval); - reservationExpirer = new ReservationExpirer(nodeRepository, defaults.reservationExpiry, metric); - retiredExpirer = new RetiredExpirer(nodeRepository, orchestrator, deployer, metric, defaults.retiredInterval, defaults.retiredExpiry); - inactiveExpirer = new InactiveExpirer(nodeRepository, defaults.inactiveExpiry, metric); - failedExpirer = new FailedExpirer(nodeRepository, zone, defaults.failedExpirerInterval, metric); - dirtyExpirer = new DirtyExpirer(nodeRepository, defaults.dirtyExpiry, metric); - provisionedExpirer = new ProvisionedExpirer(nodeRepository, defaults.provisionedExpiry, metric); - nodeRebooter = new NodeRebooter(nodeRepository, flagSource, metric); - metricsReporter = new MetricsReporter(nodeRepository, metric, orchestrator, serviceMonitor, periodicApplicationMaintainer::pendingDeployments, defaults.metricsInterval); - infrastructureProvisioner = new InfrastructureProvisioner(nodeRepository, infraDeployer, defaults.infrastructureProvisionInterval, metric); - loadBalancerExpirer = provisionServiceProvider.getLoadBalancerService(nodeRepository).map(lbService -> - new LoadBalancerExpirer(nodeRepository, defaults.loadBalancerExpirerInterval, lbService, metric)); - dynamicProvisioningMaintainer = provisionServiceProvider.getHostProvisioner().map(hostProvisioner -> - new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, flagSource, metric)); - spareCapacityMaintainer = new SpareCapacityMaintainer(deployer, nodeRepository, metric, defaults.spareCapacityMaintenanceInterval); - osUpgradeActivator = new OsUpgradeActivator(nodeRepository, defaults.osUpgradeActivatorInterval, metric); - rebalancer = new Rebalancer(deployer, nodeRepository, metric, defaults.rebalancerInterval); - nodeMetricsDbMaintainer = new NodeMetricsDbMaintainer(nodeRepository, metricsFetcher, metricsDb, defaults.nodeMetricsCollectionInterval, metric); - autoscalingMaintainer = new AutoscalingMaintainer(nodeRepository, metricsDb, deployer, metric, defaults.autoscalingInterval); - scalingSuggestionsMaintainer = new ScalingSuggestionsMaintainer(nodeRepository, metricsDb, defaults.scalingSuggestionsInterval, metric); - switchRebalancer = new SwitchRebalancer(nodeRepository, defaults.switchRebalancerInterval, metric, deployer); - + PeriodicApplicationMaintainer periodicApplicationMaintainer = new PeriodicApplicationMaintainer(deployer, metric, nodeRepository, defaults.redeployMaintainerInterval, + defaults.periodicRedeployInterval, flagSource); + InfrastructureProvisioner infrastructureProvisioner = new InfrastructureProvisioner(nodeRepository, infraDeployer, defaults.infrastructureProvisionInterval, metric); + maintainers.add(periodicApplicationMaintainer); + maintainers.add(infrastructureProvisioner); + + maintainers.add(new NodeFailer(deployer, nodeRepository, defaults.failGrace, defaults.nodeFailerInterval, orchestrator, defaults.throttlePolicy, metric)); + maintainers.add(new NodeHealthTracker(hostLivenessTracker, serviceMonitor, nodeRepository, defaults.nodeFailureStatusUpdateInterval, metric)); + maintainers.add(new OperatorChangeApplicationMaintainer(deployer, metric, nodeRepository, defaults.operatorChangeRedeployInterval)); + maintainers.add(new ReservationExpirer(nodeRepository, defaults.reservationExpiry, metric)); + maintainers.add(new RetiredExpirer(nodeRepository, orchestrator, deployer, metric, defaults.retiredInterval, defaults.retiredExpiry)); + maintainers.add(new InactiveExpirer(nodeRepository, defaults.inactiveExpiry, metric)); + maintainers.add(new FailedExpirer(nodeRepository, zone, defaults.failedExpirerInterval, metric)); + maintainers.add(new DirtyExpirer(nodeRepository, defaults.dirtyExpiry, metric)); + maintainers.add(new ProvisionedExpirer(nodeRepository, defaults.provisionedExpiry, metric)); + maintainers.add(new NodeRebooter(nodeRepository, flagSource, metric)); + maintainers.add(new MetricsReporter(nodeRepository, metric, orchestrator, serviceMonitor, periodicApplicationMaintainer::pendingDeployments, defaults.metricsInterval)); + maintainers.add(new SpareCapacityMaintainer(deployer, nodeRepository, metric, defaults.spareCapacityMaintenanceInterval)); + maintainers.add(new OsUpgradeActivator(nodeRepository, defaults.osUpgradeActivatorInterval, metric)); + maintainers.add(new Rebalancer(deployer, nodeRepository, metric, defaults.rebalancerInterval)); + maintainers.add(new NodeMetricsDbMaintainer(nodeRepository, metricsFetcher, metricsDb, defaults.nodeMetricsCollectionInterval, metric)); + maintainers.add(new AutoscalingMaintainer(nodeRepository, metricsDb, deployer, metric, defaults.autoscalingInterval)); + maintainers.add(new ScalingSuggestionsMaintainer(nodeRepository, metricsDb, defaults.scalingSuggestionsInterval, metric)); + maintainers.add(new SwitchRebalancer(nodeRepository, defaults.switchRebalancerInterval, metric, deployer)); + + provisionServiceProvider.getLoadBalancerService(nodeRepository) + .map(lbService -> new LoadBalancerExpirer(nodeRepository, defaults.loadBalancerExpirerInterval, lbService, metric)) + .ifPresent(maintainers::add); + provisionServiceProvider.getHostProvisioner() + .map(hostProvisioner -> new DynamicProvisioningMaintainer(nodeRepository, defaults.dynamicProvisionerInterval, hostProvisioner, flagSource, metric)) + .ifPresent(maintainers::add); // The DuperModel is filled with infrastructure applications by the infrastructure provisioner, so explicitly run that now infrastructureProvisioner.maintainButThrowOnException(); } @Override public void deconstruct() { - nodeFailer.close(); - nodeHealthTracker.close(); - periodicApplicationMaintainer.close(); - operatorChangeApplicationMaintainer.close(); - reservationExpirer.close(); - inactiveExpirer.close(); - retiredExpirer.close(); - failedExpirer.close(); - dirtyExpirer.close(); - nodeRebooter.close(); - spareCapacityMaintainer.close(); - provisionedExpirer.close(); - metricsReporter.close(); - infrastructureProvisioner.close(); - loadBalancerExpirer.ifPresent(NodeRepositoryMaintainer::close); - dynamicProvisioningMaintainer.ifPresent(NodeRepositoryMaintainer::close); - osUpgradeActivator.close(); - rebalancer.close(); - nodeMetricsDbMaintainer.close(); - autoscalingMaintainer.close(); - scalingSuggestionsMaintainer.close(); - switchRebalancer.close(); + maintainers.forEach(Maintainer::shutdown); + maintainers.forEach(Maintainer::awaitShutdown); } private static class DefaultTimes { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java index 55a183c8ec1..cd188bc017f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/PeriodicApplicationMaintainerTest.java @@ -51,7 +51,7 @@ public class PeriodicApplicationMaintainerTest { @After public void after() { - this.fixture.maintainer.close(); + this.fixture.maintainer.awaitShutdown(); } @Test(timeout = 60_000) diff --git a/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp b/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp index 5a5f5cb46d6..170885d1d99 100644 --- a/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp +++ b/searchcore/src/apps/vespa-feed-bm/vespa_feed_bm.cpp @@ -269,6 +269,7 @@ class BMParams { uint32_t _update_passes; uint32_t _remove_passes; uint32_t _rpc_network_threads; + uint32_t _rpc_events_before_wakeup; uint32_t _rpc_targets_per_node; uint32_t _response_threads; uint32_t _max_pending; @@ -292,7 +293,8 @@ public: _put_passes(2), _update_passes(1), _remove_passes(2), - _rpc_network_threads(1), // Same default as in stor-communicationmanager.def + _rpc_network_threads(1), // Same default as previous in stor-communicationmanager.def + _rpc_events_before_wakeup(1), // Same default as in stor-communicationmanager.def _rpc_targets_per_node(1), // Same default as in stor-communicationmanager.def _response_threads(2), // Same default as in stor-filestor.def _max_pending(1000), @@ -318,6 +320,7 @@ public: uint32_t get_update_passes() const { return _update_passes; } uint32_t get_remove_passes() const { return _remove_passes; } uint32_t get_rpc_network_threads() const { return _rpc_network_threads; } + uint32_t get_rpc_events_before_wakup() const { return _rpc_events_before_wakeup; } uint32_t get_rpc_targets_per_node() const { return _rpc_targets_per_node; } uint32_t get_response_threads() const { return _response_threads; } bool get_enable_distributor() const { return _enable_distributor; } @@ -336,6 +339,7 @@ public: void set_update_passes(uint32_t update_passes_in) { _update_passes = update_passes_in; } void set_remove_passes(uint32_t remove_passes_in) { _remove_passes = remove_passes_in; } void set_rpc_network_threads(uint32_t threads_in) { _rpc_network_threads = threads_in; } + void set_rpc_events_before_wakeup(uint32_t value) { _rpc_events_before_wakeup = value; } void set_rpc_targets_per_node(uint32_t targets_in) { _rpc_targets_per_node = targets_in; } void set_response_threads(uint32_t threads_in) { _response_threads = threads_in; } void set_enable_distributor(bool value) { _enable_distributor = value; } @@ -491,6 +495,7 @@ struct MyStorageConfig make_slobroks_config(slobroks, slobrok_port); stor_communicationmanager.useDirectStorageapiRpc = true; stor_communicationmanager.rpc.numNetworkThreads = params.get_rpc_network_threads(); + stor_communicationmanager.rpc.eventsBeforeWakeup = params.get_rpc_events_before_wakup(); stor_communicationmanager.rpc.numTargetsPerNode = params.get_rpc_targets_per_node(); stor_communicationmanager.mbusport = mbus_port; stor_communicationmanager.rpcport = rpc_port; @@ -878,7 +883,8 @@ PersistenceProviderFixture::start_service_layer(const BMParams& params) _service_layer->getNode().waitUntilInitialized(); LOG(info, "start rpc client shared resources"); config::ConfigUri client_config_uri("bm-rpc-client", _config_context); - _rpc_client_shared_rpc_resources = std::make_unique<SharedRpcResources>(client_config_uri, _rpc_client_port, 100); + _rpc_client_shared_rpc_resources = std::make_unique<SharedRpcResources> + (client_config_uri, _rpc_client_port, 100, params.get_rpc_events_before_wakup()); _rpc_client_shared_rpc_resources->start_server_and_register_slobrok("bm-rpc-client"); wait_slobrok("storage/cluster.storage/storage/0/default"); wait_slobrok("storage/cluster.storage/storage/0"); @@ -1369,6 +1375,7 @@ App::usage() "[--put-passes put-passes]\n" "[--update-passes update-passes]\n" "[--remove-passes remove-passes]\n" + "[--rpc-events-before-wakeup events]\n" "[--rpc-network-threads threads]\n" "[--rpc-targets-per-node targets]\n" "[--response-threads threads]\n" @@ -1399,6 +1406,7 @@ App::get_options() { "put-passes", 1, nullptr, 0 }, { "remove-passes", 1, nullptr, 0 }, { "response-threads", 1, nullptr, 0 }, + { "rpc-events-before-wakeup", 1, nullptr, 0 }, { "rpc-network-threads", 1, nullptr, 0 }, { "rpc-targets-per-node", 1, nullptr, 0 }, { "skip-get-spi-bucket-info", 0, nullptr, 0 }, @@ -1420,6 +1428,7 @@ App::get_options() LONGOPT_PUT_PASSES, LONGOPT_REMOVE_PASSES, LONGOPT_RESPONSE_THREADS, + LONGOPT_RPC_EVENTS_BEFORE_WAKEUP, LONGOPT_RPC_NETWORK_THREADS, LONGOPT_RPC_TARGETS_PER_NODE, LONGOPT_SKIP_GET_SPI_BUCKET_INFO, @@ -1471,6 +1480,9 @@ App::get_options() case LONGOPT_RESPONSE_THREADS: _bm_params.set_response_threads(atoi(opt_argument)); break; + case LONGOPT_RPC_EVENTS_BEFORE_WAKEUP: + _bm_params.set_rpc_events_before_wakeup(atoi(opt_argument)); + break; case LONGOPT_RPC_NETWORK_THREADS: _bm_params.set_rpc_network_threads(atoi(opt_argument)); break; diff --git a/searchlib/src/vespa/searchlib/features/onnx_feature.cpp b/searchlib/src/vespa/searchlib/features/onnx_feature.cpp index c3655e8ed2a..87e5ef2a5c2 100644 --- a/searchlib/src/vespa/searchlib/features/onnx_feature.cpp +++ b/searchlib/src/vespa/searchlib/features/onnx_feature.cpp @@ -20,7 +20,7 @@ using search::fef::ParameterList; using vespalib::Stash; using vespalib::eval::ValueType; using vespalib::make_string_short::fmt; -using vespalib::tensor::Onnx; +using vespalib::eval::Onnx; namespace search::features { diff --git a/searchlib/src/vespa/searchlib/features/onnx_feature.h b/searchlib/src/vespa/searchlib/features/onnx_feature.h index f5a94cc5345..5a45b26f1f6 100644 --- a/searchlib/src/vespa/searchlib/features/onnx_feature.h +++ b/searchlib/src/vespa/searchlib/features/onnx_feature.h @@ -12,7 +12,7 @@ namespace search::features { **/ class OnnxBlueprint : public fef::Blueprint { private: - using Onnx = vespalib::tensor::Onnx; + using Onnx = vespalib::eval::Onnx; std::unique_ptr<Onnx> _model; Onnx::WireInfo _wire_info; public: diff --git a/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp b/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp index e8401914abf..320c55f9998 100644 --- a/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp +++ b/storage/src/tests/distributor/read_for_write_visitor_operation_test.cpp @@ -8,6 +8,8 @@ #include <vespa/storage/distributor/operations/external/visitoroperation.h> #include <vespa/storage/distributor/distributor.h> #include <vespa/storage/distributor/distributormetricsset.h> +#include <vespa/storage/distributor/pendingmessagetracker.h> +#include <vespa/storageapi/message/bucket.h> #include <vespa/storageapi/message/persistence.h> #include <vespa/storageapi/message/visitor.h> #include <tests/distributor/distributortestutil.h> @@ -25,6 +27,11 @@ Bucket default_bucket(BucketId id) { return Bucket(document::FixedBucketSpaces::default_space(), id); } +api::StorageMessageAddress make_storage_address(uint16_t node) { + static vespalib::string _storage("storage"); + return {&_storage, lib::NodeType::STORAGE, node}; +} + } struct ReadForWriteVisitorOperationStarterTest : Test, DistributorTestUtil { @@ -46,6 +53,7 @@ struct ReadForWriteVisitorOperationStarterTest : Test, DistributorTestUtil { createLinks(); setupDistributor(1, 1, "version:1 distributor:1 storage:1"); _op_owner = std::make_unique<OperationOwner>(_sender, getClock()); + _sender.setPendingMessageTracker(getDistributor().getPendingMessageTracker()); addNodesToBucketDB(_sub_bucket, "0=1/2/3/t"); } @@ -81,6 +89,7 @@ struct ReadForWriteVisitorOperationStarterTest : Test, DistributorTestUtil { TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_that_fails_precondition_checks_is_immediately_failed) { auto op = create_rfw_op(create_nested_visitor_op(false)); _op_owner->start(op, OperationStarter::Priority(120)); + ASSERT_EQ("", _sender.getCommands(true)); EXPECT_EQ("CreateVisitorReply(last=BucketId(0x0000000000000000)) " "ReturnCode(ILLEGAL_PARAMETERS, No buckets in CreateVisitorCommand for visitor 'foo')", _sender.getLastReply()); @@ -92,6 +101,21 @@ TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_immediately_started_if_n ASSERT_EQ("Visitor Create => 0", _sender.getCommands(true)); } +TEST_F(ReadForWriteVisitorOperationStarterTest, visitor_is_bounced_if_merge_pending_for_bucket) { + auto op = create_rfw_op(create_nested_visitor_op(true)); + std::vector<api::MergeBucketCommand::Node> nodes({{0, false}, {1, false}}); + auto merge = std::make_shared<api::MergeBucketCommand>(default_bucket(_sub_bucket), + std::move(nodes), + api::Timestamp(123456)); + merge->setAddress(make_storage_address(0)); + getDistributor().getPendingMessageTracker().insert(merge); + _op_owner->start(op, OperationStarter::Priority(120)); + ASSERT_EQ("", _sender.getCommands(true)); + EXPECT_EQ("CreateVisitorReply(last=BucketId(0x0000000000000000)) " + "ReturnCode(BUSY, A merge operation is pending for this bucket)", + _sender.getLastReply()); +} + namespace { struct ConcurrentMutationFixture { diff --git a/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp b/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp index 8b009e02f28..a39ee819f64 100644 --- a/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp +++ b/storage/src/tests/storageserver/rpc/cluster_controller_rpc_api_service_test.cpp @@ -57,7 +57,7 @@ struct FixtureBase { config.getConfig("stor-server").set("node_index", "1"); addSlobrokConfig(config, slobrok); - shared_rpc_resources = std::make_unique<SharedRpcResources>(config.getConfigId(), 0, 1); + shared_rpc_resources = std::make_unique<SharedRpcResources>(config.getConfigId(), 0, 1, 1); cc_service = std::make_unique<ClusterControllerApiRpcService>(dispatcher, *shared_rpc_resources); shared_rpc_resources->start_server_and_register_slobrok("my_cool_rpc_test"); } diff --git a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp index d1cdd649787..0b33da39c41 100644 --- a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp +++ b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp @@ -119,7 +119,7 @@ public: cfg.set("is_distributor", is_distributor ? "true" : "false"); addSlobrokConfig(_config, slobrok); - _shared_rpc_resources = std::make_unique<SharedRpcResources>(_config.getConfigId(), 0, 1); + _shared_rpc_resources = std::make_unique<SharedRpcResources>(_config.getConfigId(), 0, 1, 1); // TODO make codec provider into interface so we can test decode-failures more easily? _codec_provider = std::make_unique<MessageCodecProvider>(_doc_type_repo); } diff --git a/storage/src/vespa/storage/common/CMakeLists.txt b/storage/src/vespa/storage/common/CMakeLists.txt index efbd62a45a0..741d97f78ef 100644 --- a/storage/src/vespa/storage/common/CMakeLists.txt +++ b/storage/src/vespa/storage/common/CMakeLists.txt @@ -2,7 +2,6 @@ vespa_add_library(storage_common OBJECT SOURCES bucketmessages.cpp - bucketoperationlogger.cpp content_bucket_space.cpp content_bucket_space_repo.cpp distributorcomponent.cpp diff --git a/storage/src/vespa/storage/common/bucketoperationlogger.cpp b/storage/src/vespa/storage/common/bucketoperationlogger.cpp deleted file mode 100644 index 905b704409f..00000000000 --- a/storage/src/vespa/storage/common/bucketoperationlogger.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "bucketoperationlogger.h" -#include <vespa/storage/bucketdb/storbucketdb.h> -#include <vespa/storage/bucketdb/bucketcopy.h> - -#include <vespa/storageapi/buckets/bucketinfo.h> -#include <vespa/storageframework/defaultimplementation/clock/realclock.h> -#include <vespa/vespalib/util/backtrace.h> -#include <vespa/vespalib/stllike/asciistream.h> - -#ifdef ENABLE_BUCKET_OPERATION_LOGGING -#include <vespa/log/log.h> -LOG_SETUP(".debuglogger"); - -namespace storage { - -namespace debug { - -BucketOperationLogger opLogger; - -void -BucketOperationLogger::log(const document::BucketId& id, - const vespalib::string& text, - bool requireLock, - State::LockUpdate lockUpdate) -{ - LogEntry entry; - framework::defaultimplementation::RealClock rclock; - entry._frameCount = vespalib::getStackTraceFrames(entry._stackFrames, MAX_STACK_FRAMES); - entry._text = text; - entry._timestamp = rclock.getTimeInMicros(); - entry._threadId = FastOS_Thread::GetCurrentThreadId() & 0xffff; - uint32_t lockedByThread = 0; - bool hasError = false; - - { - std::lock_guard<std:.mutex> guard(_logLock); - BucketMapType::iterator i = _bucketMap.lower_bound(id); - if (i != _bucketMap.end() && i->first == id) { - if (i->second._history.size() >= MAX_ENTRIES) { - i->second._history.pop_front(); - } - i->second._history.push_back(entry); - if (lockUpdate == State::BUCKET_LOCKED) { - if (i->second._lockedByThread != 0) { - LOG(warning, "Attempting to acquire lock, but lock " - "is already held by thread %u", i->second._lockedByThread); - hasError = true; - } - i->second._lockedByThread = entry._threadId; - } - lockedByThread = i->second._lockedByThread; - if (lockUpdate == State::BUCKET_UNLOCKED) { - if (i->second._lockedByThread == 0) { - LOG(warning, "Attempting to release lock, but lock " - "is not held"); - hasError = true; - } - i->second._lockedByThread = 0; - } - } else { - State addState; - addState._lockedByThread = 0; - addState._history.push_back(entry); - if (lockUpdate == State::BUCKET_LOCKED) { - addState._lockedByThread = entry._threadId; - } else if (lockUpdate == State::BUCKET_UNLOCKED) { - LOG(warning, "Attempting to release lock, but lock " - "is not held"); - hasError = true; - } - _bucketMap.insert(i, BucketMapType::value_type(id, addState)); - } - } - - if (requireLock && !lockedByThread) { - LOG(warning, "Operation '%s' requires lock, but lock is " - "not registered as held", text.c_str()); - hasError = true; - } - if (hasError) { - LOG(warning, "%s", getHistory(id).c_str()); - } -} - -namespace { - -// Must hold logger lock -template <typename LineHandler> -void -processHistory(const BucketOperationLogger& opLogger, - const document::BucketId& id, LineHandler& handler) -{ - BucketOperationLogger::BucketMapType::const_iterator i( - opLogger._bucketMap.find(id)); - if (i == opLogger._bucketMap.end()) { - vespalib::asciistream ss; - ss << "No history recorded for bucket '" - << id.toString() << "'"; - handler(ss.str()); - return; - } - - { - vespalib::asciistream ss; - ss << "Showing last " << i->second._history.size() << " operations on " - << "bucket " << id.toString() << " (newest first):"; - handler(ss.str()); - } - for (BucketOperationLogger::State::LogEntryListType::const_reverse_iterator j( - i->second._history.rbegin()), end(i->second._history.rend()); - j != end; ++j) - { - vespalib::asciistream ss; - ss << storage::framework::getTimeString( - j->_timestamp.getTime(), - storage::framework::DATETIME_WITH_MICROS) - << " " << j->_threadId << " " - << j->_text << ". " - << vespalib::getStackTrace(1, j->_stackFrames, j->_frameCount); - handler(ss.str()); - } -} - -struct LogWarnAppender -{ - void operator()(const vespalib::string& line) - { - LOG(warning, "%s", line.c_str()); - } -}; - -struct LogStringBuilder -{ - vespalib::asciistream ss; - void operator()(const vespalib::string& line) - { - ss << line << "\n"; - } -}; - -} - -void -BucketOperationLogger::dumpHistoryToLog(const document::BucketId& id) const -{ - LogWarnAppender handler; - std::lock_guard<std::mutex> guard(_logLock); - processHistory(*this, id, handler); -} - -vespalib::string -BucketOperationLogger::getHistory(const document::BucketId& id) const -{ - LogStringBuilder handler; - std::lock_guard<std::mutex> lock(_logLock); - processHistory(*this, id, handler); - return handler.ss.str(); -} - -vespalib::string -BucketOperationLogger::searchBucketHistories( - const vespalib::string& sub, - const vespalib::string& urlPrefix) const -{ - vespalib::asciistream ss; - ss << "<ul>\n"; - // This may block for a while... Assuming such searches run when system - // is otherwise idle. - std::lock_guard<std::mutex> guard(_logLock); - for (BucketMapType::const_iterator - bIt(_bucketMap.begin()), bEnd(_bucketMap.end()); - bIt != bEnd; ++bIt) - { - for (State::LogEntryListType::const_iterator - sIt(bIt->second._history.begin()), - sEnd(bIt->second._history.end()); - sIt != sEnd; ++sIt) - { - if (sIt->_text.find(sub.c_str()) != vespalib::string::npos) { - ss << "<li><a href=\"" << urlPrefix - << "0x" << vespalib::hex << bIt->first.getId() - << vespalib::dec << "\">" << bIt->first.toString() - << "</a>:\n"; - ss << sIt->_text << "</li>\n"; - } - } - } - ss << "</ul>\n"; - return ss.str(); -} - -BucketOperationLogger& -BucketOperationLogger::getInstance() -{ - return opLogger; -} - -// Storage node -void logBucketDbInsert(uint64_t key, const bucketdb::StorageBucketInfo& entry) -{ - LOG_BUCKET_OPERATION_NO_LOCK( - document::BucketId(document::BucketId::keyToBucketId(key)), - vespalib::make_string( - "bucketdb insert Bucket(crc=%x, docs=%u, size=%u, " - "metacount=%u, usedfilesize=%u, ready=%s, " - "active=%s, lastModified=%zu) disk=%u", - entry.info.getChecksum(), - entry.info.getDocumentCount(), - entry.info.getTotalDocumentSize(), - entry.info.getMetaCount(), - entry.info.getUsedFileSize(), - (entry.info.isReady() ? "true" : "false"), - (entry.info.isActive() ? "true" : "false"), - entry.info.getLastModified(), - entry.disk)); -} - -void logBucketDbErase(uint64_t key, const TypeTag<bucketdb::StorageBucketInfo>&) -{ - LOG_BUCKET_OPERATION_NO_LOCK( - document::BucketId(document::BucketId::keyToBucketId(key)), - "bucketdb erase"); -} - -// Distributor -void -checkAllConsistentNodesImpliesTrusted( - const document::BucketId& bucket, - const BucketInfo& entry) -{ - // If all copies are consistent, they should also be trusted - if (entry.validAndConsistent() && entry.getNodeCount() > 1) { - for (std::size_t i = 0; i < entry.getNodeCount(); ++i) { - const BucketCopy& copy = entry.getNodeRef(i); - if (copy.trusted() == false) { - LOG(warning, "Bucket DB entry %s for %s is consistent, but " - "contains non-trusted copy %s", entry.toString().c_str(), - bucket.toString().c_str(), copy.toString().c_str()); - DUMP_LOGGED_BUCKET_OPERATIONS(bucket); - } - } - } -} - -std::size_t -firstTrustedNode(const BucketInfo& entry) -{ - for (std::size_t i = 0; i < entry.getNodeCount(); ++i) { - const distributor::BucketCopy& copy = entry.getNodeRef(i); - if (copy.trusted()) { - return i; - } - } - return std::numeric_limits<std::size_t>::max(); -} - -void -checkNotInSyncImpliesNotTrusted( - const document::BucketId& bucket, - const BucketInfo& entry) -{ - // If there are copies out of sync, different copies should not - // be set to trusted - std::size_t trustedNode = firstTrustedNode(entry); - if (trustedNode != std::numeric_limits<std::size_t>::max()) { - // Ensure all other trusted copies match the metadata of the - // first trusted bucket - const BucketCopy& trustedCopy = entry.getNodeRef(trustedNode); - for (std::size_t i = 0; i < entry.getNodeCount(); ++i) { - if (i == trustedNode) { - continue; - } - const BucketCopy& copy = entry.getNodeRef(i); - const api::BucketInfo& copyInfo = copy.getBucketInfo(); - const api::BucketInfo& trustedInfo = trustedCopy.getBucketInfo(); - if (copy.trusted() - && ((copyInfo.getChecksum() != trustedInfo.getChecksum()))) - //|| (copyInfo.getTotalDocumentSize() != trustedInfo.getTotalDocumentSize()))) - { - LOG(warning, "Bucket DB entry %s for %s has trusted node copy " - "with differing metadata %s", entry.toString().c_str(), - bucket.toString().c_str(), copy.toString().c_str()); - DUMP_LOGGED_BUCKET_OPERATIONS(bucket); - } - } - } -} - -void -checkInvalidImpliesNotTrusted( - const document::BucketId& bucket, - const BucketInfo& entry) -{ - for (std::size_t i = 0; i < entry.getNodeCount(); ++i) { - const BucketCopy& copy = entry.getNodeRef(i); - if (!copy.valid() && copy.trusted()) { - LOG(warning, "Bucket DB entry %s for %s has invalid copy %s " - "marked as trusted", entry.toString().c_str(), - bucket.toString().c_str(), copy.toString().c_str()); - DUMP_LOGGED_BUCKET_OPERATIONS(bucket); - } - } -} - -void -logBucketDbInsert(uint64_t key, const BucketInfo& entry) -{ - document::BucketId bucket(document::BucketId::keyToBucketId(key)); - LOG_BUCKET_OPERATION_NO_LOCK( - bucket, vespalib::make_string( - "bucketdb insert of %s", entry.toString().c_str())); - // Do some sanity checking of the inserted entry - checkAllConsistentNodesImpliesTrusted(bucket, entry); - checkNotInSyncImpliesNotTrusted(bucket, entry); - checkInvalidImpliesNotTrusted(bucket, entry); -} - -void -logBucketDbErase(uint64_t key, const TypeTag<BucketInfo>&) -{ - document::BucketId bucket(document::BucketId::keyToBucketId(key)); - LOG_BUCKET_OPERATION_NO_LOCK(bucket, "bucketdb erase"); -} - -} // namespace debug - -} // namespace storage - -#endif // ENABLE_BUCKET_OPERATION_LOGGING diff --git a/storage/src/vespa/storage/common/bucketoperationlogger.h b/storage/src/vespa/storage/common/bucketoperationlogger.h deleted file mode 100644 index af4b539a4c8..00000000000 --- a/storage/src/vespa/storage/common/bucketoperationlogger.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#pragma once - -#include <vespa/vespalib/stllike/string.h> -#include <vespa/document/bucket/bucketid.h> -#include <map> -#include <list> -#include <mutex> - -/** - * Enable this to log most slotfile operations (such as all mutations) as - * well as common bucket operations such as splitting, joining and bucket db - * updates. Each log entry contains the stack frames for the logging callsite, - * a timestamp, the ID of the thread performing the operation as well as a - * message. The stack trace is cheaply acquired and does thus not affect runtime - * performance to a great degree. Expect some overhead from the logging itself - * since it requires a global mutex around the log state. - * - * All relevant bucket/slotfile operations are checked to ensure that the - * filestor lock is held during the operation and that the thread performing - * it is the same as the one that acquired the lock. - * - * Similarly, code has been added to distributor bucket database and ideal - * state handling to log these. - * - * In the case of an invariant violation (such as a locking bug), the last - * BUCKET_OPERATION_LOG_ENTRIES log entries will be dumped to the vespalog. - * Code may also dump the logged history for a bucket by calling - * DUMP_LOGGED_BUCKET_OPERATIONS(bucketid) - */ -//#define ENABLE_BUCKET_OPERATION_LOGGING -#define BUCKET_OPERATION_LOG_ENTRIES 40 - -#ifdef ENABLE_BUCKET_OPERATION_LOGGING -#define LOG_BUCKET_OPERATION_NO_LOCK(bucket, string) \ -debug::BucketOperationLogger::getInstance().log( \ - (bucket), (string), false) - -#define LOG_BUCKET_OPERATION(bucket, string) \ -debug::BucketOperationLogger::getInstance().log( \ - (bucket), (string), true) - -#define LOG_BUCKET_OPERATION_SPECIFY_LOCKED(bucket, string, require_locked) \ -debug::BucketOperationLogger::getInstance().log( \ - (bucket), (string), (require_locked)) - -#define LOG_BUCKET_OPERATION_SET_LOCK_STATE(bucket, string, require_locked, new_state) \ -debug::BucketOperationLogger::getInstance().log( \ - (bucket), (string), (require_locked), (new_state)) - -#define DUMP_LOGGED_BUCKET_OPERATIONS(bucket) \ - debug::BucketOperationLogger::getInstance().dumpHistoryToLog(bucket) - -namespace storage { - -// Debug stuff for tracking the last n operations to buckets -namespace debug { - -struct BucketOperationLogger -{ - static const std::size_t MAX_ENTRIES = BUCKET_OPERATION_LOG_ENTRIES; - static const std::size_t MAX_STACK_FRAMES = 25; - - struct LogEntry - { - void* _stackFrames[MAX_STACK_FRAMES]; - vespalib::string _text; - framework::MicroSecTime _timestamp; - int _frameCount; - int32_t _threadId; - }; - - struct State - { - typedef std::list<LogEntry> LogEntryListType; - enum LockUpdate - { - NO_UPDATE = 0, - BUCKET_LOCKED = 1, - BUCKET_UNLOCKED = 2 - }; - LogEntryListType _history; - uint32_t _lockedByThread; - }; - - typedef std::map<document::BucketId, State> BucketMapType; - - std::mutex _logLock; - BucketMapType _bucketMap; - - void log(const document::BucketId& id, - const vespalib::string& text, - bool requireLock = true, - State::LockUpdate update = State::NO_UPDATE); - - vespalib::string getHistory(const document::BucketId& id) const; - void dumpHistoryToLog(const document::BucketId& id) const; - //void dumpAllBucketHistoriesToFile(const vespalib::string& filename) const; - /** - * Search through all bucket history entry descriptions to find substring, - * creating a itemized list of buckets containing it as well as a preview. - * @param sub the exact substring to search for. - * @param urlPrefix the URL used for creating bucket links. - */ - vespalib::string searchBucketHistories(const vespalib::string& sub, - const vespalib::string& urlPrefix) const; - static BucketOperationLogger& getInstance(); -}; - -} - -} - -#else - -#define LOG_BUCKET_OPERATION_NO_LOCK(bucket, string) -#define LOG_BUCKET_OPERATION(bucket, string) -#define LOG_BUCKET_OPERATION_SPECIFY_LOCKED(bucket, string, require_locked) -#define DUMP_LOGGED_BUCKET_OPERATIONS(bucket) -#define LOG_BUCKET_OPERATION_SET_LOCK_STATE(bucket, string, require_locked, new_state) - -#endif - diff --git a/storage/src/vespa/storage/config/stor-communicationmanager.def b/storage/src/vespa/storage/config/stor-communicationmanager.def index 8f24646367f..d674ee96aa3 100644 --- a/storage/src/vespa/storage/config/stor-communicationmanager.def +++ b/storage/src/vespa/storage/config/stor-communicationmanager.def @@ -63,6 +63,9 @@ use_direct_storageapi_rpc bool default=false ## The number of network (FNET) threads used by the shared rpc resource. rpc.num_network_threads int default=2 restart +## The number of events in the queue of a network (FNET) thread before it is woken up. +rpc.events_before_wakeup int default=1 restart + ## The number of (FNET) RPC targets to use per node in the cluster. ## ## The bucket id associated with a message is used to select the RPC target. diff --git a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp index d7fa770ef12..a8c4e7c3544 100644 --- a/storage/src/vespa/storage/distributor/bucketdbupdater.cpp +++ b/storage/src/vespa/storage/distributor/bucketdbupdater.cpp @@ -8,7 +8,6 @@ #include "distributormetricsset.h" #include "simpleclusterinformation.h" #include <vespa/document/bucket/fixed_bucket_spaces.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storageapi/message/persistence.h> #include <vespa/storageapi/message/removelocation.h> #include <vespa/vespalib/util/xmlstream.h> diff --git a/storage/src/vespa/storage/distributor/distributorcomponent.cpp b/storage/src/vespa/storage/distributor/distributorcomponent.cpp index dde5281a15f..86c98cc7b78 100644 --- a/storage/src/vespa/storage/distributor/distributorcomponent.cpp +++ b/storage/src/vespa/storage/distributor/distributorcomponent.cpp @@ -4,7 +4,6 @@ #include "distributor_bucket_space.h" #include "pendingmessagetracker.h" #include <vespa/document/select/parser.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/vdslib/state/cluster_state_bundle.h> diff --git a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp index 1e87172e870..5ebf20138a4 100644 --- a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp +++ b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.cpp @@ -2,6 +2,7 @@ #include "read_for_write_visitor_operation.h" #include "visitoroperation.h" +#include <vespa/storage/distributor/distributormessagesender.h> #include <vespa/storage/distributor/pendingmessagetracker.h> #include <vespa/storage/distributor/operationowner.h> #include <cassert> @@ -40,6 +41,11 @@ void ReadForWriteVisitorOperationStarter::onStart(DistributorMessageSender& send assert(_visitor_op->has_sent_reply()); return; } + if (bucket_has_pending_merge(*maybe_bucket, sender.getPendingMessageTracker())) { + LOG(debug, "A merge is pending for bucket %s, failing visitor", maybe_bucket->toString().c_str()); + _visitor_op->fail_with_merge_pending(sender); + return; + } auto bucket_handle = _operation_sequencer.try_acquire(*maybe_bucket); if (!bucket_handle.valid()) { LOG(debug, "An operation is already pending for bucket %s, failing visitor", @@ -71,4 +77,26 @@ void ReadForWriteVisitorOperationStarter::onReceive(DistributorMessageSender& se _visitor_op->onReceive(sender, msg); } +namespace { + +struct MergePendingChecker : PendingMessageTracker::Checker { + bool has_pending_merge = false; + bool check(uint32_t message_type, [[maybe_unused]] uint16_t node, [[maybe_unused]] uint8_t priority) override { + if (message_type == api::MessageType::MERGEBUCKET_ID) { + has_pending_merge = true; + } + return true; + } +}; + +} + +bool ReadForWriteVisitorOperationStarter::bucket_has_pending_merge(const document::Bucket& bucket, + const PendingMessageTracker& tracker) const { + MergePendingChecker merge_checker; + tracker.checkPendingMessages(bucket, merge_checker); + return merge_checker.has_pending_merge; +} + + } diff --git a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h index 06b4f60307e..a6b414e6fb5 100644 --- a/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h +++ b/storage/src/vespa/storage/distributor/operations/external/read_for_write_visitor_operation.h @@ -43,6 +43,8 @@ public: void onStart(DistributorMessageSender& sender) override; void onReceive(DistributorMessageSender& sender, const std::shared_ptr<api::StorageReply> & msg) override; +private: + bool bucket_has_pending_merge(const document::Bucket&, const PendingMessageTracker& tracker) const; }; } diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp index 3d79aa176d7..5a8adb26cd8 100644 --- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp +++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp @@ -887,6 +887,13 @@ VisitorOperation::fail_with_bucket_already_locked(DistributorMessageSender& send sendReply(api::ReturnCode(api::ReturnCode::BUSY, "This bucket is already locked by another operation"), sender); } +void +VisitorOperation::fail_with_merge_pending(DistributorMessageSender& sender) +{ + assert(is_read_for_write()); + sendReply(api::ReturnCode(api::ReturnCode::BUSY, "A merge operation is pending for this bucket"), sender); +} + std::optional<document::Bucket> VisitorOperation::first_bucket_to_visit() const { diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h index 4043b0b2c50..e6ad7a042dd 100644 --- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h +++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h @@ -51,6 +51,7 @@ public: // Only valid to call if is_read_for_write() == true void fail_with_bucket_already_locked(DistributorMessageSender& sender); + void fail_with_merge_pending(DistributorMessageSender& sender); [[nodiscard]] bool verify_command_and_expand_buckets(DistributorMessageSender& sender); diff --git a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp index a74dc1c0d65..ea9cb56fae8 100644 --- a/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp +++ b/storage/src/vespa/storage/distributor/operations/idealstate/splitoperation.cpp @@ -2,7 +2,6 @@ #include "splitoperation.h" #include <vespa/storage/distributor/idealstatemanager.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storageapi/message/bucketsplitting.h> #include <vespa/storage/distributor/distributor_bucket_space.h> #include <climits> @@ -107,11 +106,6 @@ SplitOperation::onReceive(DistributorMessageSender&, const api::StorageReply::SP (DatabaseUpdate::CREATE_IF_NONEXISTING | DatabaseUpdate::RESET_TRUSTED)); - LOG_BUCKET_OPERATION_NO_LOCK( - sinfo.first, vespalib::make_string( - "Split from bucket %s: %s", - getBucketId().toString().c_str(), - copy.toString().c_str())); } } else if ( rep.getResult().getResult() == api::ReturnCode::BUCKET_NOT_FOUND @@ -137,21 +131,6 @@ SplitOperation::onReceive(DistributorMessageSender&, const api::StorageReply::SP getBucketId().toString().c_str(), rep.getResult().toString().c_str()); } -#ifdef ENABLE_BUCKET_OPERATION_LOGGING - if (_ok) { - LOG_BUCKET_OPERATION_NO_LOCK( - getBucketId(), vespalib::make_string( - "Split OK on node %d: %s. Finished: %s", - node, ost.str().c_str(), - _tracker.finished() ? "yes" : "no")); - } else { - LOG_BUCKET_OPERATION_NO_LOCK( - getBucketId(), vespalib::make_string( - "Split FAILED on node %d: %s. Finished: %s", - node, rep.getResult().toString().c_str(), - _tracker.finished() ? "yes" : "no")); - } -#endif if (_tracker.finished()) { LOG(debug, "Split done on node %d: %s completed operation", diff --git a/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp b/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp index 6983e3594af..7eb2e2bf236 100644 --- a/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp +++ b/storage/src/vespa/storage/distributor/pending_bucket_space_db_transition.cpp @@ -4,7 +4,6 @@ #include "clusterinformation.h" #include "pendingclusterstate.h" #include "distributor_bucket_space.h" -#include <vespa/storage/common/bucketoperationlogger.h> #include <algorithm> #include <vespa/log/log.h> diff --git a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp index 3dda989ff74..d009375a641 100644 --- a/storage/src/vespa/storage/distributor/pendingclusterstate.cpp +++ b/storage/src/vespa/storage/distributor/pendingclusterstate.cpp @@ -6,7 +6,6 @@ #include "distributor_bucket_space_repo.h" #include "distributor_bucket_space.h" #include <vespa/storageframework/defaultimplementation/clock/realclock.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storage/common/global_bucket_space_distribution_converter.h> #include <vespa/document/bucket/fixed_bucket_spaces.h> #include <vespa/vespalib/util/xmlstream.hpp> diff --git a/storage/src/vespa/storage/distributor/statecheckers.cpp b/storage/src/vespa/storage/distributor/statecheckers.cpp index e861adda428..9616ca018b5 100644 --- a/storage/src/vespa/storage/distributor/statecheckers.cpp +++ b/storage/src/vespa/storage/distributor/statecheckers.cpp @@ -9,7 +9,6 @@ #include <vespa/storage/distributor/operations/idealstate/setbucketstateoperation.h> #include <vespa/storage/distributor/operations/idealstate/mergeoperation.h> #include <vespa/storage/distributor/operations/idealstate/garbagecollectionoperation.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/vespalib/stllike/asciistream.h> #include <vespa/log/log.h> diff --git a/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp b/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp index 9a2fe2cd6ce..0ff12ac71bc 100644 --- a/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp +++ b/storage/src/vespa/storage/persistence/bucketownershipnotifier.cpp @@ -2,7 +2,6 @@ #include "bucketownershipnotifier.h" #include <vespa/storage/common/nodestateupdater.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storage/common/content_bucket_space_repo.h> #include <vespa/vdslib/state/cluster_state_bundle.h> #include <vespa/storageapi/message/bucket.h> @@ -83,12 +82,6 @@ BucketOwnershipNotifier::logNotification(const document::Bucket &bucket, currentOwnerIndex, sourceIndex, newInfo.toString().c_str()); - LOG_BUCKET_OPERATION_NO_LOCK( - bucket, - vespalib::make_string( - "Sending notify to distributor %u " - "(ownership changed away from %u)", - currentOwnerIndex, sourceIndex)); } void diff --git a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp index 226df025465..c97965969bc 100644 --- a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp +++ b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp @@ -9,7 +9,6 @@ #include <vespa/storage/bucketdb/storbucketdb.h> #include <vespa/storage/common/bucketmessages.h> #include <vespa/storage/common/statusmessages.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storage/common/messagebucket.h> #include <vespa/storage/persistence/asynchandler.h> #include <vespa/storage/persistence/messages.h> @@ -480,16 +479,6 @@ FileStorHandlerImpl::remapMessage(api::StorageMessage& msg, const document::Buck if (idx > -1) { cmd.remapBucketId(targets[idx]->bucket.getBucketId()); targets[idx]->foundInQueue = true; -#if defined(ENABLE_BUCKET_OPERATION_LOGGING) - { - vespalib::string desc = vespalib::make_string( - "Remapping %s from %s to %s, targetDisk = %u", - cmd.toString().c_str(), source.toString().c_str(), - targets[idx]->bid.toString().c_str(), targetDisk); - LOG_BUCKET_OPERATION_NO_LOCK(source, desc); - LOG_BUCKET_OPERATION_NO_LOCK(targets[idx]->bid, desc); - } -#endif newBucket = targets[idx]->bucket; } else { document::DocumentId did(getDocId(msg)); @@ -522,16 +511,6 @@ FileStorHandlerImpl::remapMessage(api::StorageMessage& msg, const document::Buck cmd.toString().c_str(), targets[0]->bucket.getBucketId().toString().c_str()); cmd.remapBucketId(targets[0]->bucket.getBucketId()); newBucket = targets[0]->bucket; -#ifdef ENABLE_BUCKET_OPERATION_LOGGING - { - vespalib::string desc = vespalib::make_string( - "Remapping %s from %s to %s, targetDisk = %u", - cmd.toString().c_str(), source.toString().c_str(), - targets[0]->bid.toString().c_str(), targetDisk); - LOG_BUCKET_OPERATION_NO_LOCK(source, desc); - LOG_BUCKET_OPERATION_NO_LOCK(targets[0]->bid, desc); - } -#endif } } else { LOG(debug, "Did not remap %s with bucket %s from bucket %s", diff --git a/storage/src/vespa/storage/persistence/simplemessagehandler.cpp b/storage/src/vespa/storage/persistence/simplemessagehandler.cpp index 5a5d3dcabca..9c31a1c81bc 100644 --- a/storage/src/vespa/storage/persistence/simplemessagehandler.cpp +++ b/storage/src/vespa/storage/persistence/simplemessagehandler.cpp @@ -3,7 +3,6 @@ #include "simplemessagehandler.h" #include "persistenceutil.h" #include <vespa/persistence/spi/persistenceprovider.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storageapi/message/bucket.h> #include <vespa/document/base/exceptions.h> #include <vespa/document/fieldset/fieldsetrepo.h> @@ -105,7 +104,6 @@ SimpleMessageHandler::handleCreateBucket(api::CreateBucketCommand& cmd, MessageT LOG(debug, "CreateBucket(%s)", cmd.getBucketId().toString().c_str()); if (_env._fileStorHandler.isMerging(cmd.getBucket())) { LOG(warning, "Bucket %s was merging at create time. Unexpected.", cmd.getBucketId().toString().c_str()); - DUMP_LOGGED_BUCKET_OPERATIONS(cmd.getBucketId()); } spi::Bucket spiBucket(cmd.getBucket()); _spi.createBucket(spiBucket, tracker->context()); @@ -147,7 +145,6 @@ SimpleMessageHandler::handleDeleteBucket(api::DeleteBucketCommand& cmd, MessageT { tracker->setMetric(_env._metrics.deleteBuckets); LOG(debug, "DeletingBucket(%s)", cmd.getBucketId().toString().c_str()); - LOG_BUCKET_OPERATION(cmd.getBucketId(), "deleteBucket()"); if (_env._fileStorHandler.isMerging(cmd.getBucket())) { _env._fileStorHandler.clearMergeStatus(cmd.getBucket(), api::ReturnCode(api::ReturnCode::ABORTED, "Bucket was deleted during the merge")); diff --git a/storage/src/vespa/storage/storageserver/communicationmanager.cpp b/storage/src/vespa/storage/storageserver/communicationmanager.cpp index 9d4b7b58a6f..7a3dd16bbd1 100644 --- a/storage/src/vespa/storage/storageserver/communicationmanager.cpp +++ b/storage/src/vespa/storage/storageserver/communicationmanager.cpp @@ -429,7 +429,8 @@ void CommunicationManager::configure(std::unique_ptr<CommunicationManagerConfig> } _message_codec_provider = std::make_unique<rpc::MessageCodecProvider>(_component.getTypeRepo()->documentTypeRepo); - _shared_rpc_resources = std::make_unique<rpc::SharedRpcResources>(_configUri, config->rpcport, config->rpc.numNetworkThreads); + _shared_rpc_resources = std::make_unique<rpc::SharedRpcResources>(_configUri, config->rpcport, + config->rpc.numNetworkThreads, config->rpc.eventsBeforeWakeup); _cc_rpc_service = std::make_unique<rpc::ClusterControllerApiRpcService>(*this, *_shared_rpc_resources); rpc::StorageApiRpcService::Params rpc_params; rpc_params.compression_config = convert_to_rpc_compression_config(*config); diff --git a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp index 3aa3d21aa7b..4c075f44d35 100644 --- a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp +++ b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.cpp @@ -62,9 +62,11 @@ public: SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri, int rpc_server_port, - size_t rpc_thread_pool_size) + size_t rpc_thread_pool_size, + size_t rpc_events_before_wakeup) : _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)), - _transport(std::make_unique<FNET_Transport>(TransportConfig(rpc_thread_pool_size).events_before_wakeup(1))), + _transport(std::make_unique<FNET_Transport>(TransportConfig(rpc_thread_pool_size). + events_before_wakeup(rpc_events_before_wakeup))), _orb(std::make_unique<FRT_Supervisor>(_transport.get())), _slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))), _slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))), diff --git a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h index 740277218c3..1fdd0f2648b 100644 --- a/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h +++ b/storage/src/vespa/storage/storageserver/rpc/shared_rpc_resources.h @@ -30,7 +30,8 @@ class SharedRpcResources { int _rpc_server_port; bool _shutdown; public: - SharedRpcResources(const config::ConfigUri& config_uri, int rpc_server_port, size_t rpc_thread_pool_size); + SharedRpcResources(const config::ConfigUri& config_uri, int rpc_server_port, + size_t rpc_thread_pool_size, size_t rpc_events_before_wakeup); ~SharedRpcResources(); FRT_Supervisor& supervisor() noexcept { return *_orb; } diff --git a/storage/src/vespa/storage/storageserver/statemanager.cpp b/storage/src/vespa/storage/storageserver/statemanager.cpp index 653822626ed..395e33a0393 100644 --- a/storage/src/vespa/storage/storageserver/statemanager.cpp +++ b/storage/src/vespa/storage/storageserver/statemanager.cpp @@ -6,7 +6,6 @@ #include <vespa/document/bucket/fixed_bucket_spaces.h> #include <vespa/metrics/jsonwriter.h> #include <vespa/metrics/metricmanager.h> -#include <vespa/storage/common/bucketoperationlogger.h> #include <vespa/storageapi/messageapi/storagemessage.h> #include <vespa/vdslib/state/cluster_state_bundle.h> #include <vespa/vespalib/io/fileutil.h> diff --git a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java index 2c123779a1e..2690edc9407 100644 --- a/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java +++ b/vespajlib/src/main/java/com/yahoo/concurrent/maintenance/Maintainer.java @@ -11,6 +11,7 @@ import java.util.Objects; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -21,7 +22,7 @@ import java.util.logging.Logger; * @author mpolden * @author jonmv */ -public abstract class Maintainer implements Runnable, AutoCloseable { +public abstract class Maintainer implements Runnable { protected final Logger log = Logger.getLogger(this.getClass().getName()); @@ -30,6 +31,7 @@ public abstract class Maintainer implements Runnable, AutoCloseable { private final JobMetrics jobMetrics; private final Duration interval; private final ScheduledExecutorService service; + private AtomicBoolean shutDown = new AtomicBoolean(); public Maintainer(String name, Duration interval, Instant startedAt, JobControl jobControl, JobMetrics jobMetrics, List<String> clusterHostnames) { this(name, interval, staggeredDelay(interval, startedAt, HostName.getLocalhost(), clusterHostnames), jobControl, jobMetrics); @@ -60,10 +62,16 @@ public abstract class Maintainer implements Runnable, AutoCloseable { log.log(Level.FINE, () -> "Finished " + this.getClass().getSimpleName()); } - @Override - public void close() { + /** Starts shutdown of this, typically by shutting down executors. {@link #awaitShutdown()} waits for shutdown to complete. */ + public void shutdown() { + if ( ! shutDown.getAndSet(true)) + service.shutdown(); + } + + /** Waits for shutdown to complete, calling {@link #shutdown} if this hasn't been done already. */ + public void awaitShutdown() { + shutdown(); var timeout = Duration.ofSeconds(30); - service.shutdown(); try { if (!service.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS)) { log.log(Level.WARNING, "Maintainer " + name() + " failed to shutdown " + diff --git a/zookeeper-server/zookeeper-server-3.6.2/pom.xml b/zookeeper-server/zookeeper-server-3.6.2/pom.xml index c479c84ac86..522bc71df97 100644 --- a/zookeeper-server/zookeeper-server-3.6.2/pom.xml +++ b/zookeeper-server/zookeeper-server-3.6.2/pom.xml @@ -31,6 +31,21 @@ <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> + <!-- snappy-java and metrics-core are included here + to be able to work with ZooKeeper 3.6.2 due to + class loading issues --> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-core</artifactId> + <scope>compile</scope> + <version>3.2.5</version> + </dependency> + <dependency> + <groupId>org.xerial.snappy</groupId> + <artifactId>snappy-java</artifactId> + <scope>compile</scope> + <version>1.1.7</version> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java index 0e3f3743c18..e535f627f00 100644 --- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java +++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java @@ -90,8 +90,9 @@ public class Configurator { sb.append("serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory").append("\n"); sb.append("quorumListenOnAllIPs=true").append("\n"); sb.append("standaloneEnabled=false").append("\n"); - sb.append("reconfigEnabled=" + config.dynamicReconfiguration()).append("\n"); + sb.append("reconfigEnabled=true").append("\n"); sb.append("skipACL=yes").append("\n"); + sb.append("metricsProvider.className=org.apache.zookeeper.metrics.impl.NullMetricsProvider\n"); ensureThisServerIsRepresented(config.myid(), config.server()); config.server().forEach(server -> addServerToCfg(sb, server, config.clientPort())); SSLContext sslContext = new SslContextBuilder().build(); diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java index 492cfffa1ad..9e9b6a0bbc9 100644 --- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java +++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/ZooKeeperRunner.java @@ -56,7 +56,19 @@ public class ZooKeeperRunner implements Runnable { Path path = Paths.get(getDefaults().underVespaHome(zookeeperServerConfig.zooKeeperConfigFile())); log.log(Level.INFO, "Starting ZooKeeper server with config file " + path.toFile().getAbsolutePath() + ". Trying to establish ZooKeeper quorum (members: " + zookeeperServerHostnames(zookeeperServerConfig) + ")"); - server.start(path); + // Note: Hack to make this work in ZooKeeper 3.6, where metrics provider class is + // loaded by using Thread.currentThread().getContextClassLoader() which does not work + // well in the container + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); + try { + server.start(path); + } catch (Throwable e) { + log.log(Level.SEVERE, "Starting ZooKeeper server failed", e); + throw new RuntimeException("Starting ZooKeeper server failed", e); + } finally { + Thread.currentThread().setContextClassLoader(tccl); + } } } diff --git a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java index 04a4010edf8..0cdbd68421c 100644 --- a/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java +++ b/zookeeper-server/zookeeper-server-common/src/test/java/com/yahoo/vespa/zookeeper/ConfiguratorTest.java @@ -69,7 +69,6 @@ public class ConfiguratorTest { builder.server(newServer(2, "baz", 345, 543)); builder.myidFile(idFile.getAbsolutePath()); builder.myid(1); - builder.dynamicReconfiguration(true); new Configurator(builder.build()).writeConfigToDisk(Optional.empty()); validateConfigFileMultipleHosts(cfgFile); validateIdFile(idFile, "1\n"); @@ -115,7 +114,6 @@ public class ConfiguratorTest { builder.server(newServer(0, "foo", 123, 321)); builder.myid(0); builder.jksKeyStoreFile(jksKeyStoreFile.getAbsolutePath()); - builder.dynamicReconfiguration(true); return builder; } @@ -179,7 +177,8 @@ public class ConfiguratorTest { "quorumListenOnAllIPs=true\n" + "standaloneEnabled=false\n" + "reconfigEnabled=true\n" + - "skipACL=yes\n"; + "skipACL=yes\n" + + "metricsProvider.className=org.apache.zookeeper.metrics.impl.NullMetricsProvider\n"; } private String quorumKeyStoreAndTrustStoreConfig(File jksKeyStoreFilePath, File caCertificatesFilePath) { |