From 4d29c806e4d3a85a0c91aea0862b1fd2f4b86eef Mon Sep 17 00:00:00 2001 From: HÃ¥kon Hallingstad Date: Fri, 29 Sep 2017 08:57:20 +0200 Subject: Adds listener for SuperModel changes --- .../vespa/service/monitor/ServiceMonitorImpl.java | 44 ++++++++++++++ .../service/monitor/SuperModelListenerImpl.java | 67 ++++++++++++++++++++++ .../monitor/SuperModelListenerImplTest.java | 29 ++++++++++ 3 files changed, 140 insertions(+) create mode 100644 service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitorImpl.java create mode 100644 service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SuperModelListenerImpl.java create mode 100644 service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SuperModelListenerImplTest.java (limited to 'service-monitor') diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitorImpl.java new file mode 100644 index 00000000000..3468644169d --- /dev/null +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitorImpl.java @@ -0,0 +1,44 @@ +// 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.google.inject.Inject; +import com.yahoo.cloud.config.ConfigserverConfig; +import com.yahoo.config.model.api.SuperModelProvider; +import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.applicationmodel.ApplicationInstance; +import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference; + +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +public class ServiceMonitorImpl implements ServiceMonitor { + private static final Logger logger = Logger.getLogger(ServiceMonitorImpl.class.getName()); + + private final Zone zone; + private final List configServerHostnames; + private final SlobrokMonitor2 slobrokMonitor = new SlobrokMonitor2(); + private final SuperModelListenerImpl superModelListener = + new SuperModelListenerImpl(slobrokMonitor); + + @Inject + public ServiceMonitorImpl(SuperModelProvider superModelProvider, + ConfigserverConfig configserverConfig) { + this.zone = superModelProvider.getZone(); + this.configServerHostnames = configserverConfig.zookeeperserver().stream() + .map(server -> server.hostname()) + .collect(Collectors.toList()); + superModelListener.start(superModelProvider); + } + + @Override + public Map> queryStatusOfAllApplicationInstances() { + // If we ever need to optimize this method, then consider reusing ServiceModel snapshots + // for up to X ms. + ServiceModel serviceModel = + superModelListener.createServiceModelSnapshot(zone, configServerHostnames); + return serviceModel.getAllApplicationInstances(); + } +} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SuperModelListenerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SuperModelListenerImpl.java new file mode 100644 index 00000000000..8beb90c382a --- /dev/null +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SuperModelListenerImpl.java @@ -0,0 +1,67 @@ +// 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.SuperModel; +import com.yahoo.config.model.api.SuperModelListener; +import com.yahoo.config.model.api.SuperModelProvider; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Zone; + +import java.util.List; +import java.util.logging.Logger; + +public class SuperModelListenerImpl implements SuperModelListener { + private static final Logger logger = Logger.getLogger(SuperModelListenerImpl.class.getName()); + + // Guard for updating superModel and slobrokMonitor exclusively and atomically: + // - superModel and slobrokMonitor must be updated in combination (exclusively and atomically) + // - Anyone may take a snapshot of superModel for reading purposes, hence volatile. + private final Object monitor = new Object(); + private final SlobrokMonitor2 slobrokMonitor; + private volatile SuperModel superModel; + + SuperModelListenerImpl(SlobrokMonitor2 slobrokMonitor) { + this.slobrokMonitor = slobrokMonitor; + } + + void start(SuperModelProvider superModelProvider) { + synchronized (monitor) { + // This snapshot() call needs to be within the synchronized block, + // since applicationActivated()/applicationRemoved() may be called + // asynchronously even before snapshot() returns. + SuperModel snapshot = superModelProvider.snapshot(this); + exclusiveUpdate(snapshot); + } + } + + @Override + public void applicationActivated(SuperModel superModel, ApplicationId applicationId) { + synchronized (monitor) { + exclusiveUpdate(superModel); + } + } + + @Override + public void applicationRemoved(SuperModel superModel, ApplicationId id) { + synchronized (monitor) { + exclusiveUpdate(superModel); + } + } + + ServiceModel createServiceModelSnapshot(Zone zone, List configServerHostnames) { + // Save a snapshot of volatile this.superModel outside of synchronized block. + SuperModel superModelSnapshot = this.superModel; + + ModelGenerator modelGenerator = new ModelGenerator(); + return modelGenerator.toServiceModel( + superModelSnapshot, + zone, + configServerHostnames, + slobrokMonitor); + } + + private void exclusiveUpdate(SuperModel superModel) { + this.superModel = superModel; + slobrokMonitor.updateSlobrokList(superModel); + } +} \ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SuperModelListenerImplTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SuperModelListenerImplTest.java new file mode 100644 index 00000000000..07e84b22d72 --- /dev/null +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SuperModelListenerImplTest.java @@ -0,0 +1,29 @@ +// 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.SuperModel; +import com.yahoo.config.provision.ApplicationId; +import org.junit.Test; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; + +public class SuperModelListenerImplTest { + private final SlobrokMonitor2 slobrokMonitor = mock(SlobrokMonitor2.class); + private final SuperModel superModel = mock(SuperModel.class); + private final ApplicationId applicationId = ApplicationId.defaultId(); + private final SuperModelListenerImpl listener = new SuperModelListenerImpl(slobrokMonitor); + + @Test + public void testActivateApplication() { + listener.applicationActivated(superModel, applicationId); + doNothing().when(slobrokMonitor).updateSlobrokList(superModel); + } + + @Test + public void testRemoveApplication() { + listener.applicationRemoved(superModel, applicationId); + doNothing().when(slobrokMonitor).updateSlobrokList(superModel); + } +} \ No newline at end of file -- cgit v1.2.3