aboutsummaryrefslogtreecommitdiffstats
path: root/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/GlobalBucketSyncStatsCalculator.java
blob: 0137ea2c29e543f41fb50c94c2db4e8bbdde1062 (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core;

import java.util.Optional;

/**
 * @author vekterli
 */
public class GlobalBucketSyncStatsCalculator {

    /**
     * Compute a value in [0, 1] representing how much of the cluster's data space is currently
     * out of sync, i.e. pending merging. In other words, if the value is 1 all buckets are out
     * of sync, and conversely if it's 0 all buckets are in sync. This number applies across bucket
     * spaces.
     *
     * @param globalStats Globally aggregated content node statistics for the entire cluster.
     * @return Optional containing a value [0, 1] representing the ratio of buckets pending merge
     *         in relation to the total number of buckets in the cluster, or an empty optional if
     *         the underlying global statistics contains invalid/incomplete information.
     */
    public static Optional<Double> clusterBucketsOutOfSyncRatio(ContentNodeStats globalStats) {
        long totalBuckets = 0;
        long pendingBuckets = 0;
        for (var space : globalStats.getBucketSpaces().values()) {
            if (!space.valid()) {
                return Optional.empty();
            }
            totalBuckets   += space.getBucketsTotal();
            pendingBuckets += space.getBucketsPending();
        }
        // It's currently possible for the reported number of pending buckets to be greater than
        // the number of total buckets. Example: this can happen if a bucket is present on a single
        // node, but should have been replicated to 9 more nodes. Since counts are not normalized
        // across content nodes for a given bucket, this will be counted as 9 pending and 1 total.
        // Eventually this will settle as 0 pending and 10 total.
        // TODO report node-normalized pending/total counts from distributors and use these.
        pendingBuckets = Math.min(pendingBuckets, totalBuckets);
        if (totalBuckets <= 0) {
            return Optional.of(0.0); // No buckets; cannot be out of sync by definition
        }
        return Optional.of((double)pendingBuckets / (double)totalBuckets);
    }

}