summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java20
-rwxr-xr-xconfig-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java11
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerClusterTest.java4
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java3
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/BundleLoaderProperties.java15
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/config/DiskBundleInstaller.java15
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java4
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/config/PlatformBundleLoader.java48
-rw-r--r--container-core/src/test/java/com/yahoo/container/core/config/PlatformBundleLoaderTest.java64
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/Container.java10
-rw-r--r--container-di/src/main/java/com/yahoo/container/di/Osgi.java4
-rw-r--r--container-di/src/main/resources/configdefinitions/platform-bundles.def4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java27
-rw-r--r--searchlib/src/tests/common/location/geo_location_test.cpp276
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location.h2
-rw-r--r--standalone-container/src/test/java/com/yahoo/container/standalone/StandaloneSubscriberTest.java2
16 files changed, 409 insertions, 100 deletions
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 9cc83bb4275..08f4e2fa12f 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
@@ -14,12 +14,11 @@ import com.yahoo.vespa.model.container.Container;
import com.yahoo.vespa.model.container.component.AccessLogComponent;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.xml.PlatformBundles;
import java.util.Set;
import java.util.TreeSet;
-import static com.yahoo.vespa.defaults.Defaults.getDefaults;
-
/**
* Container implementation for cluster-controllers
*/
@@ -55,11 +54,12 @@ public class ClusterControllerContainer extends Container implements
}
addComponent(new AccessLogComponent(AccessLogComponent.AccessLogType.jsonAccessLog, "controller", isHosted));
- addFileBundle("lib/jars/clustercontroller-apps-jar-with-dependencies.jar");
- addFileBundle("lib/jars/clustercontroller-apputil-jar-with-dependencies.jar");
- addFileBundle("lib/jars/clustercontroller-core-jar-with-dependencies.jar");
- addFileBundle("lib/jars/clustercontroller-utils-jar-with-dependencies.jar");
- addFileBundle("lib/jars/zookeeper-server-jar-with-dependencies.jar");
+ // TODO: Why are bundles added here instead of in the cluster?
+ addFileBundle("clustercontroller-apps");
+ addFileBundle("clustercontroller-apputil");
+ addFileBundle("clustercontroller-core");
+ addFileBundle("clustercontroller-utils");
+ addFileBundle("zookeeper-server");
}
@Override
@@ -82,8 +82,8 @@ public class ClusterControllerContainer extends Container implements
super.addHandler(h);
}
- private void addFileBundle(String bundlePath) {
- bundles.add("file:" + getDefaults().underVespaHome(bundlePath));
+ private void addFileBundle(String bundleName) {
+ bundles.add(PlatformBundles.absoluteBundlePath(bundleName).toString());
}
private ComponentModel createComponentModel(String id, String className, ComponentSpecification bundle) {
@@ -103,7 +103,7 @@ public class ClusterControllerContainer extends Container implements
@Override
public void getConfig(PlatformBundlesConfig.Builder builder) {
- bundles.forEach(builder::bundles);
+ bundles.forEach(builder::bundlePaths);
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
index e2d0868cb9d..240157fb7aa 100755
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
@@ -69,8 +69,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import static com.yahoo.container.core.BundleLoaderProperties.DISK_BUNDLE_PREFIX;
-
/**
* Parent class for all container cluster types.
*
@@ -474,12 +472,9 @@ public abstract class ContainerCluster<CONTAINER extends Container>
@Override
public void getConfig(PlatformBundlesConfig.Builder builder) {
- platformBundles.stream() .map(ContainerCluster::toFileReferenceString)
- .forEach(builder::bundles);
- }
-
- private static String toFileReferenceString(Path path) {
- return DISK_BUNDLE_PREFIX + path.toString();
+ platformBundles.stream()
+ .map(Path::toString)
+ .forEach(builder::bundlePaths);
}
@Override
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerClusterTest.java
index 754f4b66070..34f06519ac9 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerClusterTest.java
@@ -58,8 +58,8 @@ public class MetricsProxyContainerClusterTest {
var builder = new PlatformBundlesConfig.Builder();
model.getConfig(builder, CLUSTER_CONFIG_ID);
PlatformBundlesConfig config = builder.build();
- assertEquals(1, config.bundles().size());
- assertThat(config.bundles(0).value(), endsWith(METRICS_PROXY_BUNDLE_FILE.toString()));
+ assertEquals(1, config.bundlePaths().size());
+ assertThat(config.bundlePaths(0), endsWith(METRICS_PROXY_BUNDLE_FILE.toString()));
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
index 07b6cd72bdb..97359b392a5 100755
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
@@ -4,7 +4,6 @@ package com.yahoo.vespa.model.container;
import com.yahoo.cloud.config.ClusterInfoConfig;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.cloud.config.RoutingProviderConfig;
-import com.yahoo.config.FileReference;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
@@ -294,7 +293,7 @@ public class ContainerClusterTest {
ApplicationContainerCluster cluster = new ApplicationContainerCluster(root, "container0", "container1", state);
var bundleBuilder = new PlatformBundlesConfig.Builder();
cluster.getConfig(bundleBuilder);
- List<String> installedBundles = bundleBuilder.build().bundles().stream().map(FileReference::value).collect(Collectors.toList());
+ List<String> installedBundles = bundleBuilder.build().bundlePaths();
assertEquals(expectedBundleNames.size(), installedBundles.size());
assertThat(installedBundles, containsInAnyOrder(
diff --git a/container-core/src/main/java/com/yahoo/container/core/BundleLoaderProperties.java b/container-core/src/main/java/com/yahoo/container/core/BundleLoaderProperties.java
deleted file mode 100644
index ee12c7d4c9f..00000000000
--- a/container-core/src/main/java/com/yahoo/container/core/BundleLoaderProperties.java
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.core;
-
-/**
- * @author gjoranv
- */
-public interface BundleLoaderProperties {
-
- // TODO: This should be removed. The prefix is used to separate the bundles in BundlesConfig
- // into those that are transferred with filedistribution and those that are preinstalled
- // on disk. Instead, the model should have put them in two different configs. I.e. create a new
- // config 'preinstalled-bundles.def'.
- String DISK_BUNDLE_PREFIX = "file:";
-
-}
diff --git a/container-core/src/main/java/com/yahoo/container/core/config/DiskBundleInstaller.java b/container-core/src/main/java/com/yahoo/container/core/config/DiskBundleInstaller.java
index 3edabe9f861..a4cce2e38db 100644
--- a/container-core/src/main/java/com/yahoo/container/core/config/DiskBundleInstaller.java
+++ b/container-core/src/main/java/com/yahoo/container/core/config/DiskBundleInstaller.java
@@ -1,28 +1,21 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.core.config;
-import com.yahoo.config.FileReference;
import com.yahoo.osgi.Osgi;
import org.osgi.framework.Bundle;
import java.io.File;
import java.util.List;
-import static com.yahoo.container.core.BundleLoaderProperties.DISK_BUNDLE_PREFIX;
-
/**
* @author gjoranv
*/
-public class DiskBundleInstaller implements BundleInstaller {
-
- @Override
- public List<Bundle> installBundles(FileReference reference, Osgi osgi) {
- assert(reference.value().startsWith(DISK_BUNDLE_PREFIX));
- String referenceFileName = reference.value().substring(DISK_BUNDLE_PREFIX.length());
+public class DiskBundleInstaller {
- File file = new File(referenceFileName);
+ public List<Bundle> installBundles(String bundlePath, Osgi osgi) {
+ File file = new File(bundlePath);
if ( ! file.exists()) {
- throw new IllegalArgumentException("Reference '" + reference.value() + "' not found on disk.");
+ throw new IllegalArgumentException("Bundle file '" + bundlePath + "' not found on disk.");
}
return osgi.install(file.getAbsolutePath());
diff --git a/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java b/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
index 80c39bef2cb..a58dff13f09 100644
--- a/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
+++ b/container-core/src/main/java/com/yahoo/container/core/config/HandlersConfigurerDi.java
@@ -135,9 +135,9 @@ public class HandlersConfigurerDi {
}
@Override
- public void installPlatformBundles(Collection<FileReference> bundles) {
+ public void installPlatformBundles(Collection<String> bundlePaths) {
log.fine("Installing platform bundles.");
- platformBundleLoader.useBundles(new ArrayList<>(bundles));
+ platformBundleLoader.useBundles(new ArrayList<>(bundlePaths));
}
@Override
diff --git a/container-core/src/main/java/com/yahoo/container/core/config/PlatformBundleLoader.java b/container-core/src/main/java/com/yahoo/container/core/config/PlatformBundleLoader.java
index f922bc0cb25..0ab89e223f6 100644
--- a/container-core/src/main/java/com/yahoo/container/core/config/PlatformBundleLoader.java
+++ b/container-core/src/main/java/com/yahoo/container/core/config/PlatformBundleLoader.java
@@ -1,6 +1,5 @@
package com.yahoo.container.core.config;
-import com.yahoo.config.FileReference;
import com.yahoo.osgi.Osgi;
import org.osgi.framework.Bundle;
@@ -10,8 +9,13 @@ import java.util.Set;
import java.util.logging.Logger;
/**
- * Installs all platform bundles, using the {@link DiskBundleInstaller}.
+ * Used to install the bundles that are added as platform bundles by the config-model.
+ *
* All platform bundles reside on disk, and they are never uninstalled.
+ * Platform bundles are allowed to pre-install other bundles on disk via the
+ * X-JDisc-Preinstall-Bundle manifest header.
+ *
+ * Attempts to install additional bundles, after the first call, should be a NOP.
*
* @author gjoranv
*/
@@ -21,33 +25,47 @@ public class PlatformBundleLoader {
private final Osgi osgi;
private final DiskBundleInstaller installer;
+ private Set<Bundle> installedBundles;
+ private boolean hasLoadedBundles = false;
+
public PlatformBundleLoader(Osgi osgi) {
+ this(osgi, new DiskBundleInstaller());
+ }
+
+ PlatformBundleLoader(Osgi osgi, DiskBundleInstaller installer) {
this.osgi = osgi;
- installer = new DiskBundleInstaller();
+ this.installer = installer;
}
- public void useBundles(List<FileReference> fileReferences) {
- Set<Bundle> installedBundles = install(fileReferences);
+ public void useBundles(List<String> bundlePaths) {
+ if (hasLoadedBundles) {
+ log.fine(() -> "Platform bundles have already been installed." +
+ "\nInstalled bundles: " + installedBundles +
+ "\nGiven files: " + bundlePaths);
+ return;
+ }
+ installedBundles = install(bundlePaths);
BundleStarter.startBundles(installedBundles);
+ hasLoadedBundles = true;
}
- private Set<Bundle> install(List<FileReference> bundlesToInstall) {
- var installedBundles = new LinkedHashSet<Bundle>();
- for (FileReference reference : bundlesToInstall) {
+ private Set<Bundle> install(List<String> bundlesToInstall) {
+ var allInstalled = new LinkedHashSet<Bundle>();
+ for (String bundlePath : bundlesToInstall) {
try {
- installedBundles.addAll(installBundleFromDisk(reference));
+ allInstalled.addAll(installBundleFromDisk(bundlePath));
}
catch(Exception e) {
- throw new RuntimeException("Could not install bundle '" + reference + "'", e);
+ throw new RuntimeException("Could not install bundle '" + bundlePath + "'", e);
}
}
- return installedBundles;
+ return allInstalled;
}
- private List<Bundle> installBundleFromDisk(FileReference reference) {
- log.info("Installing bundle from disk with reference '" + reference.value() + "'");
- List<Bundle> bundles = installer.installBundles(reference, osgi);
- log.fine("Installed " + bundles.size() + " bundles for file reference " + reference);
+ private List<Bundle> installBundleFromDisk(String bundlePath) {
+ log.info("Installing bundle from disk: " + bundlePath);
+ List<Bundle> bundles = installer.installBundles(bundlePath, osgi);
+ log.fine("Installed " + bundles.size() + " bundles for file " + bundlePath);
return bundles;
}
diff --git a/container-core/src/test/java/com/yahoo/container/core/config/PlatformBundleLoaderTest.java b/container-core/src/test/java/com/yahoo/container/core/config/PlatformBundleLoaderTest.java
new file mode 100644
index 00000000000..931b0c547fd
--- /dev/null
+++ b/container-core/src/test/java/com/yahoo/container/core/config/PlatformBundleLoaderTest.java
@@ -0,0 +1,64 @@
+package com.yahoo.container.core.config;
+
+import com.yahoo.osgi.Osgi;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author gjoranv
+ */
+public class PlatformBundleLoaderTest {
+
+ private static final String BUNDLE_1_REF = "bundle-1";
+ private static final Bundle BUNDLE_1 = new TestBundle(BUNDLE_1_REF);
+ private static final String BUNDLE_2_REF = "bundle-2";
+ private static final Bundle BUNDLE_2 = new TestBundle(BUNDLE_2_REF);
+
+ private PlatformBundleLoader bundleLoader;
+ private TestOsgi osgi;
+
+ @Before
+ public void setup() {
+ osgi = new TestOsgi(testBundles());
+ bundleLoader = new PlatformBundleLoader(osgi, new TestBundleInstaller());
+ }
+
+ @Test
+ public void bundles_are_installed_and_started() {
+ bundleLoader.useBundles(List.of(BUNDLE_1_REF));
+ assertEquals(1, osgi.getInstalledBundles().size());
+
+ // The bundle is installed and started
+ TestBundle installedBundle = (TestBundle)osgi.getInstalledBundles().get(0);
+ assertEquals(BUNDLE_1.getSymbolicName(), installedBundle.getSymbolicName());
+ assertTrue(installedBundle.started);
+ }
+
+ @Test
+ public void bundles_cannot_be_added_by_later_calls() {
+ bundleLoader.useBundles(List.of(BUNDLE_1_REF));
+ bundleLoader.useBundles(List.of(BUNDLE_2_REF)); // Should be a NOP
+
+ assertEquals(1, osgi.getInstalledBundles().size());
+ assertEquals(BUNDLE_1.getSymbolicName(), osgi.getInstalledBundles().get(0).getSymbolicName());
+ }
+
+ private static Map<String, Bundle> testBundles() {
+ return Map.of(BUNDLE_1_REF, BUNDLE_1,
+ BUNDLE_2_REF, BUNDLE_2);
+ }
+
+ static class TestBundleInstaller extends DiskBundleInstaller {
+ @Override
+ public List<Bundle> installBundles(String bundlePath, Osgi osgi) {
+ return osgi.install(bundlePath);
+ }
+ }
+}
diff --git a/container-di/src/main/java/com/yahoo/container/di/Container.java b/container-di/src/main/java/com/yahoo/container/di/Container.java
index 672cef22010..af580767a17 100644
--- a/container-di/src/main/java/com/yahoo/container/di/Container.java
+++ b/container-di/src/main/java/com/yahoo/container/di/Container.java
@@ -4,11 +4,11 @@ package com.yahoo.container.di;
import com.google.inject.Injector;
import com.yahoo.config.ConfigInstance;
import com.yahoo.config.ConfigurationRuntimeException;
-import com.yahoo.config.FileReference;
import com.yahoo.config.subscription.ConfigInterruptedException;
import com.yahoo.container.ComponentsConfig;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.container.di.ConfigRetriever.BootstrapConfigs;
+import com.yahoo.container.di.ConfigRetriever.ComponentsConfigs;
import com.yahoo.container.di.ConfigRetriever.ConfigSnapshot;
import com.yahoo.container.di.componentgraph.core.ComponentGraph;
import com.yahoo.container.di.componentgraph.core.ComponentNode;
@@ -50,7 +50,7 @@ public class Container {
private final Osgi osgi;
private final ConfigRetriever configurer;
- private List<FileReference> platformBundles; // Used to verify that platform bundles don't change.
+ private List<String> platformBundles; // Used to verify that platform bundles don't change.
private long previousConfigGeneration = -1L;
private long leastGeneration = -1L;
@@ -106,7 +106,7 @@ public class Container {
log.log(FINE, "Got new bootstrap generation\n" + configGenerationsString());
if (graph.generation() == 0) {
- platformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundles();
+ platformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundlePaths();
osgi.installPlatformBundles(platformBundles);
} else {
throwIfPlatformBundlesChanged(snapshot);
@@ -118,7 +118,7 @@ public class Container {
// Continues loop
- } else if (snapshot instanceof ConfigRetriever.ComponentsConfigs) {
+ } else if (snapshot instanceof ComponentsConfigs) {
break;
}
}
@@ -140,7 +140,7 @@ public class Container {
}
private void throwIfPlatformBundlesChanged(ConfigSnapshot snapshot) {
- var checkPlatformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundles();
+ var checkPlatformBundles = getConfig(platformBundlesConfigKey, snapshot.configs()).bundlePaths();
if (! checkPlatformBundles.equals(platformBundles))
throw new RuntimeException("Platform bundles are not allowed to change!\nOld: " + platformBundles + "\nNew: " + checkPlatformBundles);
}
diff --git a/container-di/src/main/java/com/yahoo/container/di/Osgi.java b/container-di/src/main/java/com/yahoo/container/di/Osgi.java
index c9ca256b5e0..940986e2f38 100644
--- a/container-di/src/main/java/com/yahoo/container/di/Osgi.java
+++ b/container-di/src/main/java/com/yahoo/container/di/Osgi.java
@@ -25,8 +25,8 @@ public interface Osgi {
return new BundleClasses(new MockBundle(), Collections.emptySet());
}
- default void installPlatformBundles(Collection<FileReference> bundles) {
- System.out.println("installPlatformBundles " + bundles.stream().map(Object::toString).collect(Collectors.joining(", ")));
+ default void installPlatformBundles(Collection<String> bundlePaths) {
+ System.out.println("installPlatformBundles " + bundlePaths);
}
/**
diff --git a/container-di/src/main/resources/configdefinitions/platform-bundles.def b/container-di/src/main/resources/configdefinitions/platform-bundles.def
index 9b72bf6831e..a30a846b565 100644
--- a/container-di/src/main/resources/configdefinitions/platform-bundles.def
+++ b/container-di/src/main/resources/configdefinitions/platform-bundles.def
@@ -1,5 +1,5 @@
# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package=com.yahoo.container.di.config
-# References to platform bundles to install.
-bundles[] file
+# Paths to platform bundles to install.
+bundlePaths[] string
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java
index 3f8cc58540d..2afbb0e6476 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/FailedExpirer.java
@@ -3,7 +3,6 @@ package com.yahoo.vespa.hosted.provision.maintenance;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Zone;
import com.yahoo.jdisc.Metric;
@@ -23,24 +22,21 @@ import java.util.stream.Collectors;
/**
* This moves expired failed nodes:
- * <ul>
- * <li>To parked: If the node has known hardware failure, Docker hosts are moved to parked only when all of their
- * children are already in parked
- * <li>To dirty: If the node has failed less than 5 times OR the environment is dev, test or perf.
- * Those environments have no protection against users running bogus applications, so
- * we cannot use the node failure count to conclude the node has a failure.
- * <li>Otherwise the node will remain in failed
- * </ul>
+ *
+ * - To parked: If the node has known hardware failure, Docker hosts are moved to parked only when all of their
+ * children are already in parked.
+ * - To dirty: If the node is a host and has failed less than 5 times, or always if the node is a child.
+ * - Otherwise the node will remain in failed.
+ *
* Failed content nodes are given a long expiry time to enable us to manually moved them back to
* active to recover data in cases where the node was failed accidentally.
- * <p>
+ *
* Failed container (Vespa, not Docker) nodes are expired early as there's no data to potentially recover.
- * </p>
- * <p>
+ *
* The purpose of the automatic recycling to dirty + fail count is that nodes which were moved
* to failed due to some undetected hardware failure will end up being failed again.
* When that has happened enough they will not be recycled.
- * <p>
+ *
* Nodes with detected hardware issues will not be recycled.
*
* @author bratseth
@@ -125,8 +121,7 @@ public class FailedExpirer extends NodeRepositoryMaintainer {
/** Returns whether the current node fail count should be used as an indicator of hardware issue */
private boolean failCountIndicatesHardwareIssue(Node node) {
- if (node.flavor().getType() == Flavor.Type.DOCKER_CONTAINER) return false;
- return (zone.environment() == Environment.prod || zone.environment() == Environment.staging) &&
- node.status().failCount() >= maxAllowedFailures;
+ return node.type().isHost() && node.status().failCount() >= maxAllowedFailures;
}
+
}
diff --git a/searchlib/src/tests/common/location/geo_location_test.cpp b/searchlib/src/tests/common/location/geo_location_test.cpp
index 8093ea61697..31b844d0fc8 100644
--- a/searchlib/src/tests/common/location/geo_location_test.cpp
+++ b/searchlib/src/tests/common/location/geo_location_test.cpp
@@ -9,6 +9,15 @@
using search::common::GeoLocation;
using search::common::GeoLocationParser;
+using Box = search::common::GeoLocation::Box;
+using Point = search::common::GeoLocation::Point;
+using Range = search::common::GeoLocation::Range;
+using Aspect = search::common::GeoLocation::Aspect;
+
+constexpr int32_t plus_inf = std::numeric_limits<int32_t>::max();
+constexpr int32_t minus_inf = std::numeric_limits<int32_t>::min();
+constexpr uint32_t u32_inf = std::numeric_limits<uint32_t>::max();
+
bool is_parseable(const char *str) {
GeoLocationParser parser;
return parser.parseOldFormat(str);
@@ -20,7 +29,7 @@ GeoLocation parse(const char *str) {
return parser.getGeoLocation();
}
-TEST(GeoLocationTest, malformed_bounding_boxes_are_not_parseable) {
+TEST(GeoLocationParserTest, malformed_bounding_boxes_are_not_parseable) {
EXPECT_TRUE(is_parseable("[2,10,20,30,40]"));
EXPECT_FALSE(is_parseable("[2,10,20,30,40][2,10,20,30,40]"));
EXPECT_FALSE(is_parseable("[1,10,20,30,40]"));
@@ -31,7 +40,7 @@ TEST(GeoLocationTest, malformed_bounding_boxes_are_not_parseable) {
EXPECT_FALSE(is_parseable("[10,20,30,40]"));
}
-TEST(GeoLocationTest, malformed_circles_are_not_parseable) {
+TEST(GeoLocationParserTest, malformed_circles_are_not_parseable) {
EXPECT_TRUE(is_parseable("(2,10,20,5,0,0,0)"));
EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0)(2,10,20,5,0,0,0)"));
EXPECT_FALSE(is_parseable("(1,10,20,5,0,0,0)"));
@@ -43,7 +52,7 @@ TEST(GeoLocationTest, malformed_circles_are_not_parseable) {
EXPECT_FALSE(is_parseable("(10,20,5)"));
}
-TEST(GeoLocationTest, bounding_boxes_can_be_parsed) {
+TEST(GeoLocationParserTest, bounding_boxes_can_be_parsed) {
auto loc = parse("[2,10,20,30,40]");
EXPECT_EQ(false, loc.has_point);
EXPECT_EQ(true, loc.bounding_box.active());
@@ -57,7 +66,7 @@ TEST(GeoLocationTest, bounding_boxes_can_be_parsed) {
EXPECT_EQ(40, loc.bounding_box.y.high);
}
-TEST(GeoLocationTest, circles_can_be_parsed) {
+TEST(GeoLocationParserTest, circles_can_be_parsed) {
auto loc = parse("(2,10,20,5,0,0,0)");
EXPECT_EQ(true, loc.has_point);
EXPECT_EQ(true, loc.bounding_box.active());
@@ -71,7 +80,7 @@ TEST(GeoLocationTest, circles_can_be_parsed) {
EXPECT_EQ(25, loc.bounding_box.y.high);
}
-TEST(GeoLocationTest, circles_can_have_aspect_ratio) {
+TEST(GeoLocationParserTest, circles_can_have_aspect_ratio) {
auto loc = parse("(2,10,20,5,0,0,0,2147483648)");
EXPECT_EQ(true, loc.has_point);
EXPECT_EQ(true, loc.bounding_box.active());
@@ -85,7 +94,7 @@ TEST(GeoLocationTest, circles_can_have_aspect_ratio) {
EXPECT_EQ(25, loc.bounding_box.y.high);
}
-TEST(GeoLocationTest, bounding_box_can_be_specified_after_circle) {
+TEST(GeoLocationParserTest, bounding_box_can_be_specified_after_circle) {
auto loc = parse("(2,10,20,5,0,0,0)[2,10,20,30,40]");
EXPECT_EQ(true, loc.has_point);
EXPECT_EQ(true, loc.bounding_box.active());
@@ -99,7 +108,7 @@ TEST(GeoLocationTest, bounding_box_can_be_specified_after_circle) {
EXPECT_EQ(25, loc.bounding_box.y.high);
}
-TEST(GeoLocationTest, circles_can_be_specified_after_bounding_box) {
+TEST(GeoLocationParserTest, circles_can_be_specified_after_bounding_box) {
auto loc = parse("[2,10,20,30,40](2,10,20,5,0,0,0)");
EXPECT_EQ(true, loc.has_point);
EXPECT_EQ(true, loc.bounding_box.active());
@@ -113,13 +122,13 @@ TEST(GeoLocationTest, circles_can_be_specified_after_bounding_box) {
EXPECT_EQ(25, loc.bounding_box.y.high);
}
-TEST(GeoLocationTest, santa_search_gives_non_wrapped_bounding_box) {
+TEST(GeoLocationParserTest, santa_search_gives_non_wrapped_bounding_box) {
auto loc = parse("(2,122163600,89998536,290112,4,2000,0,109704)");
EXPECT_GE(loc.bounding_box.x.high, loc.bounding_box.x.low);
EXPECT_GE(loc.bounding_box.y.high, loc.bounding_box.y.low);
}
-TEST(GeoLocationTest, near_boundary_search_gives_non_wrapped_bounding_box) {
+TEST(GeoLocationParserTest, near_boundary_search_gives_non_wrapped_bounding_box) {
auto loc1 = parse("(2,2000000000,2000000000,3000000000,0,1,0)");
EXPECT_GE(loc1.bounding_box.x.high, loc1.bounding_box.x.low);
EXPECT_GE(loc1.bounding_box.y.high, loc1.bounding_box.y.low);
@@ -133,4 +142,253 @@ TEST(GeoLocationTest, near_boundary_search_gives_non_wrapped_bounding_box) {
EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.y.low);
}
+void check_box(const GeoLocation &location, Box expected)
+{
+ int32_t lx = expected.x.low;
+ int32_t hx = expected.x.high;
+ int32_t ly = expected.y.low;
+ int32_t hy = expected.y.high;
+ EXPECT_TRUE(location.inside_limit(Point{lx,ly}));
+ EXPECT_TRUE(location.inside_limit(Point{lx,hy}));
+ EXPECT_TRUE(location.inside_limit(Point{hx,ly}));
+ EXPECT_TRUE(location.inside_limit(Point{hx,hy}));
+
+ EXPECT_FALSE(location.inside_limit(Point{lx,ly-1}));
+ EXPECT_FALSE(location.inside_limit(Point{lx,hy+1}));
+ EXPECT_FALSE(location.inside_limit(Point{lx-1,ly}));
+ EXPECT_FALSE(location.inside_limit(Point{lx-1,hy}));
+ EXPECT_FALSE(location.inside_limit(Point{hx,ly-1}));
+ EXPECT_FALSE(location.inside_limit(Point{hx,hy+1}));
+ EXPECT_FALSE(location.inside_limit(Point{hx+1,ly}));
+ EXPECT_FALSE(location.inside_limit(Point{hx+1,hy}));
+
+ EXPECT_FALSE(location.inside_limit(Point{plus_inf,plus_inf}));
+ EXPECT_FALSE(location.inside_limit(Point{minus_inf,minus_inf}));
+}
+
+TEST(GeoLocationTest, invalid_location) {
+ GeoLocation invalid;
+ EXPECT_FALSE(invalid.valid());
+ EXPECT_FALSE(invalid.has_radius());
+ EXPECT_FALSE(invalid.can_limit());
+ EXPECT_FALSE(invalid.has_point);
+ EXPECT_FALSE(invalid.bounding_box.active());
+ EXPECT_FALSE(invalid.x_aspect.active());
+
+ EXPECT_EQ(invalid.sq_distance_to(Point{0,0}), 0);
+ EXPECT_EQ(invalid.sq_distance_to(Point{999999,999999}), 0);
+ EXPECT_EQ(invalid.sq_distance_to(Point{-999999,-999999}), 0);
+ EXPECT_EQ(invalid.sq_distance_to(Point{plus_inf,plus_inf}), 0);
+ EXPECT_EQ(invalid.sq_distance_to(Point{minus_inf,minus_inf}), 0);
+
+ EXPECT_TRUE(invalid.inside_limit(Point{0,0}));
+ EXPECT_TRUE(invalid.inside_limit(Point{999999,999999}));
+ EXPECT_TRUE(invalid.inside_limit(Point{-999999,-999999}));
+ EXPECT_TRUE(invalid.inside_limit(Point{plus_inf,plus_inf}));
+ EXPECT_TRUE(invalid.inside_limit(Point{minus_inf,minus_inf}));
+}
+
+TEST(GeoLocationTest, point_location) {
+ GeoLocation location(Point{300,-400});
+ EXPECT_TRUE(location.valid());
+ EXPECT_FALSE(location.has_radius());
+ EXPECT_FALSE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_FALSE(location.bounding_box.active());
+ EXPECT_FALSE(location.x_aspect.active());
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{300,-400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{300,400}), 640000);
+
+ EXPECT_TRUE(location.inside_limit(Point{0,0}));
+ EXPECT_TRUE(location.inside_limit(Point{999999,999999}));
+ EXPECT_TRUE(location.inside_limit(Point{-999999,-999999}));
+ EXPECT_TRUE(location.inside_limit(Point{plus_inf,plus_inf}));
+ EXPECT_TRUE(location.inside_limit(Point{minus_inf,minus_inf}));
+}
+
+TEST(GeoLocationTest, point_and_radius) {
+ GeoLocation location(Point{300,-400}, 500);
+ EXPECT_TRUE(location.valid());
+ EXPECT_TRUE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_FALSE(location.x_aspect.active());
+
+ EXPECT_EQ(location.radius, 500);
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{300,-400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{300,400}), 640000);
+
+ EXPECT_TRUE(location.inside_limit(Point{0,0}));
+ EXPECT_TRUE(location.inside_limit(Point{-200,-400}));
+ EXPECT_TRUE(location.inside_limit(Point{800,-400}));
+ EXPECT_TRUE(location.inside_limit(Point{300,-400}));
+ EXPECT_TRUE(location.inside_limit(Point{300,100}));
+ EXPECT_TRUE(location.inside_limit(Point{300,-900}));
+
+ check_box(location, Box{Range{0,600},{-800,0}});
+}
+
+TEST(GeoLocationTest, point_and_aspect) {
+ GeoLocation location(Point{600,400}, Aspect{0.5});
+ // same: GeoLocation location(Point{600,400}, Aspect{1ul << 31});
+ EXPECT_TRUE(location.valid());
+ EXPECT_FALSE(location.has_radius());
+ EXPECT_FALSE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_FALSE(location.bounding_box.active());
+ EXPECT_TRUE(location.x_aspect.active());
+ EXPECT_EQ(location.x_aspect.multiplier, 1ul << 31);
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{600,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{1200,800}), 500*500);
+
+ EXPECT_TRUE(location.inside_limit(Point{0,0}));
+ EXPECT_TRUE(location.inside_limit(Point{999999,999999}));
+ EXPECT_TRUE(location.inside_limit(Point{-999999,-999999}));
+ EXPECT_TRUE(location.inside_limit(Point{plus_inf,plus_inf}));
+ EXPECT_TRUE(location.inside_limit(Point{minus_inf,minus_inf}));
+}
+
+TEST(GeoLocationTest, point_radius_and_aspect) {
+ GeoLocation location(Point{1200,400}, 500, Aspect{0.25});
+ EXPECT_TRUE(location.valid());
+ EXPECT_TRUE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_TRUE(location.x_aspect.active());
+ EXPECT_EQ(location.x_aspect.multiplier, 1ul << 30);
+
+ EXPECT_EQ(location.radius, 500);
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{1200,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{1240,400}), 100);
+
+ EXPECT_TRUE(location.inside_limit(Point{1200,400}));
+ EXPECT_TRUE(location.inside_limit(Point{0,0}));
+ EXPECT_TRUE(location.inside_limit(Point{2400,0}));
+ EXPECT_TRUE(location.inside_limit(Point{2400,800}));
+ EXPECT_TRUE(location.inside_limit(Point{0,800}));
+ // note: must be 4 outside since 3*0.25 may be truncated to 0
+ EXPECT_FALSE(location.inside_limit(Point{-4,0}));
+ EXPECT_FALSE(location.inside_limit(Point{-4,800}));
+ EXPECT_FALSE(location.inside_limit(Point{2404,0}));
+ EXPECT_FALSE(location.inside_limit(Point{2404,800}));
+ EXPECT_FALSE(location.inside_limit(Point{2400,-1}));
+ EXPECT_FALSE(location.inside_limit(Point{2400,801}));
+ EXPECT_FALSE(location.inside_limit(Point{0,-1}));
+ EXPECT_FALSE(location.inside_limit(Point{0,801}));
+ EXPECT_FALSE(location.inside_limit(Point{plus_inf,plus_inf}));
+ EXPECT_FALSE(location.inside_limit(Point{minus_inf,minus_inf}));
+}
+
+TEST(GeoLocationTest, box_location) {
+ Box mybox{Range{300,350},Range{400,450}};
+ GeoLocation location(mybox);
+ EXPECT_TRUE(location.valid());
+ EXPECT_FALSE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_FALSE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_FALSE(location.x_aspect.active());
+
+ // currently does not measure distance outside box:
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{300,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{350,450}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{450,550}), 0);
+
+ EXPECT_TRUE(location.inside_limit(Point{333,444}));
+ EXPECT_FALSE(location.inside_limit(Point{0,0}));
+ check_box(location, mybox);
+}
+
+TEST(GeoLocationTest, box_and_point) {
+ Box mybox{Range{287,343},Range{366,401}};
+ GeoLocation location(mybox, Point{300,400});
+ EXPECT_TRUE(location.valid());
+ EXPECT_FALSE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_FALSE(location.x_aspect.active());
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{300,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{300,423}), 23*23);
+
+ check_box(location, mybox);
+}
+
+TEST(GeoLocationTest, box_point_and_aspect) {
+ Box mybox{Range{-1000,350},Range{-1000,600}};
+ GeoLocation location(mybox, Point{600,400}, Aspect{0.5});
+ EXPECT_TRUE(location.valid());
+ EXPECT_FALSE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_TRUE(location.x_aspect.active());
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{600,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{600,407}), 7*7);
+ EXPECT_EQ(location.sq_distance_to(Point{614,400}), 7*7);
+
+ check_box(location, mybox);
+}
+
+TEST(GeoLocationTest, box_point_and_radius) {
+ Box mybox{Range{-1000,350},Range{-1000,600}};
+ GeoLocation location(mybox, Point{300,400}, 500);
+ EXPECT_TRUE(location.valid());
+ EXPECT_TRUE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_FALSE(location.x_aspect.active());
+
+ EXPECT_EQ(location.radius, 500);
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{300,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{300,423}), 23*23);
+
+ EXPECT_EQ(location.bounding_box.x.low, -200);
+ EXPECT_EQ(location.bounding_box.y.low, -100);
+ EXPECT_EQ(location.bounding_box.x.high, 350);
+ EXPECT_EQ(location.bounding_box.y.high, 600);
+}
+
+TEST(GeoLocationTest, box_point_radius_and_aspect) {
+ Box mybox{Range{-1000,650},Range{-1000,700}};
+ GeoLocation location(mybox, Point{600,400}, 500, Aspect{0.5});
+ EXPECT_TRUE(location.valid());
+ EXPECT_TRUE(location.has_radius());
+ EXPECT_TRUE(location.can_limit());
+ EXPECT_TRUE(location.has_point);
+ EXPECT_TRUE(location.bounding_box.active());
+ EXPECT_TRUE(location.x_aspect.active());
+
+ EXPECT_EQ(location.radius, 500);
+
+ EXPECT_EQ(location.sq_distance_to(Point{0,0}), 500*500);
+ EXPECT_EQ(location.sq_distance_to(Point{600,400}), 0);
+ EXPECT_EQ(location.sq_distance_to(Point{600,407}), 7*7);
+ EXPECT_EQ(location.sq_distance_to(Point{614,400}), 7*7);
+
+ EXPECT_GE(location.bounding_box.x.low, -402);
+ EXPECT_LE(location.bounding_box.x.low, -400);
+ EXPECT_EQ(location.bounding_box.y.low, -100);
+ EXPECT_EQ(location.bounding_box.x.high, 650);
+ EXPECT_EQ(location.bounding_box.y.high, 700);
+}
+
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/vespa/searchlib/common/geo_location.h b/searchlib/src/vespa/searchlib/common/geo_location.h
index 5d04a09142a..261951caf3e 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location.h
+++ b/searchlib/src/vespa/searchlib/common/geo_location.h
@@ -28,6 +28,8 @@ struct GeoLocation
uint32_t multiplier;
Aspect() : multiplier(0) {}
Aspect(uint32_t multiplier_in) : multiplier(multiplier_in) {}
+ // for unit tests:
+ Aspect(double multiplier_in) : multiplier(multiplier_in*4294967296.0) {}
bool active() const { return multiplier != 0; }
};
struct Range {
diff --git a/standalone-container/src/test/java/com/yahoo/container/standalone/StandaloneSubscriberTest.java b/standalone-container/src/test/java/com/yahoo/container/standalone/StandaloneSubscriberTest.java
index 9ba1a56083a..8ca20fdf7cd 100644
--- a/standalone-container/src/test/java/com/yahoo/container/standalone/StandaloneSubscriberTest.java
+++ b/standalone-container/src/test/java/com/yahoo/container/standalone/StandaloneSubscriberTest.java
@@ -48,7 +48,7 @@ public class StandaloneSubscriberTest {
ApplicationBundlesConfig applicationBundlesConfig = (ApplicationBundlesConfig) config.get(applicationBundlesKey);
ComponentsConfig componentsConfig = (ComponentsConfig) config.get(componentsKey);
- assertThat(platformBundlesConfig.bundles().size(), is(0));
+ assertThat(platformBundlesConfig.bundlePaths().size(), is(0));
assertThat(applicationBundlesConfig.bundles().size(), is(0));
assertThat(componentsConfig.components().size(), greaterThan(10));
return null;