aboutsummaryrefslogtreecommitdiffstats
path: root/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java
blob: 1e6847a47bed4ac24eec3803e50b6c3854cf0a31 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.content;

import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
import com.yahoo.config.model.test.MockRoot;
import com.yahoo.text.XML;
import com.yahoo.vespa.config.content.FleetcontrollerConfig;
import com.yahoo.vespa.model.builder.xml.dom.ModelElement;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;

import static com.yahoo.config.model.test.TestUtil.joinLines;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class FleetControllerClusterTest {

    private ClusterControllerConfig parse(String xml, TestProperties props) {
        Document doc = XML.getDocument(xml);
        var deployState = new DeployState.Builder().properties(props).build();
        MockRoot root = new MockRoot("", deployState);
        var clusterElement = new ModelElement(doc.getDocumentElement());
        ModelContext.FeatureFlags featureFlags = new TestProperties();
        return new ClusterControllerConfig.Builder("storage",
                                                   clusterElement,
                                                   new ClusterResourceLimits.Builder(false,
                                                                                     featureFlags.resourceLimitDisk(),
                                                                                     featureFlags.resourceLimitMemory())
                                                           .build(clusterElement).getClusterControllerLimits())
                .build(root.getDeployState(), root, clusterElement.getXml());
    }

    private ClusterControllerConfig parse(String xml) {
        return parse(xml, new TestProperties());
    }

    @Test
    void testParameters() {
        FleetcontrollerConfig.Builder builder = new FleetcontrollerConfig.Builder();
        parse("<cluster id=\"storage\">\n" +
                "  <documents/>" +
                "  <tuning>\n" +
                "    <bucket-splitting minimum-bits=\"7\" />" +
                "    <cluster-controller>\n" +
                "      <init-progress-time>13</init-progress-time>\n" +
                "      <transition-time>27</transition-time>\n" +
                "      <max-premature-crashes>4</max-premature-crashes>\n" +
                "      <stable-state-period>72</stable-state-period>\n" +
                "      <min-distributor-up-ratio>0.7</min-distributor-up-ratio>\n" +
                "      <min-storage-up-ratio>0.3</min-storage-up-ratio>\n" +
                "    </cluster-controller>\n" +
                "  </tuning>\n" +
                "</cluster>").
                getConfig(builder);

        FleetcontrollerConfig config = new FleetcontrollerConfig(builder);
        assertEquals(13 * 1000, config.init_progress_time());
        assertEquals(27 * 1000, config.storage_transition_time());
        assertEquals(4, config.max_premature_crashes());
        assertEquals(72 * 1000, config.stable_state_time_period());
        assertEquals(0.7, config.min_distributor_up_ratio(), 0.01);
        assertEquals(0.3, config.min_storage_up_ratio(), 0.01);
        assertEquals(7, config.ideal_distribution_bits());
    }

    @Test
    void testDurationParameters() {
        FleetcontrollerConfig.Builder builder = new FleetcontrollerConfig.Builder();
        parse("<cluster id=\"storage\">\n" +
                "  <documents/>" +
                "  <tuning>\n" +
                "    <cluster-controller>\n" +
                "      <init-progress-time>13ms</init-progress-time>\n" +
                "    </cluster-controller>\n" +
                "  </tuning>\n" +
                "</cluster>").
                getConfig(builder);

        FleetcontrollerConfig config = new FleetcontrollerConfig(builder);
        assertEquals(13, config.init_progress_time());
    }

    @Test
    void min_node_ratio_per_group_tuning_config_is_propagated() {
        FleetcontrollerConfig.Builder builder = new FleetcontrollerConfig.Builder();
        parse("<cluster id=\"storage\">\n" +
                "  <documents/>\n" +
                "  <tuning>\n" +
                "    <min-node-ratio-per-group>0.75</min-node-ratio-per-group>\n" +
                "  </tuning>\n" +
                "</cluster>").
                getConfig(builder);

        FleetcontrollerConfig config = new FleetcontrollerConfig(builder);
        assertEquals(0.75, config.min_node_ratio_per_group(), 0.01);
    }

    @Test
    void min_node_ratio_per_group_is_implicitly_zero_when_omitted() {
        var config = getConfigForBasicCluster();
        assertEquals(0.0, config.min_node_ratio_per_group(), 0.01);
    }

    @Test
    void default_cluster_feed_block_limits_are_set() {
        assertLimits(0.75, 0.8, getConfigForBasicCluster());
    }

    @Test
    void resource_limits_can_be_set_in_tuning() {
        assertLimits(0.6, 0.7, getConfigForResourceLimitsTuning(0.6, 0.7));
        assertLimits(0.6, 0.8, getConfigForResourceLimitsTuning(0.6, null));
        assertLimits(0.75, 0.7, getConfigForResourceLimitsTuning(null, 0.7));
    }

    private static final double DELTA = 0.00001;

    private void assertLimits(double expDisk, double expMemory, FleetcontrollerConfig config) {
        var limits = config.cluster_feed_block_limit();
        assertEquals(3, limits.size());
        assertEquals(expDisk, limits.get("disk"), DELTA);
        assertEquals(expMemory, limits.get("memory"), DELTA);
        assertEquals(0.9, limits.get("attribute-address-space"), DELTA);
    }

    private FleetcontrollerConfig getConfigForResourceLimitsTuning(Double diskLimit, Double memoryLimit) {
        FleetcontrollerConfig.Builder builder = new FleetcontrollerConfig.Builder();
        parse(joinLines("<cluster id=\"test\">",
                "<documents/>",
                "<tuning>",
                "  <resource-limits>",
                (diskLimit != null ? ("    <disk>" + diskLimit + "</disk>") : ""),
                (memoryLimit != null ? ("    <memory>" + memoryLimit + "</memory>") : ""),
                "  </resource-limits>",
                "</tuning>" +
                "</cluster>")).
                getConfig(builder);
        return new FleetcontrollerConfig(builder);
    }

    @Test
    void feature_flag_controls_min_node_ratio_per_group() {
        verifyFeatureFlagControlsMinNodeRatioPerGroup(0.0, new TestProperties());
        verifyFeatureFlagControlsMinNodeRatioPerGroup(0.3,
                new TestProperties().setMinNodeRatioPerGroup(0.3));
    }

    private void verifyFeatureFlagControlsMinNodeRatioPerGroup(double expRatio, TestProperties props) {
        var config = getConfigForBasicCluster(props);
        assertEquals(expRatio, config.min_node_ratio_per_group(), DELTA);
    }

    private FleetcontrollerConfig getConfigForBasicCluster(TestProperties props) {
        var builder = new FleetcontrollerConfig.Builder();
        parse("<cluster id=\"storage\">\n" +
                "  <documents/>\n" +
                "</cluster>", props).
                getConfig(builder);
        return new FleetcontrollerConfig(builder);
    }

    private FleetcontrollerConfig getConfigForBasicCluster() {
        return getConfigForBasicCluster(new TestProperties());
    }
}