com.facebook.buck.distributed.BuildTargetsQueue.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.distributed.BuildTargetsQueue.java

Source

/*
 * Copyright 2016-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.facebook.buck.distributed;

import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleResolver;
import com.google.common.base.Preconditions;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class BuildTargetsQueue {
    private List<EnqueuedTarget> zeroDependencyTargets;
    private final Map<String, EnqueuedTarget> allEnqueuedTargets;

    private BuildTargetsQueue(List<EnqueuedTarget> zeroDependencyTargets,
            Map<String, EnqueuedTarget> allEnqueuedTargets) {
        this.zeroDependencyTargets = zeroDependencyTargets;
        this.allEnqueuedTargets = allEnqueuedTargets;
    }

    public static BuildTargetsQueue newEmptyQueue() {
        return new BuildTargetsQueue(new ArrayList<>(), new HashMap<>());
    }

    public static BuildTargetsQueue newQueue(BuildRuleResolver resolver, Iterable<BuildTarget> targetsToBuild) {
        // Build the reverse dependency graph by traversing the action graph Top-Down.
        Map<String, Set<String>> allReverseDeps = new HashMap<>();
        Map<String, Integer> numberOfDependencies = new HashMap<>();
        Set<String> visitedTargets = Sets.newHashSet();
        Queue<BuildRule> buildRulesToProcess = Lists
                .newLinkedList(FluentIterable.from(targetsToBuild).transform(x -> {
                    BuildRule rule = resolver.getRule(x);
                    visitedTargets.add(ruleToTarget(rule));
                    return rule;
                }));
        while (!buildRulesToProcess.isEmpty()) {
            BuildRule rule = buildRulesToProcess.remove();
            String target = ruleToTarget(rule);
            numberOfDependencies.put(target, rule.getBuildDeps().size());
            for (BuildRule dependencyRule : rule.getBuildDeps()) {
                String dependencyTarget = ruleToTarget(dependencyRule);
                if (!allReverseDeps.containsKey(dependencyTarget)) {
                    allReverseDeps.put(dependencyTarget, Sets.newHashSet());
                }
                allReverseDeps.get(dependencyTarget).add(target);

                if (!visitedTargets.contains(dependencyTarget)) {
                    visitedTargets.add(dependencyTarget);
                    buildRulesToProcess.add(dependencyRule);
                }
            }
        }

        // Do the reference counting and create the EnqueuedTargets.
        List<EnqueuedTarget> zeroDependencyTargets = new ArrayList<>();
        Map<String, EnqueuedTarget> allEnqueuedTargets = new HashMap<>();
        for (String target : visitedTargets) {
            Iterable<String> currentRevDeps = null;
            if (allReverseDeps.containsKey(target)) {
                currentRevDeps = allReverseDeps.get(target);
            } else {
                currentRevDeps = new ArrayList<>();
            }

            EnqueuedTarget enqueuedTarget = new EnqueuedTarget(target, ImmutableList.copyOf(currentRevDeps),
                    Preconditions.checkNotNull(numberOfDependencies.get(target)));
            allEnqueuedTargets.put(target, enqueuedTarget);

            if (enqueuedTarget.areAllDependenciesResolved()) {
                zeroDependencyTargets.add(enqueuedTarget);
            }
        }

        return new BuildTargetsQueue(zeroDependencyTargets, allEnqueuedTargets);
    }

    public ImmutableList<String> dequeueZeroDependencyNodes(ImmutableList<String> finishedNodes) {
        // Decrement reference counting.
        for (String node : finishedNodes) {
            EnqueuedTarget target = Preconditions.checkNotNull(allEnqueuedTargets.get(node));
            for (String dependent : target.getDependentTargets()) {
                EnqueuedTarget dep = Preconditions.checkNotNull(allEnqueuedTargets.get(dependent));
                dep.decrementUnsatisfiedDeps();
                if (dep.areAllDependenciesResolved()) {
                    zeroDependencyTargets.add(dep);
                }
            }
        }

        // Return all the Targets that have all dependencies resolved.
        ImmutableList<String> targetsReadyToBuild = ImmutableList
                .copyOf(FluentIterable.from(zeroDependencyTargets).transform(x -> x.getBuildTarget()));
        zeroDependencyTargets.clear();
        return targetsReadyToBuild;
    }

    private static String ruleToTarget(BuildRule rule) {
        return rule.getFullyQualifiedName();
    }

    private static class EnqueuedTarget {
        private final String buildTarget;
        private final ImmutableList<String> dependentTargets;
        private int unsatisfiedDependencies;

        private EnqueuedTarget(String buildTarget, ImmutableList<String> dependentTargets,
                int numberOfDependencies) {
            this.buildTarget = buildTarget;
            this.dependentTargets = dependentTargets;
            this.unsatisfiedDependencies = numberOfDependencies;
        }

        public boolean areAllDependenciesResolved() {
            return 0 == unsatisfiedDependencies;
        }

        public String getBuildTarget() {
            return buildTarget;
        }

        public ImmutableList<String> getDependentTargets() {
            return dependentTargets;
        }

        public void decrementUnsatisfiedDeps() {
            --unsatisfiedDependencies;
            Preconditions.checkArgument(unsatisfiedDependencies >= 0,
                    "The number of unsatisfied dependencies can never be negative.");
        }

        @Override
        public String toString() {
            return "EnqueuedTarget{" + "buildTarget='" + buildTarget + '\'' + ", unsatisfiedDependencies="
                    + unsatisfiedDependencies + ", dependentTargets=" + dependentTargets + '}';
        }
    }
}