aboutsummaryrefslogtreecommitdiffstats
path: root/container-core/src/main/java/com/yahoo/container/handler/Coverage.java
blob: ef088a1685a8f989fde94358a3abdb04a14754b5 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.container.handler;


import com.google.common.annotations.Beta;

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

    protected long docs;
    protected long active;
    protected long soonActive;
    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;

    /**
     * Build an invalid instance to initiate manually.
     */
    protected Coverage() { }

    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.soonActive = 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();
        soonActive += other.getSoonActive();
        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.
     * Still in beta, semantics not finalized yet.
     */
    @Beta
    public long getSoonActive() { return soonActive; }

    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() {
        switch (fullReason) {
            case EXPLICITLY_FULL:
                return true;
            case EXPLICITLY_INCOMPLETE:
                return false;
            case DOCUMENT_COUNT:
                return docs == active;
            default:
                throw new IllegalStateException("Implementation out of sync. Please report this as a bug.");
        }
    }

    /** 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 how many
     * percent coverage the result sets this Coverage instance contains information
     * about had.
     */
    public int getResultPercentage() {
        if (getResultSets() == 0) {
            return 0;
        }
        if (docs < active) {
            return (int) Math.round(docs * 100.0d / active);
        }
        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(), getSoonActive(), degradation);
    }

}