Java tutorial
// Copyright 2016 The Bazel Authors. All rights reserved. // // 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.google.devtools.build.lib.query2; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.devtools.build.lib.query2.SkyQueryEnvironment.IS_TTV; import static com.google.devtools.build.lib.query2.SkyQueryEnvironment.SKYKEY_TO_LABEL; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.concurrent.MultisetSemaphore; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.query2.engine.Callback; import com.google.devtools.build.lib.query2.engine.QueryException; import com.google.devtools.build.lib.query2.engine.Uniquifier; import com.google.devtools.build.skyframe.SkyKey; import java.util.Map; import java.util.Set; /** * A helper class that computes unbounded 'deps(<expr>)' via BFS. Re-use logic from {@link * AbstractEdgeVisitor} to grab relevant semaphore locks when processing nodes as well as batching * visits by packages. */ class DepsUnboundedVisitor extends AbstractEdgeVisitor<SkyKey> { /** * A {@link Uniquifier} for valid deps. Only used prior to visiting the deps. Deps filtering is * done in the {@link DepsUnboundedVisitor#getVisitResult} stage. */ private final Uniquifier<SkyKey> validDepUniquifier; private final boolean depsNeedFiltering; private final Callback<Target> errorReporter; DepsUnboundedVisitor(SkyQueryEnvironment env, Uniquifier<SkyKey> validDepUniquifier, Callback<Target> callback, MultisetSemaphore<PackageIdentifier> packageSemaphore, boolean depsNeedFiltering, Callback<Target> errorReporter) { super(env, callback, packageSemaphore); this.validDepUniquifier = validDepUniquifier; this.depsNeedFiltering = depsNeedFiltering; this.errorReporter = errorReporter; } /** * A {@link Factory} for {@link DepsUnboundedVisitor} instances, each of which will be used to * perform visitation of the DTC of the {@link SkyKey}s passed in a single {@link * Callback#process} call. Note that all the created instances share the same {@link Uniquifier} * so that we don't visit the same Skyframe node more than once. */ static class Factory implements ParallelVisitor.Factory { private final SkyQueryEnvironment env; private final Uniquifier<SkyKey> validDepUniquifier; private final Callback<Target> callback; private final MultisetSemaphore<PackageIdentifier> packageSemaphore; private final boolean depsNeedFiltering; private final Callback<Target> errorReporter; Factory(SkyQueryEnvironment env, Callback<Target> callback, MultisetSemaphore<PackageIdentifier> packageSemaphore, boolean depsNeedFiltering, Callback<Target> errorReporter) { this.env = env; this.validDepUniquifier = env.createSkyKeyUniquifier(); this.callback = callback; this.packageSemaphore = packageSemaphore; this.depsNeedFiltering = depsNeedFiltering; this.errorReporter = errorReporter; } @Override public ParallelVisitor<SkyKey, Target> create() { return new DepsUnboundedVisitor(env, validDepUniquifier, callback, packageSemaphore, depsNeedFiltering, errorReporter); } } @Override protected Visit getVisitResult(Iterable<SkyKey> keys) throws InterruptedException { if (depsNeedFiltering) { // We have to targetify the keys here in order to determine the allowed dependencies. Multimap<SkyKey, SkyKey> packageKeyToTargetKeyMap = env.makePackageKeyToTargetKeyMap(keys); Set<PackageIdentifier> pkgIdsNeededForTargetification = packageKeyToTargetKeyMap.keySet().stream() .map(SkyQueryEnvironment.PACKAGE_SKYKEY_TO_PACKAGE_IDENTIFIER).collect(toImmutableSet()); packageSemaphore.acquireAll(pkgIdsNeededForTargetification); Iterable<Target> deps; try { deps = env.getFwdDeps(env.makeTargetsFromSkyKeys(keys).values()); } finally { packageSemaphore.releaseAll(pkgIdsNeededForTargetification); } return new Visit(/*keysToUseForResult=*/ keys, /*keysToVisit=*/ Iterables.transform(deps, Target::getLabel)); } // We need to explicitly check that all requested TTVs are actually in the graph. Map<SkyKey, Iterable<SkyKey>> depMap = env.graph.getDirectDeps(keys); checkIfMissingTargets(keys, depMap); Iterable<SkyKey> deps = Iterables.filter(Iterables.concat(depMap.values()), IS_TTV); return new Visit(keys, deps); } private void checkIfMissingTargets(Iterable<SkyKey> keys, Map<SkyKey, Iterable<SkyKey>> depMap) { if (depMap.size() != Iterables.size(keys)) { Iterable<Label> missingTargets = Iterables.transform( Iterables.filter(keys, Predicates.not(Predicates.in(depMap.keySet()))), SKYKEY_TO_LABEL); env.getEventHandler().handle(Event.warn("Targets were missing from graph: " + missingTargets)); } } @Override protected Iterable<SkyKey> preprocessInitialVisit(Iterable<SkyKey> keys) { return keys; } @Override protected void processPartialResults(Iterable<SkyKey> keysToUseForResult, Callback<Target> callback) throws QueryException, InterruptedException { errorReporter.process(processResultsAndReturnTargets(keysToUseForResult, callback)); } @Override protected SkyKey getNewNodeFromEdge(SkyKey visit) { return visit; } @Override protected ImmutableList<SkyKey> getUniqueValues(Iterable<SkyKey> keysToVisit) { // Legit deps are already filtered using env.getFwdDeps(). return validDepUniquifier.unique(keysToVisit); } }