summaryrefslogtreecommitdiffstats
path: root/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DeprovisionedExpirer.java
blob: 92062f13f1a4fdda49ea43ae3ea9e1c31c99d697 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.maintenance;

import com.yahoo.jdisc.Metric;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.hosted.provision.node.History.Event.Type;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;

import static java.util.Comparator.comparing;

/**
 * This removes hosts from {@link com.yahoo.vespa.hosted.provision.Node.State#deprovisioned}, in dynamically provisioned
 * zones, after a grace period.
 *
 * @author mpolden
 */
public class DeprovisionedExpirer extends Expirer {

    private static final int maxDeprovisionedNodes = 1000;

    DeprovisionedExpirer(NodeRepository nodeRepository, Duration expiryTime, Metric metric) {
        super(Node.State.deprovisioned, History.Event.Type.deprovisioned, nodeRepository, expiryTime, metric);
    }

    @Override
    protected boolean isExpired(Node node) {
        return nodeRepository().zone().cloud().dynamicProvisioning() && super.isExpired(node);
    }

    @Override
    protected NodeList getExpiredNodes() {
        List<Node> deprovisioned = nodeRepository().nodes().list(Node.State.deprovisioned)
                                                   .sortedBy(comparing(node -> node.history().event(Type.deprovisioned)
                                                                                   .map(History.Event::at)
                                                                                   .orElse(Instant.EPOCH)))
                                                   .asList();
        Deque<Node> expired = new ArrayDeque<>(deprovisioned);
        int kept = 0;
        while ( ! expired.isEmpty()) {
            if (isExpired(expired.getLast()) || kept++ >= maxDeprovisionedNodes) break; // If we encounter an expired node, the rest are also expired.
            expired.removeLast();
        }
        return NodeList.copyOf(List.copyOf(expired));
    }

    @Override
    protected void expire(List<Node> expired) {
        nodeRepository().nodes().performOn(NodeList.copyOf(expired),
                                           (node, lock) -> { nodeRepository().nodes().forget(node); return node; });
    }

}