// 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);
}
}