aboutsummaryrefslogtreecommitdiffstats
path: root/container-core/src/main/java/com/yahoo/container/handler/Coverage.java
blob: bbb47d1457123ed62bd36b761af0f91492ee7945 (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
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler;

/**
 * The coverage report for a result set.
 *
 * @author Steinar Knutsen
 * @author baldersheim
 */
public class Coverage {

    protected long docs;
    protected long active;
    protected long targetActive;
    protected int degradedReason;
    protected int nodes;
    private   int nodesTried;
    protected int resultSets;
    protected int fullResultSets;

    // need a default setting for deserialization logic in subclasses
    protected FullCoverageDefinition fullReason = FullCoverageDefinition.DOCUMENT_COUNT;

    protected enum FullCoverageDefinition {
        EXPLICITLY_FULL, EXPLICITLY_INCOMPLETE, DOCUMENT_COUNT;
    }

    public final static int DEGRADED_BY_MATCH_PHASE = 1;
    public final static int DEGRADED_BY_TIMEOUT = 2;
    public final static int DEGRADED_BY_ADAPTIVE_TIMEOUT = 4;

    protected Coverage(long docs, long active, int nodes, int resultSets) {
        this(docs, active, nodes, resultSets, FullCoverageDefinition.DOCUMENT_COUNT);
    }

    public Coverage(long docs, int nodes, boolean full) {
        this(docs, nodes, full, 1);
    }

    protected Coverage(long docs, int nodes, boolean full, int resultSets) {
        this(docs, docs, nodes, resultSets, full ? FullCoverageDefinition.EXPLICITLY_FULL
                                                 : FullCoverageDefinition.EXPLICITLY_INCOMPLETE);
    }

    private Coverage(long docs, long active, int nodes, int resultSets, FullCoverageDefinition fullReason) {
        this.docs = docs;
        this.nodes = nodes;
        this.nodesTried = nodes;
        this.active = active;
        this.targetActive = active;
        this.degradedReason = 0;
        this.resultSets = resultSets;
        this.fullReason = fullReason;
        this.fullResultSets = getFull() ? resultSets : 0;
    }

    public void merge(Coverage other) {
        if (other == null) return;

        docs += other.getDocs();
        nodes += other.getNodes();
        nodesTried += other.nodesTried;
        active += other.getActive();
        targetActive += other.getTargetActive();
        degradedReason |= other.degradedReason;
        resultSets += other.getResultSets();
        fullResultSets += other.getFullResultSets();

        // explicitly incomplete beats doc count beats explicitly full
        switch (other.fullReason) {
            case EXPLICITLY_FULL:
                // do nothing
                break;
            case EXPLICITLY_INCOMPLETE:
                fullReason = FullCoverageDefinition.EXPLICITLY_INCOMPLETE;
                break;
            case DOCUMENT_COUNT:
                if (fullReason == FullCoverageDefinition.EXPLICITLY_FULL) {
                    fullReason = FullCoverageDefinition.DOCUMENT_COUNT;
                }
                break;
        }
    }

    /**
     * Returns the number of documents searched for this result. If the final result
     * set is produced through several queries, this number will be the sum
     * for all the queries.
     */
    public long getDocs() {
        return docs;
    }

    /** Returns the total number of documents that could be searched. */
    public long getActive() { return active; }

    /**
     * Returns the total number of documents that will be searchable once redistribution has settled.
     */
    public long getTargetActive() { return targetActive; }

    public boolean isDegraded() { return (degradedReason != 0) || isDegradedByNonIdealState(); }
    public boolean isDegradedByMatchPhase() { return (degradedReason & DEGRADED_BY_MATCH_PHASE) != 0; }
    public boolean isDegradedByTimeout() { return (degradedReason & DEGRADED_BY_TIMEOUT) != 0; }
    public boolean isDegradedByAdapativeTimeout() { return (degradedReason & DEGRADED_BY_ADAPTIVE_TIMEOUT) != 0; }
    public boolean isDegradedByNonIdealState() { return (degradedReason == 0) && (getResultPercentage() != 100);}

    /** Returns whether the search had full coverage or not */
    public boolean getFull() {
        return switch (fullReason) {
            case EXPLICITLY_FULL: yield true;
            case EXPLICITLY_INCOMPLETE: yield false;
            case DOCUMENT_COUNT: yield (docs == active) && !((active == 0) && isDegradedByTimeout()) ;
        };
    }

    /** Returns the number of search instances which participated successfully in the search. */
    public int getNodes() {
        return nodes;
    }

    /** Returns the number of search instances which tried to participate in the search. */
    public int getNodesTried() {
        return nodesTried;
    }

    public Coverage setNodesTried(int nodesTried) { this.nodesTried = nodesTried; return this; }

    /**
     * A Coverage instance contains coverage information for potentially more
     * than one search. If several queries, e.g. through blending of results
     * from multiple clusters, produced a result set, this number will show how
     * many of the result sets for these queries had full coverage.
     *
     * @return the number of result sets which had full coverage
     */
    public int getFullResultSets() {
        return fullResultSets;
    }

    /**
     * A Coverage instance contains coverage information for potentially more
     * than one search. If several queries, e.g. through blending of results
     * from multiple clusters, produced a result set, this number will show how
     * many result sets containing coverage information this Coverage instance
     * contains information about.
     *
     * @return the number of result sets with coverage information for this instance
     */
    public int getResultSets() {
        return resultSets;
    }

    /**
     * An int between 0 (inclusive) and 100 (inclusive) representing the
     * percent coverage of the result sets this instance contains information about.
     */
    public int getResultPercentage() {
        if (getResultSets() == 0) {
            return 0;
        }
        long total = targetActive;
        if (docs < total) {
            return (int) Math.round(docs * 100.0d / total);
        }
        if ((total == 0) && isDegradedByTimeout()) {
            return 0;
        }
        return getFullResultSets() * 100 / getResultSets();
    }

    public com.yahoo.container.logging.Coverage toLoggingCoverage() {
        int degradation = com.yahoo.container.logging.Coverage.toDegradation(isDegradedByMatchPhase(),
                isDegradedByTimeout(),
                isDegradedByAdapativeTimeout());
        return new com.yahoo.container.logging.Coverage(getDocs(), getActive(), getTargetActive(), degradation);
    }

}