// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.builder.xml.dom; import com.yahoo.collections.CollectionUtil; import com.yahoo.vespa.config.search.core.ProtonConfig; import com.yahoo.config.model.builder.xml.test.DomBuilderTest; import com.yahoo.vespa.model.search.Tuning; import org.junit.jupiter.api.Test; import org.w3c.dom.Element; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.*; /** * @author geirst */ public class DomSchemaTuningBuilderTest extends DomBuilderTest { private static final double DELTA = 0.000001; private static Element parseXml(String... xmlLines) { return parse("", "", CollectionUtil.mkString(Arrays.asList(xmlLines), "\n"), "", ""); } private Tuning createTuning(Element xml) { DomSearchTuningBuilder b = new DomSearchTuningBuilder(); return b.build(root.getDeployState(), root, xml); } private ProtonConfig getProtonCfg(Tuning tuning) { ProtonConfig.Builder pb = new ProtonConfig.Builder(); tuning.getConfig(pb); return new ProtonConfig(pb); } @Test void requireThatWeCanParseRequestThreadsTag() { Tuning t = createTuning(parseXml("", "123", "34", "456", "")); assertEquals(123, t.searchNode.threads.numSearchThreads.longValue()); assertEquals(456, t.searchNode.threads.numSummaryThreads.longValue()); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.numsearcherthreads(), 123); assertEquals(cfg.numthreadspersearch(), 34); assertEquals(cfg.numsummarythreads(), 456); } @Test void requireThatWeCanParseLidSpaceTag() { Tuning t = createTuning(parseXml("", "0.5", "")); assertEquals(0.5, t.searchNode.lidSpace.bloatFactor.doubleValue()); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.lidspacecompaction().allowedlidbloatfactor(), 0.5); } @Test void requireThatWeCanParseFlushStrategyTag() { Tuning t = createTuning(parseXml("", "", "", "900", "8.7", "", "", "600", "5.4", "300", "", "", "1024", "", "", "0.6", "0.7", "", "", "")); assertEquals(900, t.searchNode.strategy.totalMaxMemoryGain.longValue()); assertEquals(8.7, t.searchNode.strategy.totalDiskBloatFactor, DELTA); assertEquals(600, t.searchNode.strategy.componentMaxMemoryGain.longValue()); assertEquals(5.4, t.searchNode.strategy.componentDiskBloatFactor, DELTA); assertEquals(300, t.searchNode.strategy.componentMaxage, DELTA); assertEquals(1024, t.searchNode.strategy.transactionLogMaxSize.longValue()); assertEquals(0.6, t.searchNode.strategy.conservativeMemoryLimitFactor, DELTA); assertEquals(0.7, t.searchNode.strategy.conservativeDiskLimitFactor, DELTA); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.flush().memory().maxmemory(), 900); assertEquals(cfg.flush().memory().diskbloatfactor(), 8.7, DELTA); assertEquals(cfg.flush().memory().each().maxmemory(), 600); assertEquals(cfg.flush().memory().each().diskbloatfactor(), 5.4, DELTA); assertEquals(cfg.flush().memory().maxage().time(), 300, DELTA); assertEquals(cfg.flush().memory().maxtlssize(), 1024); assertEquals(cfg.flush().memory().conservative().memorylimitfactor(), 0.6, DELTA); assertEquals(cfg.flush().memory().conservative().disklimitfactor(), 0.7, DELTA); } @Test void requireThatWeCanParseIndexTag() { Tuning t = createTuning(parseXml("", "", "mmap", "", "" + "", "true", "", "")); assertEquals(Tuning.SearchNode.IoType.MMAP, t.searchNode.index.io.search); assertEquals(178, t.searchNode.index.warmup.time, DELTA); assertTrue(t.searchNode.index.warmup.unpack); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.indexing().write().io(), ProtonConfig.Indexing.Write.Io.DIRECTIO); assertEquals(cfg.indexing().read().io(), ProtonConfig.Indexing.Read.Io.DIRECTIO); assertEquals(cfg.index().warmup().time(), 178, DELTA); assertTrue(cfg.index().warmup().unpack()); } @Test void requireThatWeCanPopulateIndex() { Tuning t = createTuning(parseXml("", "", "populate", "", "")); assertEquals(Tuning.SearchNode.IoType.POPULATE, t.searchNode.index.io.search); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.indexing().write().io(), ProtonConfig.Indexing.Write.Io.DIRECTIO); assertEquals(cfg.indexing().read().io(), ProtonConfig.Indexing.Read.Io.DIRECTIO); assertEquals(cfg.search().mmap().options().size(), 1); assertEquals(cfg.search().mmap().options().get(0), ProtonConfig.Search.Mmap.Options.POPULATE); } @Test void requireThatWeCanParseRemovedDBTag() { Tuning t = createTuning(parseXml("", "", "19388", "193", "", "")); assertEquals(19388, t.searchNode.removedDB.prune.age, DELTA); assertEquals(193, t.searchNode.removedDB.prune.interval, DELTA); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.pruneremoveddocumentsinterval(), 193, DELTA); assertEquals(cfg.pruneremoveddocumentsage(), 19388, DELTA); } @Test void requireThatWeCanParseAttributeTag() { Tuning t = createTuning(parseXml("", "", "normal", "", "")); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.attribute().write().io(), ProtonConfig.Attribute.Write.Io.DIRECTIO); } @Test void requireThatWeCanParseSummaryTag() { Tuning t = createTuning(parseXml("", "", "directio", "directio", "", "", "", "128", "30.7", "64", "", "none", "3", "", "", "", "512", "0.3", "", "256", "", "lz4", "5", "", "", "", "", "")); assertEquals(Tuning.SearchNode.IoType.DIRECTIO, t.searchNode.summary.io.read); assertEquals(128, t.searchNode.summary.store.cache.maxSize.longValue()); assertEquals(30.7, t.searchNode.summary.store.cache.maxSizePercent, DELTA); assertEquals(Tuning.SearchNode.Summary.Store.Compression.Type.NONE, t.searchNode.summary.store.cache.compression.type); assertEquals(3, t.searchNode.summary.store.cache.compression.level.intValue()); assertEquals(512, t.searchNode.summary.store.logStore.maxFileSize.longValue()); assertEquals(0.3, t.searchNode.summary.store.logStore.minFileSizeFactor, DELTA); assertEquals(256, t.searchNode.summary.store.logStore.chunk.maxSize.intValue()); assertEquals(Tuning.SearchNode.Summary.Store.Compression.Type.LZ4, t.searchNode.summary.store.logStore.chunk.compression.type); assertEquals(5, t.searchNode.summary.store.logStore.chunk.compression.level.intValue()); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.summary().write().io(), ProtonConfig.Summary.Write.Io.DIRECTIO); assertEquals(cfg.summary().read().io(), ProtonConfig.Summary.Read.Io.DIRECTIO); assertEquals(cfg.summary().cache().maxbytes(), 128); assertEquals(cfg.summary().cache().initialentries(), 64); assertEquals(cfg.summary().cache().compression().type(), ProtonConfig.Summary.Cache.Compression.Type.NONE); assertEquals(cfg.summary().cache().compression().level(), 3); assertEquals(cfg.summary().log().maxfilesize(), 512); assertEquals(cfg.summary().log().minfilesizefactor(), 0.3, DELTA); assertEquals(cfg.summary().log().chunk().maxbytes(), 256); assertEquals(cfg.summary().log().chunk().compression().type(), ProtonConfig.Summary.Log.Chunk.Compression.Type.LZ4); assertEquals(cfg.summary().log().chunk().compression().level(), 5); assertEquals(cfg.summary().log().compact().compression().type(), ProtonConfig.Summary.Log.Compact.Compression.Type.LZ4); assertEquals(cfg.summary().log().compact().compression().level(), 5); } @Test void requireThatWeCanGiveSummaryCacheSizeInPercentage() { Tuning t = createTuning(parseXml("", "", "", "30.7", "", "", "")); assertNull(t.searchNode.summary.store.cache.maxSize); assertEquals(30.7, t.searchNode.summary.store.cache.maxSizePercent, DELTA); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.summary().cache().maxbytes(), -30); } @Test void requireThatWeCanPopulateSummary() { Tuning t = createTuning(parseXml("", "", "populate", "", "")); assertEquals(Tuning.SearchNode.IoType.POPULATE, t.searchNode.summary.io.read); ProtonConfig cfg = getProtonCfg(t); assertEquals(ProtonConfig.Summary.Read.Io.MMAP, cfg.summary().read().io()); assertEquals(ProtonConfig.Summary.Read.Mmap.Options.POPULATE, cfg.summary().read().mmap().options().get(0)); } @Test void requireThatWeCanParseInitializeTag() { Tuning t = createTuning(parseXml("", "7", "")); assertEquals(7, t.searchNode.initialize.threads.intValue()); ProtonConfig cfg = getProtonCfg(t); assertEquals(cfg.initialize().threads(), 7); } @Test void requireThatWeCanParseFeedingTag() { Tuning t = createTuning(parseXml("", "0.7", "0.3", "")); assertEquals(0.7, t.searchNode.feeding.concurrency, DELTA); assertEquals(0.3, t.searchNode.feeding.niceness, DELTA); var cfg = getProtonCfg(t); assertEquals(cfg.feeding().concurrency(), 0.7, DELTA); assertEquals(cfg.feeding().niceness(), 0.3, DELTA); } }