<commit_before>// Copyright 2016 Yahoo Inc. 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.config.provision.ApplicationId;
import com.yahoo.config.provision.Deployer;
import com.yahoo.config.provision.Deployment;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;

import java.time.Duration;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;

/**
 * The application maintainer regularly redeploys all applications.
 * This is necessary because applications may gain and lose active nodes due to nodes being moved to and from the
 * failed state. This is corrected by redeploying the applications periodically.
 * It can not (at this point) be done reliably synchronously as part of the fail/reactivate call due to the need for this
 * to happen at a node having the deployer.
 *
 * @author bratseth
 */
public class ApplicationMaintainer extends Maintainer {

    private final Deployer deployer;
    private final Function<NodeRepository, Set<ApplicationId>> activeApplicationsGetter;

    public ApplicationMaintainer(Deployer deployer, NodeRepository nodeRepository, Duration interval) {
        this(deployer, nodeRepository, interval, ApplicationMaintainer::getActiveApplications);
    }

    ApplicationMaintainer(Deployer deployer, NodeRepository nodeRepository, Duration interval,
                          Function<NodeRepository, Set<ApplicationId>> activeApplicationsGetter) {
        super(nodeRepository, interval);
        this.deployer = deployer;
        this.activeApplicationsGetter = activeApplicationsGetter;
    }

    @Override
    protected void maintain() {
        Set<ApplicationId> applications = activeApplicationsGetter.apply(nodeRepository());

        for (ApplicationId application : applications) {
            try {
                // An application might change it's state between the time the set of applications is retrieved and the
                // time deployment happens. Lock on application and check if it's still active.
                //
                // Lock is acquired with a low timeout to reduce the chance of colliding with an external deployment.
                try (Mutex lock = nodeRepository().lock(application, Duration.ofSeconds(1))) {
                    if (isApplicationActive(application)) {
                        Optional<Deployment> deployment = deployer.deployFromLocalActive(application, Duration.ofMinutes(30));
                        if ( ! deployment.isPresent()) continue; // this will be done at another config server

                        deployment.get().prepare();
                        deployment.get().activate();
                    }
                }
            }
            catch (RuntimeException e) {
                log.log(Level.WARNING, "Exception on maintenance redeploy of " + application, e);
            }
        }
    }

    @Override
    public String toString() { return "Periodic application redeployer"; }

    private boolean isApplicationActive(ApplicationId application) {
        return !nodeRepository().getNodes(application, Node.State.active).isEmpty();
    }

    static Set<ApplicationId> getActiveApplications(NodeRepository nodeRepository) {
        return nodeRepository.getNodes(Node.State.active).stream()
                .map(node -> node.allocation().get().owner())
                .collect(Collectors.toSet());
    }

}<commit_msg>Nonfunctional change<commit_after>// Copyright 2016 Yahoo Inc. 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.config.provision.ApplicationId;
import com.yahoo.config.provision.Deployer;
import com.yahoo.config.provision.Deployment;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;

import java.time.Duration;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;

/**
 * The application maintainer regularly redeploys all applications.
 * This is necessary because applications may gain and lose active nodes due to nodes being moved to and from the
 * failed state. This is corrected by redeploying the applications periodically.
 * It can not (at this point) be done reliably synchronously as part of the fail/reactivate call due to the need for this
 * to happen at a node having the deployer.
 *
 * @author bratseth
 */
public class ApplicationMaintainer extends Maintainer {

    private final Deployer deployer;
    private final Function<NodeRepository, Set<ApplicationId>> activeApplicationsGetter;

    public ApplicationMaintainer(Deployer deployer, NodeRepository nodeRepository, Duration interval) {
        this(deployer, nodeRepository, interval, ApplicationMaintainer::getActiveApplications);
    }

    ApplicationMaintainer(Deployer deployer, NodeRepository nodeRepository, Duration interval,
                          Function<NodeRepository, Set<ApplicationId>> activeApplicationsGetter) {
        super(nodeRepository, interval);
        this.deployer = deployer;
        this.activeApplicationsGetter = activeApplicationsGetter;
    }

    @Override
    protected void maintain() {
        Set<ApplicationId> applications = activeApplicationsGetter.apply(nodeRepository());

        for (ApplicationId application : applications) {
            try {
                // An application might change it's state between the time the set of applications is retrieved and the
                // time deployment happens. Lock on application and check if it's still active.
                //
                // Lock is acquired with a low timeout to reduce the chance of colliding with an external deployment.
                try (Mutex lock = nodeRepository().lock(application, Duration.ofSeconds(1))) {
                    if ( ! isActive(application)) continue;
                    Optional<Deployment> deployment = deployer.deployFromLocalActive(application, Duration.ofMinutes(30));
                    if ( ! deployment.isPresent()) continue; // this will be done at another config server

                    deployment.get().prepare();
                    deployment.get().activate();
                }
            }
            catch (RuntimeException e) {
                log.log(Level.WARNING, "Exception on maintenance redeploy of " + application, e);
            }
        }
    }

    @Override
    public String toString() { return "Periodic application redeployer"; }

    private boolean isActive(ApplicationId application) {
        return ! nodeRepository().getNodes(application, Node.State.active).isEmpty();
    }

    static Set<ApplicationId> getActiveApplications(NodeRepository nodeRepository) {
        return nodeRepository.getNodes(Node.State.active).stream()
                .map(node -> node.allocation().get().owner())
                .collect(Collectors.toSet());
    }

}
{'fraction_non_alphanumeric': 0.08084696823869104, 'fraction_numerical': 0.002474907190980338, 'mean_word_length': 2.99231613611416, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2282775', 'n_tokens_mistral': 1804, 'n_tokens_neox': 1704, 'n_words': 546}