aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValerij Fredriksen <freva@users.noreply.github.com>2020-03-09 09:33:20 +0100
committerGitHub <noreply@github.com>2020-03-09 09:33:20 +0100
commitbbc74ec90bcba32b2de15b3cb5f17b0ed221ca33 (patch)
tree147fa5b15eb1363c22e443caf6d8018693cb2e20
parent238581e9723fd2340192e7cd48c452286a25cd6b (diff)
parentab0fc576e409c72c21d14ce7d3e473b4d4d7005a (diff)
Merge pull request #12500 from vespa-engine/hakonhall/avoid-building-lots-of-applicationinstances
Avoid building lots of ApplicationInstances
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/application/OrchestratorMock.java7
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java40
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/OrchestratorMock.java7
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java35
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Orchestrator.java7
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java29
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyServiceMonitor.java5
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java32
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java77
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java13
12 files changed, 159 insertions, 97 deletions
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/OrchestratorMock.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/OrchestratorMock.java
index 837cbd4605a..88d486cef87 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/OrchestratorMock.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/OrchestratorMock.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.config.server.application;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.orchestrator.Host;
import com.yahoo.vespa.orchestrator.Orchestrator;
@@ -41,6 +42,12 @@ public class OrchestratorMock implements Orchestrator {
}
@Override
+ public HostInfo getHostInfo(ApplicationInstanceReference reference, HostName hostname) {
+ HostInfo hostInfo = hostInfos.get(hostname);
+ return hostInfo == null ? HostInfo.createNoRemarks() : hostInfo;
+ }
+
+ @Override
public Function<HostName, Optional<HostInfo>> getHostResolver() {
return hostName -> Optional.of(hostInfos.getOrDefault(hostName, HostInfo.createNoRemarks()));
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java
index e65b7273b9e..e107abf8fbb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporter.java
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
import com.yahoo.jdisc.Metric;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
@@ -15,7 +16,7 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.orchestrator.Orchestrator;
-import com.yahoo.vespa.orchestrator.status.HostInfo;
+import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
import java.time.Clock;
@@ -24,7 +25,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -36,7 +36,7 @@ import static com.yahoo.config.provision.NodeResources.DiskSpeed.any;
public class MetricsReporter extends Maintainer {
private final Metric metric;
- private final Function<HostName, Optional<HostInfo>> orchestrator;
+ private final Orchestrator orchestrator;
private final ServiceMonitor serviceMonitor;
private final Map<Map<String, String>, Metric.Context> contextMap = new HashMap<>();
private final Supplier<Integer> pendingRedeploymentsSupplier;
@@ -51,7 +51,7 @@ public class MetricsReporter extends Maintainer {
Clock clock) {
super(nodeRepository, interval);
this.metric = metric;
- this.orchestrator = orchestrator.getHostResolver();
+ this.orchestrator = orchestrator;
this.serviceMonitor = serviceMonitor;
this.pendingRedeploymentsSupplier = pendingRedeploymentsSupplier;
this.clock = clock;
@@ -60,9 +60,9 @@ public class MetricsReporter extends Maintainer {
@Override
public void maintain() {
NodeList nodes = nodeRepository().list();
- Map<HostName, List<ServiceInstance>> servicesByHost = serviceMonitor.getServicesByHostname();
+ ServiceModel serviceModel = serviceMonitor.getServiceModelSnapshot();
- nodes.forEach(node -> updateNodeMetrics(node, servicesByHost));
+ nodes.forEach(node -> updateNodeMetrics(node, serviceModel));
updateStateMetrics(nodes);
updateMaintenanceMetrics();
updateDockerMetrics(nodes);
@@ -73,7 +73,7 @@ public class MetricsReporter extends Maintainer {
metric.set("hostedVespa.pendingRedeployments", pendingRedeploymentsSupplier.get(), null);
}
- private void updateNodeMetrics(Node node, Map<HostName, List<ServiceInstance>> servicesByHost) {
+ private void updateNodeMetrics(Node node, ServiceModel serviceModel) {
Metric.Context context;
Optional<Allocation> allocation = node.allocation();
@@ -128,19 +128,23 @@ public class MetricsReporter extends Maintainer {
metric.set("wantToDeprovision", node.status().wantToDeprovision() ? 1 : 0, context);
metric.set("failReport", NodeFailer.reasonsToFailParentHost(node).isEmpty() ? 0 : 1, context);
- orchestrator.apply(new HostName(node.hostname())).ifPresent(info -> {
- int suspended = info.status().isSuspended() ? 1 : 0;
- metric.set("suspended", suspended, context);
- metric.set("allowedToBeDown", suspended, context); // remove summer 2020.
- long suspendedSeconds = info.suspendedSince()
- .map(suspendedSince -> Duration.between(suspendedSince, clock.instant()).getSeconds())
- .orElse(0L);
- metric.set("suspendedSeconds", suspendedSeconds, context);
- });
+ HostName hostname = new HostName(node.hostname());
+
+ serviceModel.getApplication(hostname)
+ .map(ApplicationInstance::reference)
+ .map(reference -> orchestrator.getHostInfo(reference, hostname))
+ .ifPresent(info -> {
+ int suspended = info.status().isSuspended() ? 1 : 0;
+ metric.set("suspended", suspended, context);
+ metric.set("allowedToBeDown", suspended, context); // remove summer 2020.
+ long suspendedSeconds = info.suspendedSince()
+ .map(suspendedSince -> Duration.between(suspendedSince, clock.instant()).getSeconds())
+ .orElse(0L);
+ metric.set("suspendedSeconds", suspendedSeconds, context);
+ });
long numberOfServices;
- HostName hostName = new HostName(node.hostname());
- List<ServiceInstance> services = servicesByHost.get(hostName);
+ List<ServiceInstance> services = serviceModel.getServiceInstancesByHostName().get(hostname);
if (services == null) {
numberOfServices = 0;
} else {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
index 8a5a119f6a7..b0b8f7d8d2c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeFailer.java
@@ -186,7 +186,7 @@ public class NodeFailer extends Maintainer {
Map<String, Node> activeNodesByHostname = nodeRepository().getNodes(Node.State.active).stream()
.collect(Collectors.toMap(Node::hostname, node -> node));
- serviceMonitor.getServicesByHostname()
+ serviceMonitor.getServiceModelSnapshot().getServiceInstancesByHostName()
.forEach((hostName, serviceInstances) -> {
Node node = activeNodesByHostname.get(hostName.s());
if (node == null) return;
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 ecc550527fc..c3c488c9616 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
@@ -8,10 +8,10 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostLivenessTracker;
import com.yahoo.config.provision.InfraDeployer;
import com.yahoo.config.provision.Zone;
-import com.yahoo.vespa.hosted.provision.autoscale.NodeMetrics;
import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.autoscale.NodeMetrics;
import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricsDb;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisionServiceProvider;
import com.yahoo.vespa.orchestrator.Orchestrator;
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/OrchestratorMock.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/OrchestratorMock.java
index d183e62c96c..ff9cb98783c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/OrchestratorMock.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/OrchestratorMock.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.provision.testutils;
import com.yahoo.component.AbstractComponent;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.orchestrator.Host;
import com.yahoo.vespa.orchestrator.Orchestrator;
@@ -40,6 +41,12 @@ public class OrchestratorMock extends AbstractComponent implements Orchestrator
}
@Override
+ public HostInfo getHostInfo(ApplicationInstanceReference reference, HostName hostname) {
+ HostInfo hostInfo = suspendedHosts.get(hostname);
+ return hostInfo == null ? HostInfo.createNoRemarks() : hostInfo;
+ }
+
+ @Override
public Function<HostName, Optional<HostInfo>> getHostResolver() {
return hostName -> Optional.of(suspendedHosts.getOrDefault(hostName, HostInfo.createNoRemarks()));
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
index 8daec1d641e..ddca903a5c2 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java
@@ -11,6 +11,8 @@ import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Zone;
import com.yahoo.jdisc.Metric;
import com.yahoo.test.ManualClock;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.flags.InMemoryFlagSource;
@@ -26,7 +28,9 @@ import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver;
import com.yahoo.vespa.orchestrator.Orchestrator;
import com.yahoo.vespa.orchestrator.status.HostInfo;
import com.yahoo.vespa.orchestrator.status.HostStatus;
+import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
+import org.junit.Before;
import org.junit.Test;
import java.time.Clock;
@@ -40,6 +44,8 @@ import java.util.Optional;
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -48,6 +54,23 @@ import static org.mockito.Mockito.when;
* @author smorgrav
*/
public class MetricsReporterTest {
+ private final ServiceMonitor serviceMonitor = mock(ServiceMonitor.class);
+ private final ApplicationInstanceReference reference = mock(ApplicationInstanceReference.class);
+
+ @Before
+ public void setUp() {
+ // On the serviceModel returned by serviceMonitor.getServiceModelSnapshot(),
+ // 2 methods should be used by MetricsReporter:
+ // - getServiceInstancesByHostName() -> empty Map
+ // - getApplication() which is mapped to a dummy ApplicationInstanceReference and
+ // used for lookup.
+ ServiceModel serviceModel = mock(ServiceModel.class);
+ when(serviceMonitor.getServiceModelSnapshot()).thenReturn(serviceModel);
+ when(serviceModel.getServiceInstancesByHostName()).thenReturn(Map.of());
+ ApplicationInstance applicationInstance = mock(ApplicationInstance.class);
+ when(serviceModel.getApplication(any())).thenReturn(Optional.of(applicationInstance));
+ when(applicationInstance.reference()).thenReturn(reference);
+ }
@Test
public void test_registered_metric() {
@@ -91,12 +114,10 @@ public class MetricsReporterTest {
expectedMetrics.put("numberOfServices", 0L);
ManualClock clock = new ManualClock(Instant.ofEpochSecond(124));
+
Orchestrator orchestrator = mock(Orchestrator.class);
- ServiceMonitor serviceMonitor = mock(ServiceMonitor.class);
- when(orchestrator.getHostResolver()).thenReturn(hostName ->
- Optional.of(HostInfo.createSuspended(HostStatus.ALLOWED_TO_BE_DOWN, Instant.ofEpochSecond(1)))
- );
- when(serviceMonitor.getServicesByHostname()).thenReturn(Map.of());
+ when(orchestrator.getHostInfo(eq(reference), any())).thenReturn(
+ HostInfo.createSuspended(HostStatus.ALLOWED_TO_BE_DOWN, Instant.ofEpochSecond(1)));
TestMetric metric = new TestMetric();
MetricsReporter metricsReporter = new MetricsReporter(
@@ -141,9 +162,7 @@ public class MetricsReporterTest {
nodeRepository.addDockerNodes(new LockedNodeList(List.of(container2), nodeRepository.lockUnallocated()));
Orchestrator orchestrator = mock(Orchestrator.class);
- ServiceMonitor serviceMonitor = mock(ServiceMonitor.class);
- when(orchestrator.getHostResolver()).thenReturn(hostName -> Optional.of(HostInfo.createNoRemarks()));
- when(serviceMonitor.getServicesByHostname()).thenReturn(Map.of());
+ when(orchestrator.getHostInfo(eq(reference), any())).thenReturn(HostInfo.createNoRemarks());
TestMetric metric = new TestMetric();
ManualClock clock = new ManualClock();
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Orchestrator.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Orchestrator.java
index 10fa10f1150..9d2d72277e5 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Orchestrator.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/Orchestrator.java
@@ -2,8 +2,8 @@
package com.yahoo.vespa.orchestrator;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.orchestrator.model.NodeGroup;
import com.yahoo.vespa.orchestrator.policy.BatchHostStateChangeDeniedException;
import com.yahoo.vespa.orchestrator.policy.HostStateChangeDeniedException;
import com.yahoo.vespa.orchestrator.status.ApplicationInstanceStatus;
@@ -45,10 +45,13 @@ public interface Orchestrator {
*
* @param hostName The FQDN which are used in the noderepo.
* @return The enum describing the current state.
- * @throws HostNameNotFoundException if hostName is unrecognized (in node repo)
+ * @throws HostNameNotFoundException if hostName is not associated with any application
*/
HostStatus getNodeStatus(HostName hostName) throws HostNameNotFoundException;
+ /** Get host info for hostname in application, returning no-remarks if not in application. */
+ HostInfo getHostInfo(ApplicationInstanceReference reference, HostName hostname);
+
/**
* Returns a lambda, which when invoked with a hostname, returns its current host info.
*
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
index 5ac5c66cc7c..f36f7088424 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
@@ -127,19 +127,25 @@ public class OrchestratorImpl implements Orchestrator {
@Override
public HostStatus getNodeStatus(HostName hostName) throws HostNameNotFoundException {
- return getNodeStatus(getApplicationInstance(hostName).reference(), hostName);
+ ApplicationInstanceReference reference = getApplicationInstanceReference(hostName);
+ return statusService.getHostInfo(reference, hostName).status();
+ }
+
+ @Override
+ public HostInfo getHostInfo(ApplicationInstanceReference reference, HostName hostname) {
+ return statusService.getHostInfo(reference, hostname);
}
@Override
public Function<HostName, Optional<HostInfo>> getHostResolver() {
return hostName -> serviceMonitor
- .getApplication(hostName)
- .map(application -> statusService.getHostInfo(application.reference(), hostName));
+ .getApplicationInstanceReference(hostName)
+ .map(reference -> statusService.getHostInfo(reference, hostName));
}
@Override
public void setNodeStatus(HostName hostName, HostStatus status) throws OrchestrationException {
- ApplicationInstanceReference reference = getApplicationInstance(hostName).reference();
+ ApplicationInstanceReference reference = getApplicationInstanceReference(hostName);
OrchestratorContext context = OrchestratorContext.createContextForSingleAppOp(clock);
try (ApplicationLock lock = statusService.lockApplication(context, reference)) {
lock.setHostState(hostName, status);
@@ -347,11 +353,7 @@ public class OrchestratorImpl implements Orchestrator {
return leftApplicationReference.asString().compareTo(rightApplicationReference.asString());
}
- private HostStatus getNodeStatus(ApplicationInstanceReference applicationRef, HostName hostName) {
- return statusService.getHostInfo(applicationRef, hostName).status();
- }
-
- private void setApplicationStatus(ApplicationId appId, ApplicationInstanceStatus status)
+ private void setApplicationStatus(ApplicationId appId, ApplicationInstanceStatus status)
throws ApplicationStateChangeDeniedException, ApplicationIdNotFoundException{
OrchestratorContext context = OrchestratorContext.createContextForSingleAppOp(clock);
ApplicationInstanceReference reference = OrchestratorUtil.toApplicationInstanceReference(appId, serviceMonitor);
@@ -420,9 +422,14 @@ public class OrchestratorImpl implements Orchestrator {
}
}
+ private ApplicationInstanceReference getApplicationInstanceReference(HostName hostname) throws HostNameNotFoundException {
+ return serviceMonitor.getApplicationInstanceReference(hostname)
+ .orElseThrow(() -> new HostNameNotFoundException(hostname));
+ }
+
private ApplicationInstance getApplicationInstance(HostName hostName) throws HostNameNotFoundException{
- return serviceMonitor.getApplication(hostName).orElseThrow(
- () -> new HostNameNotFoundException(hostName));
+ return serviceMonitor.getApplication(hostName)
+ .orElseThrow(() -> new HostNameNotFoundException(hostName));
}
private static void sleep(long time, TimeUnit timeUnit) {
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyServiceMonitor.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyServiceMonitor.java
index a784187fb62..501a09f78ff 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyServiceMonitor.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/DummyServiceMonitor.java
@@ -163,11 +163,6 @@ public class DummyServiceMonitor implements ServiceMonitor, AntiServiceMonitor {
}
@Override
- public Map<HostName, List<ServiceInstance>> getServicesByHostname() {
- throw new UnsupportedOperationException();
- }
-
- @Override
public CriticalRegion disallowDuperModelLockAcquisition(String regionDescription) {
return () -> {};
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
index 678b0d3d5ba..e6e6e85c710 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
@@ -10,7 +10,6 @@ import com.yahoo.jdisc.Timer;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.service.duper.DuperModelManager;
import com.yahoo.vespa.service.manager.MonitorManager;
import com.yahoo.vespa.service.manager.UnionMonitorManager;
@@ -21,8 +20,6 @@ import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
-import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -70,13 +67,16 @@ public class ServiceMonitorImpl implements ServiceMonitor, AntiServiceMonitor {
}
@Override
- public Optional<ApplicationInstance> getApplication(HostName hostname) {
- Optional<ApplicationInfo> applicationInfo = getApplicationInfo(hostname);
- if (applicationInfo.isEmpty()) {
- return Optional.empty();
- }
+ public Optional<ApplicationInstanceReference> getApplicationInstanceReference(HostName hostname) {
+ return duperModelManager.getApplicationInfo(toConfigProvisionHostName(hostname))
+ .map(ApplicationInfo::getApplicationId)
+ .map(modelGenerator::toApplicationInstanceReference);
+ }
- return Optional.of(modelGenerator.toApplicationInstance(applicationInfo.get(), serviceStatusProvider));
+ @Override
+ public Optional<ApplicationInstance> getApplication(HostName hostname) {
+ return getApplicationInfo(hostname)
+ .map(applicationInfo -> modelGenerator.toApplicationInstance(applicationInfo, serviceStatusProvider));
}
@Override
@@ -97,11 +97,6 @@ public class ServiceMonitorImpl implements ServiceMonitor, AntiServiceMonitor {
}
@Override
- public Map<HostName, List<ServiceInstance>> getServicesByHostname() {
- return getServiceModelSnapshot().getServiceInstancesByHostName();
- }
-
- @Override
public void registerListener(ServiceHostListener listener) {
var duperModelListener = ServiceHostListenerAdapter.asDuperModelListener(listener, modelGenerator);
duperModelManager.registerListener(duperModelListener);
@@ -118,8 +113,11 @@ public class ServiceMonitorImpl implements ServiceMonitor, AntiServiceMonitor {
}
private Optional<ApplicationInfo> getApplicationInfo(HostName hostname) {
- // The duper model uses HostName from config.provision, which is more natural than applicationmodel.
- var configProvisionHostname = com.yahoo.config.provision.HostName.from(hostname.s());
- return duperModelManager.getApplicationInfo(configProvisionHostname);
+ return duperModelManager.getApplicationInfo(toConfigProvisionHostName(hostname));
+ }
+
+ /** The duper model uses HostName from config.provision. */
+ private static com.yahoo.config.provision.HostName toConfigProvisionHostName(HostName hostname) {
+ return com.yahoo.config.provision.HostName.from(hostname.s());
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java
index ed72893400a..c8f491a0fc7 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java
@@ -1,66 +1,91 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.monitor;
+import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
import com.yahoo.vespa.applicationmodel.ServiceCluster;
import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
- * The ServiceModel is almost a mirror of the SuperModel, except that it
- * also gives ServiceStatus on each service, and there may be
- * artificial applications like the config server "application".
+ * The service model is the union of the duper model and the service monitor, and presented
+ * as classes from the {@code application-model} module.
+ *
+ * <p>The duper model contains the latest {@link ApplicationInfo} of both tenant and infrastructure
+ * applications. The service monitor provides Slobrok or {@code /state/v1/health} information
+ * on (most) services. The application model presents an application as a set of clusters, and
+ * each cluster a set of services, and each service is associated with a particular host
+ * and has a health status.</p>
+ *
+ * @author hakonhall
*/
public class ServiceModel {
- private final Map<ApplicationInstanceReference, ApplicationInstance> applications;
- private final Map<HostName, ApplicationInstance> applicationsByHostName;
+ private final Map<ApplicationInstanceReference, ApplicationInstance> applicationsByReference;
- public ServiceModel(Map<ApplicationInstanceReference, ApplicationInstance> applications) {
- this.applications = Collections.unmodifiableMap(applications);
- this.applicationsByHostName = Collections.unmodifiableMap(applicationsByHostNames(applications.values()));
+ private Map<HostName, ApplicationInstance> applicationsByHostName = null;
+ private Map<HostName, List<ServiceInstance>> servicesByHostName = null;
+
+ public ServiceModel(Map<ApplicationInstanceReference, ApplicationInstance> applicationsByReference) {
+ this.applicationsByReference = Collections.unmodifiableMap(Map.copyOf(applicationsByReference));
}
public Map<ApplicationInstanceReference, ApplicationInstance> getAllApplicationInstances() {
- return applications;
+ return applicationsByReference;
}
public Optional<ApplicationInstance> getApplicationInstance(ApplicationInstanceReference reference) {
- return Optional.ofNullable(applications.get(reference));
+ return Optional.ofNullable(applicationsByReference.get(reference));
}
- public Map<HostName, ApplicationInstance> getApplicationsByHostName() {
- return applicationsByHostName;
+ public Optional<ApplicationInstance> getApplication(HostName hostname) {
+ if (applicationsByHostName == null) {
+ fillMaps();
+ }
+
+ return Optional.ofNullable(applicationsByHostName.get(hostname));
}
public Map<HostName, List<ServiceInstance>> getServiceInstancesByHostName() {
- return applications.values().stream()
- .flatMap(application -> application.serviceClusters().stream())
- .flatMap(cluster -> cluster.serviceInstances().stream())
- .collect(Collectors.groupingBy(ServiceInstance::hostName, Collectors.toList()));
+ if (servicesByHostName == null) {
+ fillMaps();
+ }
+
+ return servicesByHostName;
}
- private static Map<HostName, ApplicationInstance> applicationsByHostNames(Collection<ApplicationInstance> applications) {
- Map<HostName, ApplicationInstance> hosts = new HashMap<>();
- for (ApplicationInstance application : applications)
- for (ServiceCluster cluster : application.serviceClusters())
+ private void fillMaps() {
+ Map<HostName, ApplicationInstance> applicationInstances = new HashMap<>();
+ Map<HostName, List<ServiceInstance>> serviceInstances = new HashMap<>();
+
+ for (ApplicationInstance application : applicationsByReference.values()) {
+ for (ServiceCluster cluster : application.serviceClusters()) {
for (ServiceInstance instance : cluster.serviceInstances()) {
- ApplicationInstance previous = hosts.put(instance.hostName(), application);
- if (previous != null && ! previous.equals(application))
+
+ ApplicationInstance previous = applicationInstances.put(instance.hostName(), application);
+ if (previous != null && !previous.equals(application)) {
throw new IllegalStateException("Major assumption broken: Multiple application instances contain host " +
- instance.hostName().s() + ": " + Arrays.asList(previous, application));
+ instance.hostName().s() + ": " + Arrays.asList(previous, application));
+ }
+
+ serviceInstances
+ .computeIfAbsent(instance.hostName(), key -> new ArrayList<>())
+ .add(instance);
}
- return hosts;
+ }
+ }
+
+ applicationsByHostName = Collections.unmodifiableMap(applicationInstances);
+ servicesByHostName = Collections.unmodifiableMap(serviceInstances);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
index 0d162fee182..4f52d7d229c 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
@@ -4,10 +4,7 @@ package com.yahoo.vespa.service.monitor;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
-import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -31,8 +28,12 @@ public interface ServiceMonitor {
return getServiceModelSnapshot().getAllApplicationInstances().keySet();
}
+ default Optional<ApplicationInstanceReference> getApplicationInstanceReference(HostName hostname) {
+ return getApplication(hostname).map(ApplicationInstance::reference);
+ }
+
default Optional<ApplicationInstance> getApplication(HostName hostname) {
- return Optional.ofNullable(getServiceModelSnapshot().getApplicationsByHostName().get(hostname));
+ return getServiceModelSnapshot().getApplication(hostname);
}
default Optional<ApplicationInstance> getApplication(ApplicationInstanceReference reference) {
@@ -43,10 +44,6 @@ public interface ServiceMonitor {
return getApplication(hostname);
}
- default Map<HostName, List<ServiceInstance>> getServicesByHostname() {
- return getServiceModelSnapshot().getServiceInstancesByHostName();
- }
-
/**
* Get notified of changes to the set of applications, or set of hosts assigned to an application.
*