// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.container.xml; import com.yahoo.config.application.api.ApplicationPackage; import com.yahoo.config.model.NullConfigModelRegistry; import com.yahoo.config.model.builder.xml.test.DomBuilderTest; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.test.MockApplicationPackage; import com.yahoo.search.config.QrStartConfig; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.container.ContainerCluster; import org.junit.Test; import org.w3c.dom.Element; import org.xml.sax.SAXException; import java.io.IOException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author baldersheim * @author gjoranv */ public class JvmOptionsTest extends ContainerModelBuilderTestBase { @Test public void verify_jvm_tag_with_attributes() throws IOException, SAXException { String servicesXml = "" + " " + " " + " " + " " + " " + ""; ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).build(); // Need to create VespaModel to make deploy properties have effect final TestLogger logger = new TestLogger(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder() .applicationPackage(applicationPackage) .deployLogger(logger) .build()); QrStartConfig.Builder qrStartBuilder = new QrStartConfig.Builder(); model.getConfig(qrStartBuilder, "container/container.0"); QrStartConfig qrStartConfig = new QrStartConfig(qrStartBuilder); assertEquals("-XX:+UseParNewGC", qrStartConfig.jvm().gcopts()); assertEquals(45, qrStartConfig.jvm().heapSizeAsPercentageOfPhysicalMemory()); assertEquals("-XX:SoftRefLRUPolicyMSPerMB=2500", model.getContainerClusters().values().iterator().next().getContainers().get(0).getJvmOptions()); } @Test public void detect_conflicting_jvmgcoptions_in_jvmargs() { assertFalse(ContainerModelBuilder.incompatibleGCOptions("")); assertFalse(ContainerModelBuilder.incompatibleGCOptions("UseG1GC")); assertTrue(ContainerModelBuilder.incompatibleGCOptions("-XX:+UseG1GC")); assertTrue(ContainerModelBuilder.incompatibleGCOptions("abc -XX:+UseParNewGC xyz")); assertTrue(ContainerModelBuilder.incompatibleGCOptions("-XX:CMSInitiatingOccupancyFraction=19")); } @Test public void honours_jvm_gc_options() { Element clusterElem = DomBuilderTest.parse( "", " ", " ", " ", " ", "" ); createModel(root, clusterElem); QrStartConfig.Builder qrStartBuilder = new QrStartConfig.Builder(); root.getConfig(qrStartBuilder, "container/container.0"); QrStartConfig qrStartConfig = new QrStartConfig(qrStartBuilder); assertEquals("-XX:+UseG1GC", qrStartConfig.jvm().gcopts()); } private static void verifyIgnoreJvmGCOptions(boolean isHosted) throws IOException, SAXException { verifyIgnoreJvmGCOptionsIfJvmArgs("jvmargs", ContainerCluster.G1GC, isHosted); verifyIgnoreJvmGCOptionsIfJvmArgs( "jvm-options", "-XX:+UseG1GC", isHosted); } private static void verifyIgnoreJvmGCOptionsIfJvmArgs(String jvmOptionsName, String expectedGC, boolean isHosted) throws IOException, SAXException { String servicesXml = "" + " " + " " + " " + ""; ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).build(); // Need to create VespaModel to make deploy properties have effect final TestLogger logger = new TestLogger(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder() .applicationPackage(applicationPackage) .deployLogger(logger) .properties(new TestProperties().setHostedVespa(isHosted)) .build()); QrStartConfig.Builder qrStartBuilder = new QrStartConfig.Builder(); model.getConfig(qrStartBuilder, "container/container.0"); QrStartConfig qrStartConfig = new QrStartConfig(qrStartBuilder); assertEquals(expectedGC, qrStartConfig.jvm().gcopts()); } @Test public void ignores_jvmgcoptions_on_conflicting_jvmargs() throws IOException, SAXException { verifyIgnoreJvmGCOptions(false); verifyIgnoreJvmGCOptions(true); } private void verifyJvmGCOptions(boolean isHosted, String featureFlagDefault, String override, String expected) throws IOException, SAXException { String servicesXml = "" + " " : ("jvm-gc-options='" + override + "'>")) + " " + " " + ""; ApplicationPackage applicationPackage = new MockApplicationPackage.Builder().withServices(servicesXml).build(); // Need to create VespaModel to make deploy properties have effect final TestLogger logger = new TestLogger(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), new DeployState.Builder() .applicationPackage(applicationPackage) .deployLogger(logger) .properties(new TestProperties().setJvmGCOptions(featureFlagDefault).setHostedVespa(isHosted)) .build()); QrStartConfig.Builder qrStartBuilder = new QrStartConfig.Builder(); model.getConfig(qrStartBuilder, "container/container.0"); QrStartConfig qrStartConfig = new QrStartConfig(qrStartBuilder); assertEquals(expected, qrStartConfig.jvm().gcopts()); } @Test public void requireThatJvmGCOptionsIsHonoured() throws IOException, SAXException { verifyJvmGCOptions(false, null,null, ContainerCluster.G1GC); verifyJvmGCOptions(true, null,null, ContainerCluster.CMS); verifyJvmGCOptions(true, "",null, ContainerCluster.CMS); verifyJvmGCOptions(false, "-XX:+UseConcMarkSweepGC",null, "-XX:+UseConcMarkSweepGC"); verifyJvmGCOptions(true, "-XX:+UseConcMarkSweepGC",null, "-XX:+UseConcMarkSweepGC"); verifyJvmGCOptions(false, null,"-XX:+UseG1GC", "-XX:+UseG1GC"); verifyJvmGCOptions(false, "-XX:+UseConcMarkSweepGC","-XX:+UseG1GC", "-XX:+UseG1GC"); verifyJvmGCOptions(false, null,"-XX:+UseConcMarkSweepGC", "-XX:+UseConcMarkSweepGC"); } }