Search in sources :

Example 11 with Mutex

use of com.yahoo.transaction.Mutex in project vespa by vespa-engine.

the class NodeRetirer method retireAllocated.

void retireAllocated() {
    List<Node> allNodes = nodeRepository().getNodes(NodeType.tenant);
    List<ApplicationId> activeApplications = getActiveApplicationIds(allNodes);
    Map<Flavor, Map<Node.State, Long>> numSpareNodesByFlavorByState = getNumberOfNodesByFlavorByNodeState(allNodes);
    flavorSpareChecker.updateReadyAndActiveCountsByFlavor(numSpareNodesByFlavorByState);
    // Get all the nodes that we could retire along with their deployments
    Map<Deployment, Set<Node>> nodesToRetireByDeployment = new HashMap<>();
    for (ApplicationId applicationId : activeApplications) {
        Map<ClusterSpec.Id, Set<Node>> nodesByCluster = getNodesBelongingToApplication(allNodes, applicationId).stream().collect(Collectors.groupingBy(node -> node.allocation().get().membership().cluster().id(), Collectors.toSet()));
        Map<ClusterSpec.Id, Set<Node>> retireableNodesByCluster = nodesByCluster.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> filterRetireableNodes(entry.getValue())));
        if (retireableNodesByCluster.values().stream().mapToInt(Set::size).sum() == 0)
            continue;
        Optional<Deployment> deployment = deployer.deployFromLocalActive(applicationId);
        // this will be done at another config server
        if (!deployment.isPresent())
            continue;
        Set<Node> replaceableNodes = retireableNodesByCluster.entrySet().stream().flatMap(entry -> entry.getValue().stream().filter(node -> flavorSpareChecker.canRetireAllocatedNodeWithFlavor(node.flavor())).limit(getNumberNodesAllowToRetireForCluster(nodesByCluster.get(entry.getKey()), MAX_SIMULTANEOUS_RETIRES_PER_CLUSTER))).collect(Collectors.toSet());
        if (!replaceableNodes.isEmpty())
            nodesToRetireByDeployment.put(deployment.get(), replaceableNodes);
    }
    nodesToRetireByDeployment.forEach(((deployment, nodes) -> {
        ApplicationId app = nodes.iterator().next().allocation().get().owner();
        Set<Node> nodesToRetire;
        // that may have changed) with wantToRetire and wantToDeprovision.
        try (Mutex lock = nodeRepository().lock(app)) {
            nodesToRetire = nodes.stream().map(node -> nodeRepository().getNode(node.hostname()).filter(upToDateNode -> node.state() == Node.State.active).filter(upToDateNode -> node.allocation().get().owner().equals(upToDateNode.allocation().get().owner()))).flatMap(node -> node.map(Stream::of).orElseGet(Stream::empty)).collect(Collectors.toSet());
            nodesToRetire.forEach(node -> retirementPolicy.shouldRetire(node).ifPresent(reason -> {
                log.info("Setting wantToRetire and wantToDeprovision for host " + node.hostname() + " with flavor " + node.flavor().name() + " allocated to " + node.allocation().get().owner() + ". Reason: " + reason);
                Node updatedNode = node.with(node.status().withWantToRetire(true).withWantToDeprovision(true));
                nodeRepository().write(updatedNode);
            }));
        }
        // This takes a while, so do it outside of the application lock
        if (!nodesToRetire.isEmpty()) {
            try {
                deployment.activate();
            } catch (Exception e) {
                log.log(LogLevel.INFO, "Failed to redeploy " + app.serializedForm() + ", will be redeployed later by application maintainer", e);
            }
        }
    }));
}
Also used : Deployer(com.yahoo.config.provision.Deployer) FlavorSpareChecker(com.yahoo.vespa.hosted.provision.provisioning.FlavorSpareChecker) RetirementPolicy(com.yahoo.vespa.hosted.provision.maintenance.retire.RetirementPolicy) Iterator(java.util.Iterator) ApplicationId(com.yahoo.config.provision.ApplicationId) Deployment(com.yahoo.config.provision.Deployment) NodeType(com.yahoo.config.provision.NodeType) Collection(java.util.Collection) ClusterSpec(com.yahoo.config.provision.ClusterSpec) Set(java.util.Set) HashMap(java.util.HashMap) Node(com.yahoo.vespa.hosted.provision.Node) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) NodeRepository(com.yahoo.vespa.hosted.provision.NodeRepository) Mutex(com.yahoo.transaction.Mutex) List(java.util.List) Stream(java.util.stream.Stream) Agent(com.yahoo.vespa.hosted.provision.node.Agent) Flavor(com.yahoo.config.provision.Flavor) Duration(java.time.Duration) Map(java.util.Map) LogLevel(com.yahoo.log.LogLevel) Optional(java.util.Optional) Set(java.util.Set) HashMap(java.util.HashMap) Node(com.yahoo.vespa.hosted.provision.Node) Deployment(com.yahoo.config.provision.Deployment) Mutex(com.yahoo.transaction.Mutex) Flavor(com.yahoo.config.provision.Flavor) Stream(java.util.stream.Stream) ApplicationId(com.yahoo.config.provision.ApplicationId) ApplicationId(com.yahoo.config.provision.ApplicationId) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

Mutex (com.yahoo.transaction.Mutex)11 Node (com.yahoo.vespa.hosted.provision.Node)5 ApplicationId (com.yahoo.config.provision.ApplicationId)4 Deployment (com.yahoo.config.provision.Deployment)4 List (java.util.List)4 Map (java.util.Map)4 Flavor (com.yahoo.config.provision.Flavor)3 NodeType (com.yahoo.config.provision.NodeType)3 Agent (com.yahoo.vespa.hosted.provision.node.Agent)3 Duration (java.time.Duration)3 ArrayList (java.util.ArrayList)3 Optional (java.util.Optional)3 Set (java.util.Set)3 Collectors (java.util.stream.Collectors)3 ListMap (com.yahoo.collections.ListMap)2 ClusterSpec (com.yahoo.config.provision.ClusterSpec)2 Deployer (com.yahoo.config.provision.Deployer)2 LogLevel (com.yahoo.log.LogLevel)2 NodeRepository (com.yahoo.vespa.hosted.provision.NodeRepository)2 RetirementPolicy (com.yahoo.vespa.hosted.provision.maintenance.retire.RetirementPolicy)2