aboutsummaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsAggregator.java
blob: ba1dd20bb2c3d1546065225f2570f2407a68eda3 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.metrics;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author olaa
 * @author ogronnesby
 */
public class DeploymentMetricsAggregator {

    private LatencyMetrics feed;
    private LatencyMetrics qr;
    private LatencyMetrics container;
    private Double documentCount;
    private ResourceUsage memoryUsage;
    private ResourceUsage diskUsage;
    private Map<String, Double> reindexingProgress;

    public synchronized DeploymentMetricsAggregator addFeedLatency(double sum, double count) {
        this.feed = combineLatency(this.feed, sum, count);
        return this;
    }

    public synchronized DeploymentMetricsAggregator addQrLatency(double sum, double count) {
        this.qr = combineLatency(this.qr, sum, count);
        return this;
    }

    public synchronized DeploymentMetricsAggregator addContainerLatency(double sum, double count) {
        this.container = combineLatency(this.container, sum, count);
        return this;
    }

    public synchronized DeploymentMetricsAggregator addDocumentCount(double count) {
        this.documentCount = (this.documentCount == null ? 0.0 : this.documentCount) + count;
        return this;
    }

    public synchronized DeploymentMetricsAggregator addDiskUsage(double feedBlockUtil, double feedBlockLimit) {
        this.diskUsage = combineResourceUtil(this.diskUsage, feedBlockUtil, feedBlockLimit);
        return this;
    }

    public synchronized DeploymentMetricsAggregator addMemoryUsage(double feedBlockUtil, double feedBlockLimit) {
        this.memoryUsage = combineResourceUtil(this.memoryUsage, feedBlockUtil, feedBlockLimit);
        return this;
    }

    public synchronized DeploymentMetricsAggregator addReindexingProgress(String documentType, double progress) {
        if (reindexingProgress == null) this.reindexingProgress = new HashMap<>();
        this.reindexingProgress.put(documentType, progress);
        return this;
    }

    public Optional<Double> aggregateFeedLatency() {
        return Optional.ofNullable(feed).map(m -> m.sum / m.count).filter(num -> !num.isNaN());
    }

    public Optional<Double> aggregateFeedRate() {
        return Optional.ofNullable(feed).map(m -> m.count / 60);
    }

    public Optional<Double> aggregateQueryLatency() {
        if (container == null && qr == null) return Optional.empty();
        var c = Optional.ofNullable(container).orElseGet(LatencyMetrics::new);
        var q = Optional.ofNullable(qr).orElseGet(LatencyMetrics::new);
        return Optional.of((c.sum + q.sum) / (c.count + q.count)).filter(num -> !num.isNaN());
    }

    public Optional<Double> aggregateQueryRate() {
        if (container == null && qr == null) return Optional.empty();
        var c = Optional.ofNullable(container).orElseGet(LatencyMetrics::new);
        var q = Optional.ofNullable(qr).orElseGet(LatencyMetrics::new);
        return Optional.of((c.count + q.count) / 60);
    }

    public Optional<Double> aggregateDocumentCount() {
        return Optional.ofNullable(documentCount);
    }

    public Optional<ResourceUsage> memoryUsage() {
        return Optional.ofNullable(memoryUsage);
    }

    public Optional<ResourceUsage> diskUsage() {
        return Optional.ofNullable(diskUsage);
    }

    public Optional<Map<String, Double>> reindexingProgress() {
        return Optional.ofNullable(reindexingProgress);
    }


    private static LatencyMetrics combineLatency(LatencyMetrics metricsOrNull, double sum, double count) {
        return Optional.ofNullable(metricsOrNull).orElseGet(LatencyMetrics::new).combine(sum, count);
    }

    private static ResourceUsage combineResourceUtil(ResourceUsage resourceUsageOrNull, double util, double limit) {
        return Optional.ofNullable(resourceUsageOrNull).orElseGet(ResourceUsage::new).combine(util, limit);
    }

    private static class LatencyMetrics {
        private double sum;
        private double count;

        private LatencyMetrics combine(double sum, double count) {
            this.sum += sum;
            this.count += count;
            return this;
        }
    }

    public static class ResourceUsage {
        /**
         * Current resource utilization relative to feed block limit, i.e. value of >= 1 means utilization at or above
         * feed block limit.
         */
        private double feedBlockUtil;

        /** Resource utilization limit at which further external feed is blocked */
        private double feedBlockLimit;

        private ResourceUsage combine(double feedBlockUtil, double feedBlockLimit) {
            if (feedBlockUtil > this.feedBlockUtil) this.feedBlockUtil = feedBlockUtil;
            if (feedBlockLimit > this.feedBlockLimit) this.feedBlockLimit = feedBlockLimit;
            return this;
        }

        public double util() { return feedBlockUtil * feedBlockLimit; }
        public double feedBlockLimit() { return feedBlockLimit; }
    }
}